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
 
 
-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 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
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
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 :
 
-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
@@ -62,6 +62,14 @@ This is highly non-portable so IF this works on your linux system, count
 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
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
 
index c52a370c6ddef05837245506d84aaa3c2634bd8b..2cb979eb8a7dc4680689e86b3090821346f00c5b 100644 (file)
@@ -1,5 +1,5 @@
 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
@@ -155,6 +155,7 @@ AC_CHECK_MEMBER([struct sockaddr_storage.ss_family],
 
 #output
 AC_CONFIG_FILES([Makefile]
+                [doc/Makefile]
                 [include/Makefile]
                 [lib/Makefile]
                 [mount/Makefile]
@@ -163,6 +164,7 @@ AC_CONFIG_FILES([Makefile]
                 [nsm/Makefile]
                 [portmap/Makefile]
                 [rquota/Makefile]
+                [utils/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 \
@@ -10,20 +10,3 @@ AM_CPPFLAGS = \
        "-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);
                }
 
-               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);
                }
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");
-       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);
        }
@@ -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;
-       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);
@@ -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");
-       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);
        }
@@ -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");
-       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);
        }
@@ -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");
-       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);
        }
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 = \
-       libnfs-private.h \
-       slist.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
+
+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
 
+/*
+ * 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;
@@ -82,9 +92,9 @@ struct rpc_context {
        char *encodebuf;
        int encodebuflen;
 
-       struct rpc_pdu *outqueue;
+       struct rpc_queue outqueue;
        struct sockaddr_storage udp_src;
-       struct rpc_pdu *waitpdu;
+       struct rpc_queue waitpdu[HASHES];
 
        uint32_t inpos;
        uint32_t insize;
@@ -106,6 +116,7 @@ struct rpc_context {
        int tcp_syncnt;
        int uid;
        int gid;
+       uint32_t readahead;
 };
 
 struct rpc_pdu {
@@ -126,6 +137,11 @@ struct rpc_pdu {
        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);
@@ -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_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);
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.
  */
-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.
@@ -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.
@@ -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.
  */
-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.
@@ -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.
  */
-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.
@@ -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.
  */
-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.
@@ -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.
  */
-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.
- *                      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.
  */
-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
- *                      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.
  */
-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
index 406fcdfa0b4525bab3e582f5cdc0f6a903634cd6..dfa2185a06b57854be7f3aea6a9df5291065fbde 100644 (file)
 #if defined(AROS)
 #include <sys/time.h>
 #endif
+#if defined(__APPLE__) && defined(__MACH__)
+#include <sys/time.h>
+#endif
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#define LIBNFS_FEATURE_READAHEAD
+#define NFS_BLKSIZE 4096
+
 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_readahead(struct nfs_context *nfs, uint32_t v);
 
 /*
  * MOUNT THE EXPORT
@@ -322,13 +329,15 @@ EXTERN int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat *
 /*
  * 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
+ * O_APPEND
  * 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.
  */
-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.
  */
-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;
+       uint32_t nlink;
 };
 /*
  * 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_
 
-#define SLIST_ADD(list, item) \
+#define LIBNFS_LIST_ADD(list, item) \
        do {                                                    \
                (item)->next = (*list);                         \
                (*list) = (item);                               \
        } while (0);
 
-#define SLIST_ADD_END(list, item)                              \
+#define LIBNFS_LIST_ADD_END(list, item)                                \
        if ((*list) == NULL) {                                  \
-          SLIST_ADD((list), (item));                           \
+          LIBNFS_LIST_ADD((list), (item));                             \
        } else {                                                \
           void *head = (*list);                                \
           while ((*list)->next)                                \
@@ -36,7 +36,7 @@
           (*list) = head;                                      \
        }
 
-#define SLIST_REMOVE(list, item) \
+#define LIBNFS_LIST_REMOVE(list, item) \
        if ((*list) == (item)) {                                \
           (*list) = (item)->next;                              \
        } else {                                                \
index aa0855f76c5e3b34b7cb0505bc072c4e89e5c75f..1f9a55a7d0e55515730d1c214ff24c162ab1612a 100644 (file)
@@ -18,9 +18,9 @@ libnfs_la_SOURCES = \
        pdu.c \
        socket.c
 
-SOCURRENT=4
+SOCURRENT=5
 SOREVISION=0
-SOAGE=0
+SOAGE=1
 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>
 
-
+   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
@@ -49,6 +52,7 @@ struct rpc_context *rpc_init_context(void)
 {
        struct rpc_context *rpc;
        static uint32_t salt = 0;
+       unsigned int i;
 
        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_reset_queue(&rpc->outqueue);
+       for (i = 0; i < HASHES; i++)
+               rpc_reset_queue(&rpc->waitpdu[i]);
 
        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)
 {
@@ -155,19 +168,27 @@ char *rpc_get_error(struct rpc_context *rpc)
 
 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);
 
-       while((pdu = rpc->outqueue) != NULL) {
+       while ((pdu = rpc->outqueue.head) != NULL) {
                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);
        }
-       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;
 
-             SLIST_REMOVE(&rpc->fragments, fragment);
+             rpc->fragments = fragment->next;
              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);
-       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;
+       unsigned int i;
 
        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);
-               SLIST_REMOVE(&rpc->outqueue, pdu);
+               LIBNFS_LIST_REMOVE(&rpc->outqueue.head, 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);
index 7ba52225395fcfc10f715181030882240c672640..d4a54513f2647df3e3020bea932971223f3d8d70 100644 (file)
 #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
 #include <sys/ioctl.h>
 #endif
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
 #ifdef HAVE_POLL_H
 #include <poll.h>
 #endif
 #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) {
-               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;
        }
 
@@ -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.call = "pread";
 
        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)
 {
-       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;
 
-       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)
@@ -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;
+       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");
@@ -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)
 {
-       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;
 
@@ -1328,7 +1354,7 @@ void free_nfs_srvr_list(struct nfs_server_list *srv)
                free(srv);
                srv = next;
        }
-}           
+}
 
 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;
        }
-       
+
        /* 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) {
-               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;
        }
@@ -1399,7 +1425,7 @@ static int send_nfsd_probes(struct rpc_context *rpc, INTERFACE_INFO *InterfaceLi
 
   assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
-  for(i = 0; i < numIfs; i++) 
+  for(i = 0; i < numIfs; i++)
   {
     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;
-               
+
     nFlags = InterfaceList[i].iiFlags;
 
-    if (!(nFlags & IFF_UP)) 
+    if (!(nFlags & IFF_UP))
     {
       continue;
     }
 
-    if (nFlags & IFF_LOOPBACK) 
+    if (nFlags & IFF_LOOPBACK)
     {
       continue;
     }
 
-    if (!(nFlags & IFF_BROADCAST)) 
+    if (!(nFlags & IFF_BROADCAST))
     {
       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;
     }
 
-    if (rpc_set_udp_destination(rpc, bcdd, 111, 1) < 0) 
+    if (rpc_set_udp_destination(rpc, bcdd, 111, 1) < 0)
     {
       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;
     }
@@ -1457,34 +1483,34 @@ struct nfs_server_list *nfs_find_local_servers(void)
   int nNumInterfaces = 0;
 
   rpc = rpc_init_udp_context();
-  if (rpc == NULL) 
+  if (rpc == 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;
   }
 
-  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);
 
-  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);
-    for(;;) 
+    for(;;)
     {
       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);
 
-      if (poll(&pfd, 1, mpt) < 0) 
+      if (poll(&pfd, 1, mpt) < 0)
       {
         free_nfs_srvr_list(data.srvrs);
         rpc_destroy_context(rpc);
         return NULL;
       }
-      if (pfd.revents == 0) 
+      if (pfd.revents == 0)
       {
         break;
       }
-               
-      if (rpc_service(rpc, pfd.revents) < 0) 
+
+      if (rpc_service(rpc, pfd.revents) < 0)
       {
         break;
       }
@@ -1516,7 +1542,7 @@ struct nfs_server_list *nfs_find_local_servers(void)
 
   rpc_destroy_context(rpc);
 
-  if (data.status != 0) 
+  if (data.status != 0)
   {
     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;
                }
 
-               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;
                }
        }
@@ -1607,21 +1633,21 @@ struct nfs_server_list *nfs_find_local_servers(void)
        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);
-                       free(ifc.ifc_buf);      
+                       free(ifc.ifc_buf);
                        return NULL;
                }
-       }       
+       }
 
        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;
                }
 
@@ -1645,14 +1671,14 @@ struct nfs_server_list *nfs_find_local_servers(void)
                        if (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) {
index 7eae9520c9a85d4b47d8267b3300364e4bf0acaa..5a0df03018c64bfd58665841a66a9a27c6a8de12 100644 (file)
@@ -70,6 +70,7 @@ nfs_set_auth
 nfs_set_gid
 nfs_set_tcp_syncnt
 nfs_set_uid
+nfs_set_readahead
 nfs_stat
 nfs_stat_async
 nfs_stat64
@@ -96,12 +97,21 @@ rpc_disconnect
 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
index bb89d4a8c10bb34fd541801af242d7d3704ce1f6..94f03cb520455600f5d27c93301e8fecc1122dfb 100644 (file)
 #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-raw-portmap.h"
 #include "libnfs-private.h"
 
+#define MAX_DIR_CACHE 128
+
 struct nfsdir {
+       struct nfs_fh3 fh;
+       fattr3 attr;
+       struct nfsdir *next;
+
        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;
+       int is_append;
        uint64_t offset;
+       struct nfs_readahead ra;
 };
 
 struct nfs_context {
@@ -94,6 +114,7 @@ struct nfs_context {
        uint64_t readmax;
        uint64_t writemax;
        char *cwd;
+       struct nfsdir *dircache;
 };
 
 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->fh.data.data_val);
        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;
-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;
@@ -132,9 +184,8 @@ struct nfs_cb_data {
        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;
-       size_t request_size;
        char *usrbuf;
 };
 
@@ -142,9 +193,10 @@ struct nfs_mcb_data {
        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)
 {
@@ -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)
 {
-       if (!strncmp(arg, "tcp-syncnt", 10)) {
+       if (!strcmp(arg, "tcp-syncnt")) {
                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));
-       } else if (!strncmp(arg, "gid", 3)) {
+       } else if (!strcmp(arg, "gid")) {
                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;
 }
@@ -375,6 +429,12 @@ void nfs_destroy_context(struct nfs_context *nfs)
                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);
 }
 
@@ -394,6 +454,30 @@ void free_rpc_cb_data(struct rpc_cb_data *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;
@@ -414,6 +498,25 @@ static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *
                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);
 }
@@ -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;
-       uint32_t rpc_port;
+       struct pmap3_string_result *gar;
+       uint32_t rpc_port = 0;
+       unsigned char *ptr;
 
        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;
        }
 
-       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);
@@ -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;
+       struct pmap3_mapping map;
 
        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;
        }
 
-       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;
        }
 
-       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;
 
@@ -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;
@@ -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;
@@ -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");
-       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;
        }
+
        /* 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
  */
@@ -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;
 
-       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;
@@ -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;
+       fattr3 *attr;
 
        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;
        }
 
-       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;
@@ -964,11 +974,10 @@ static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb
                if (slash != NULL) {
                        *slash = '/';
                }
-               data->continue_cb(nfs, data);
+               data->continue_cb(nfs, attr, data);
                return 0;
        }
 
-
        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);
-       if (len >= 1) {
+       if (len > 1) {
                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;
 }
 
+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;
+       struct GETATTR3args args;
 
        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;
-
-       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;
        }
+
+       /* 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;
 }
 
 
-
-
-
 /*
  * 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_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;
@@ -1206,7 +1260,7 @@ static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_dat
        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;
 
@@ -1286,7 +1340,7 @@ static void nfs_stat64_1_cb(struct rpc_context *rpc, int status, void *command_d
        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;
 
@@ -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_APPEND) {
+               nfsfh->is_append = 1;
+       }
 
        /* 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_APPEND) {
+               nfsfh->is_append = 1;
+       }
 
        /* 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);
 }
 
-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;
@@ -1504,7 +1564,7 @@ int nfs_open_async(struct nfs_context *nfs, const char *path, int flags, nfs_cb
 /*
  * 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);
@@ -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;
-               } 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 (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) {
-                                       data->buffer =  malloc(data->request_size);
+                                       data->buffer =  malloc(data->count);
                                        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;
                                        }
                                }
                        }
-                       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) {
-                                               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!");
@@ -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 */
-                       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;
-                                       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++;
@@ -1634,17 +1699,37 @@ static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_dat
                return;
        }
 
-       data->nfsfh->offset = data->max_offset;
        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);
        }
 
+       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);
 }
 
-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;
 
@@ -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->request_size = count;
-
-       nfsfh->offset = offset;
+       data->org_offset   = offset;
+       data->org_count    = count;
 
        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.
         */
-       data->max_offset = offset;
-       data->start_offset = offset;
-
        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->update_pos = update_pos;
 
                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;
 }
 
+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)
 {
-       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->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;
 }
@@ -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  {
-                       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;
-                                       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,
-                                                                               &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;
@@ -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;
        }
 
-       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);
 }
 
 
-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;
 
@@ -1839,8 +1995,6 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
        data->nfsfh        = nfsfh;
        data->usrbuf       = buf;
 
-       nfsfh->offset = offset;
-
        /* 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;
-       data->start_offset = offset;
+       data->offset = offset;
 
        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->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);
@@ -1895,12 +2050,80 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
        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()
  */
+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)
 {
-       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->ra.buf);
        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()
  */
-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;
@@ -2160,7 +2384,7 @@ static void nfs_mkdir_cb(struct rpc_context *rpc, int status, void *command_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;
@@ -2251,7 +2475,7 @@ static void nfs_rmdir_cb(struct rpc_context *rpc, int status, void *command_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;
@@ -2396,7 +2620,7 @@ static void nfs_creat_1_cb(struct rpc_context *rpc, int status, void *command_da
        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;
@@ -2487,7 +2711,7 @@ static void nfs_unlink_cb(struct rpc_context *rpc, int status, void *command_dat
        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;
@@ -2586,7 +2810,7 @@ static void nfs_mknod_cb(struct rpc_context *rpc, int status, void *command_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;
@@ -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->nlink = attributes->nlink;
                }
        }
 
@@ -2840,49 +3065,54 @@ static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_d
                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;
 
-       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);
-                               rdpe_cb_data->status = RPC_STATUS_ERROR;
                                free(rdpe_lookup_cb_data);
+                               free(rdpe_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);
-                       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->nlink = entry->name_attributes.post_op_attr_u.attributes.nlink;
                }
 
                nfsdirent->next  = nfsdir->entries;
@@ -2998,6 +3229,9 @@ static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_da
                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;
@@ -3006,9 +3240,34 @@ static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_da
        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;
+       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;
@@ -3058,9 +3317,9 @@ struct nfsdirent *nfs_readdir(struct nfs_context *nfs _U_, struct nfsdir *nfsdir
 /*
  * 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;
-       uint64_t offset;
+       int64_t offset;
        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;
+       uint64_t size = 0;
 
        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;
        }
 
-       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);
 }
 
-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) {
-               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) {
-               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;
        }
 
@@ -3191,11 +3468,11 @@ static void nfs_statvfs_1_cb(struct rpc_context *rpc, int status, void *command_
                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)
@@ -3209,7 +3486,7 @@ static void nfs_statvfs_1_cb(struct rpc_context *rpc, int status, void *command_
        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;
 
@@ -3271,7 +3548,7 @@ static void nfs_readlink_1_cb(struct rpc_context *rpc, int status, void *command
        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;
 
@@ -3333,7 +3610,7 @@ static void nfs_chmod_cb(struct rpc_context *rpc, int status, void *command_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;
 
@@ -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);
 
-       if (nfs_chmod_continue_internal(nfs, data) != 0) {
+       if (nfs_chmod_continue_internal(nfs, NULL, data) != 0) {
                return -1;
        }
 
@@ -3436,7 +3713,7 @@ struct nfs_chown_data {
        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;
@@ -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);
 
-       if (nfs_chown_continue_internal(nfs, data) != 0) {
+       if (nfs_chown_continue_internal(nfs, NULL, data) != 0) {
                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);
 }
 
-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;
@@ -3705,7 +3982,7 @@ static void nfs_access_cb(struct rpc_context *rpc, int status, void *command_dat
        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;
@@ -3802,7 +4079,7 @@ static void nfs_symlink_cb(struct rpc_context *rpc, int status, void *command_da
        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;
@@ -3938,7 +4215,7 @@ static void nfs_rename_cb(struct rpc_context *rpc, int status, void *command_dat
        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;
@@ -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);
@@ -4108,7 +4385,7 @@ static void nfs_link_cb(struct rpc_context *rpc, int status, void *command_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;
@@ -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;
 
@@ -4233,6 +4510,10 @@ void nfs_set_gid(struct nfs_context *nfs, int 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;
@@ -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;
@@ -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;
        }
-       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;
        }
index 5def0bc5d9041363b2bc833b5f50677750e5c517..4d487b71b0c692408dd606881294eaa229dde9b0 100644 (file)
--- a/lib/pdu.c
+++ b/lib/pdu.c
 #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;
@@ -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) {
+               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;
                }
-               SLIST_ADD_END(&rpc->waitpdu, pdu);
+
+               hash = rpc_hash_xid(pdu->xid);
+               rpc_enqueue(&rpc->waitpdu[hash], pdu);
                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);
-       SLIST_ADD_END(&rpc->outqueue, pdu);
+       rpc_enqueue(&rpc->outqueue, pdu);
 
        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)
 {
-       struct rpc_pdu *pdu;
+       struct rpc_pdu *pdu, *prev_pdu;
+       struct rpc_queue *q;
        ZDR zdr;
        int pos, recordmarker = 0;
+       unsigned int hash;
        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);
 
-       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) {
+                       prev_pdu = pdu;
                        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");
index 055109a73c9f7b4be1f69d73f0552feb5c2d51ff..f973f0178b923a0dab3f369fea14a04b076e85ab 100644 (file)
@@ -80,7 +80,6 @@
 #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);
 
@@ -96,6 +95,14 @@ static void set_nonblocking(int fd)
 #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)
 {
@@ -123,6 +130,11 @@ int rpc_get_fd(struct rpc_context *rpc)
        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;
@@ -136,7 +148,7 @@ int rpc_which_events(struct rpc_context *rpc)
                return POLLIN;
        }
 
-       if (rpc->outqueue) {
+       if (rpc_has_queue(&rpc->outqueue)) {
                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;
+       struct rpc_pdu *pdu;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -153,12 +166,12 @@ static int rpc_write_to_socket(struct rpc_context *rpc)
                return -1;
        }
 
-       while (rpc->outqueue != NULL) {
+       while ((pdu = rpc->outqueue.head) != NULL) {
                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;
@@ -167,12 +180,16 @@ static int rpc_write_to_socket(struct rpc_context *rpc)
                        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;
@@ -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;
@@ -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);
                }
+#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:
@@ -449,7 +475,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
         * 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;
@@ -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")) {
-                               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)
@@ -482,6 +522,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
        }
 
        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);
@@ -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)
 {
-       struct sockaddr_in *sin = (struct sockaddr_in *)&rpc->s;
+       struct addrinfo *ai = NULL;
 
        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;
 
-       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;
-       }
-
+       }
 
-       switch (rpc->s.ss_family) {
+       switch (ai->ai_family) {
        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
-               sin->sin_len = sizeof(struct sockaddr_in);
+               ((struct sockaddr_in6 *)&rpc->s)->sin6_len = sizeof(struct sockaddr_in6);
 #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;
 
+       freeaddrinfo(ai);
+
        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;
+       unsigned int i;
 
        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
         */
-       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) {
@@ -697,14 +754,19 @@ int rpc_queue_length(struct rpc_context *rpc)
 {
        int i=0;
        struct rpc_pdu *pdu;
+       unsigned int n;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
-       for(pdu = rpc->outqueue; pdu; pdu = pdu->next) {
+       for(pdu = rpc->outqueue.head; pdu; pdu = pdu->next) {
                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;
 }
index 138d031b8e444cb630eae020d689f91ed3acb1fc..de7fdbdeb0fb28bb7f2ab996e36a9edfb960f598 100644 (file)
@@ -17,6 +17,8 @@ mount-stamp : mount.x
        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.
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.
@@ -6,7 +35,8 @@
 #ifndef _MOUNT_H_RPCGEN
 #define _MOUNT_H_RPCGEN
 
-#include <nfsc/libnfs-zdr.h>
+
+
 
 #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 */
index aad66ce60957ed87e0ffdea7afc945c16b467a47..2177519c8b71576ee5ec72e2a74bb7dd93258e7f 100644 (file)
@@ -18,5 +18,7 @@ nfs-stamp : nfs.x
        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.
@@ -17,24 +46,13 @@ zdr_cookieverf3 (ZDR *zdrs, cookieverf3 objp)
        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;
 
-        if (!zdr_uint64 (zdrs, objp))
+        if (!zdr_u_quad_t (zdrs, objp))
                 return FALSE;
        return TRUE;
 }
@@ -124,7 +142,7 @@ zdr_size3 (ZDR *zdrs, size3 *objp)
        register int32_t *buf;
        buf = NULL;
 
-        if (!zdr_uint64 (zdrs, objp))
+        if (!zdr_u_quad_t (zdrs, objp))
                 return FALSE;
        return TRUE;
 }
@@ -135,7 +153,7 @@ zdr_fileid3 (ZDR *zdrs, fileid3 *objp)
        register int32_t *buf;
        buf = NULL;
 
-        if (!zdr_uint64 (zdrs, objp))
+        if (!zdr_u_quad_t (zdrs, objp))
                 return FALSE;
        return TRUE;
 }
@@ -188,7 +206,7 @@ zdr_fattr3 (ZDR *zdrs, fattr3 *objp)
                 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;
@@ -250,7 +268,7 @@ zdr_offset3 (ZDR *zdrs, offset3 *objp)
        register int32_t *buf;
        buf = NULL;
 
-        if (!zdr_uint64 (zdrs, objp))
+        if (!zdr_u_quad_t (zdrs, objp))
                 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.
@@ -30,9 +59,7 @@ typedef long long unsigned u_quad_t;
 
 typedef char cookieverf3[NFS3_COOKIEVERFSIZE];
 
-typedef u_quad_t uint64;
-
-typedef uint64 cookie3;
+typedef u_quad_t cookie3;
 
 struct nfs_fh3 {
        struct {
@@ -67,9 +94,9 @@ typedef u_int uid3;
 
 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;
@@ -92,7 +119,7 @@ struct fattr3 {
        size3 size;
        size3 used;
        specdata3 rdev;
-       uint64 fsid;
+       u_quad_t fsid;
        fileid3 fileid;
        nfstime3 atime;
        nfstime3 mtime;
@@ -148,7 +175,7 @@ enum stable_how {
 };
 typedef enum stable_how stable_how;
 
-typedef uint64 offset3;
+typedef u_quad_t offset3;
 
 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);
-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*);
@@ -1799,7 +1825,6 @@ extern  bool_t zdr_SETACL3res (ZDR *, SETACL3res*);
 
 #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 ();
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
@@ -10,16 +37,7 @@ const NFS3_COOKIEVERFSIZE = 8;
 
 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>;
@@ -48,9 +66,9 @@ typedef unsigned int uid3;
 
 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;
@@ -71,7 +89,7 @@ struct fattr3 {
        size3        size;
        size3        used;
        specdata3    rdev;
-       uint64       fsid;
+       u_quad_t       fsid;
        fileid3      fileid;
        nfstime3     atime;
        nfstime3     mtime;
@@ -124,7 +142,7 @@ enum stable_how {
        FILE_SYNC = 2
 };
 
-typedef uint64 offset3;
+typedef u_quad_t offset3;
 
 typedef unsigned int count3;
 
index 5b6d02fbc0d81a7c5b3a15ed40fff8d58154616e..0cc563dbf5b327c92010b6adace537c80ed5ded8 100644 (file)
@@ -18,5 +18,7 @@ nlm-stamp : nlm.x
        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.
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.
 #ifndef _NLM_H_RPCGEN
 #define _NLM_H_RPCGEN
 
-#include <nfsc/libnfs-zdr.h>
+
+
 
 #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 {
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<>;
@@ -29,8 +54,8 @@ struct nlm4_holder {
        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;
@@ -39,8 +64,8 @@ struct nlm4_lock {
        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 {
index 6362ddb938a14918327f245123fe83a6ef38617b..3bf06a84ed83051b931fbedd2f269eb9bba5d3bf 100644 (file)
@@ -18,5 +18,7 @@ nsm-stamp : nsm.x
        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.
@@ -90,6 +119,7 @@ zdr_NSM1_MONargs (ZDR *zdrs, NSM1_MONargs *objp)
        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))
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.
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
index 98acdbc4d1df71eaf01bd508fd5c9c0aca15773f..8b34636f30ce38d0146e1efc4d4144f5c56e43a5 100644 (file)
@@ -95,8 +95,20 @@ development libraries for LibNFS
 %{_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
-* 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
@@ -120,7 +132,7 @@ development libraries for LibNFS
  - 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
index 4d486fc3f79d451eade9ac3d829a7ca6065efdd3..682ca2ac5a6695fbe6a0aae59f5b567c2e365880 100644 (file)
@@ -18,5 +18,7 @@ portmap-stamp : portmap.x
        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.
@@ -7,7 +36,7 @@
 #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;
@@ -63,7 +92,7 @@ zdr_pmap_mapping (ZDR *zdrs, pmap_mapping *objp)
 }
 
 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;
@@ -119,7 +148,7 @@ zdr_pmap_call_args (ZDR *zdrs, pmap_call_args *objp)
 }
 
 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;
@@ -132,25 +161,161 @@ zdr_pmap_call_result (ZDR *zdrs, pmap_call_result *objp)
 }
 
 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;
 
-        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;
-        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
-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;
 
-        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;
 }
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.
@@ -15,15 +44,15 @@ extern "C" {
 
 #define PMAP_PORT 111
 
-struct pmap_mapping {
+struct pmap2_mapping {
        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;
@@ -32,89 +61,219 @@ struct pmap_call_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;
 };
-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_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 */
-#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 */
+#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)
-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 */
-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 */
 
index 5042e8c19b0eb6bc7fb724953ee28c87d8a53b87..9b0e0f64cf35c3cc79edd9207ffc34d32dd3ac3a 100644 (file)
 #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;
 
-       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) {
-               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) {
-               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;
        }
@@ -45,14 +47,14 @@ int rpc_pmap_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
        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 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) {
-               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;
        }
 
@@ -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;
-       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_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;
        }
@@ -75,14 +77,14 @@ int rpc_pmap_getport_async(struct rpc_context *rpc, int program, int version, in
        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 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) {
-               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;
        }
 
@@ -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;
-       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_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;
        }
@@ -105,14 +107,14 @@ int rpc_pmap_set_async(struct rpc_context *rpc, int program, int version, int pr
        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 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) {
-               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;
        }
 
@@ -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;
-       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_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;
        }
@@ -135,18 +137,18 @@ int rpc_pmap_unset_async(struct rpc_context *rpc, int program, int version, int
        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;
 
-       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) {
-               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) {
-               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;
        }
@@ -154,14 +156,14 @@ int rpc_pmap_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
        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 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) {
-               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;
        }
 
@@ -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;
 
-       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_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;
        }
 
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 */
 
-struct pmap_mapping {
+struct pmap2_mapping {
        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<>;
 };
 
-struct pmap_call_result {
+struct pmap2_call_result {
        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
-               PMAP_NULL(void)              = 0;
+               PMAP2_NULL(void)              = 0;
 
                bool
-               PMAP_SET(pmap_mapping)       = 1;
+               PMAP2_SET(pmap2_mapping)       = 1;
 
                bool
-               PMAP_UNSET(pmap_mapping)     = 2;
+               PMAP2_UNSET(pmap2_mapping)     = 2;
 
                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;
+       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;
 
index 02f86f7f42bfd69834340ee0545304d5d121442b..5a604a8cc2ae9656ec388a65c4c99193a03e8449 100644 (file)
@@ -16,7 +16,9 @@ $(rquota_GENERATED) : rquota-stamp
 rquota-stamp : rquota.x
        rm -f $(rquota_GENERATED)
        touch rquota-stamp
-       
+
 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.
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.
@@ -6,7 +35,8 @@
 #ifndef _RQUOTA_H_RPCGEN
 #define _RQUOTA_H_RPCGEN
 
-#include <nfsc/libnfs-zdr.h>
+
+
 
 #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 */
 
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 nfs_stat_64 st;
        
        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;
                }
-
                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");
@@ -137,28 +130,28 @@ void process_dir(struct nfs_context *nfs, char *dir, int level) {
                        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",
-                       "-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",
-                       "-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);
                
-               if (recursive && (st.nfs_mode & S_IFMT) == S_IFDIR) {
+               if (recursive && (nfsdirent->mode & S_IFMT) == S_IFDIR) {
                        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;
-       struct nfs_url *url;
+       struct nfs_url *url = NULL;
        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_