Hello community,

here is the log from the commit of package libnfs for openSUSE:Factory checked 
in at 2019-07-31 14:12:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libnfs (Old)
 and      /work/SRC/openSUSE:Factory/.libnfs.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libnfs"

Wed Jul 31 14:12:06 2019 rev:7 rq:718320 version:4.0.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/libnfs/libnfs.changes    2018-11-26 
10:11:59.806316784 +0100
+++ /work/SRC/openSUSE:Factory/.libnfs.new.4126/libnfs.changes  2019-07-31 
14:12:07.550950528 +0200
@@ -1,0 +2,20 @@
+Wed Jul 24 15:18:59 UTC 2019 - Bjørn Lie <[email protected]>
+
+- Update to version 4.0.0:
+  + Fix the versioning in makerpms.sh.
+  + Fix some compile issues in the test programs.
+  + NFSv3: skip commit on close if the file has not been written
+    to.
+  + Add nfs_umount() to NFSv3.
+  + Add nfs_statvfs64().
+  + Fix invalid shift of pid_t when generating rpc->xid.
+  + Compile fixes for Mac OSX.
+  + Fix for dup2() on Windows.
+  + NFSv4 fix for directory handling.
+  + Improvements to configure/building.
+- Bump sover to 13 following upstream.
+- Use modern macros.
+- Pass explicit --enable-utils to configure, ensure we build the
+  utils.
+
+-------------------------------------------------------------------

Old:
----
  libnfs-3.0.0.tar.gz

New:
----
  libnfs-4.0.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libnfs.spec ++++++
--- /var/tmp/diff_new_pack.Hcx3EH/_old  2019-07-31 14:12:07.974950381 +0200
+++ /var/tmp/diff_new_pack.Hcx3EH/_new  2019-07-31 14:12:07.974950381 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package libnfs
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 # Copyright (c) 2015 Bjørn Lie, Bryne, Norway.
 #
 # All modifications and additions to the file contributed by third parties
@@ -17,15 +17,17 @@
 #
 
 
-%define sover   12
+%define sover   13
+
 Name:           libnfs
-Version:        3.0.0
+Version:        4.0.0
 Release:        0
 Summary:        Client library for accessing NFS shares over a network
 License:        LGPL-2.1-or-later AND BSD-2-Clause AND GPL-3.0-or-later
 Group:          Productivity/Networking/NFS
 URL:            https://github.com/sahlberg/libnfs
-Source0:        
https://github.com/sahlberg/libnfs/archive/libnfs-%{version}.tar.gz
+Source0:        %{url}/archive/libnfs-%{version}.tar.gz
+
 BuildRequires:  autoconf
 BuildRequires:  libtool
 BuildRequires:  pkgconfig
@@ -69,14 +71,16 @@
 accessing NFS servers using libnfs.
 
 %prep
-%setup -q -n %{name}-%{name}-%{version}
+%autosetup -p1 -n %{name}-%{name}-%{version}
 
 %build
 autoreconf -fiv
 %configure \
        --disable-static \
-       --disable-examples
-make %{?_smp_mflags}
+       --disable-examples \
+       --enable-utils \
+       %{nil}
+%make_build
 
 %install
 %make_install

++++++ libnfs-3.0.0.tar.gz -> libnfs-4.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/CHANGELOG 
new/libnfs-libnfs-4.0.0/CHANGELOG
--- old/libnfs-libnfs-3.0.0/CHANGELOG   2018-06-24 00:53:52.000000000 +0200
+++ new/libnfs-libnfs-4.0.0/CHANGELOG   2019-02-12 22:38:04.000000000 +0100
@@ -1,3 +1,16 @@
+Changes since 3.0.0
+
+Fix the versioning in makerpms.sh
+Fix some compile issues in the test programs.
+NFSv3: skip commit on close if the file has not been written to.
+Add nfs_umount() to NFSv3
+Add nfs_statvfs64()
+Fix invalid shift of pid_t when generating rpc->xid
+Compile fixes for Mac OSX
+Fix for dup2() on Windows
+NFSv4 fix for directory handling
+Improvements to configure/bulding
+
 Changes since 2.0.0
 
 NFSv4 support.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/README 
new/libnfs-libnfs-4.0.0/README
--- old/libnfs-libnfs-3.0.0/README      2018-06-24 00:53:52.000000000 +0200
+++ new/libnfs-libnfs-4.0.0/README      2019-02-12 22:38:04.000000000 +0100
@@ -25,9 +25,9 @@
 
 NFSv4:
 ======
-NFSv4 is supported but only for the RAW ASYNC interface.
-Examples/nfsv4-cat.c is a "simple" example to illustrate how to use
-NFSv4 to connect to a server and read a file off the server.
+NFSv3 is the default but NFSv4 can be selected either by using the URL argument
+version=4 or programatically calling nfs_set_version(nfs, NFS_V4) before
+connecting to the server/share.
 
 SERVER SUPPORT:
 ===============
@@ -67,8 +67,6 @@
                          to the application.
  if=<interface>    : Interface name (e.g., eth1) to bind; requires `root`
  version=<3|4>     : NFS Version. Default is 3.
-                     This is just a placeholder for now. NFSv4 support is not
-                    yet functional.
  nfsport=<port>    : Use this port for NFS instead of using the portmapper.
  mountport=<port>  : Use this port for the MOUNT protocol instead of
                      using portmapper. This argument is ignored for NFSv4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/configure.ac 
new/libnfs-libnfs-4.0.0/configure.ac
--- old/libnfs-libnfs-3.0.0/configure.ac        2018-06-24 00:53:52.000000000 
+0200
+++ new/libnfs-libnfs-4.0.0/configure.ac        2019-02-12 22:38:04.000000000 
+0100
@@ -1,5 +1,5 @@
 AC_PREREQ(2.50)
-AC_INIT([libnfs], [3.0.0], [[email protected]])
+AC_INIT([libnfs], [4.0.0], [[email protected]])
 AC_CONFIG_HEADERS([config.h])
 AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
 AC_CANONICAL_HOST
@@ -25,11 +25,13 @@
 AC_SYS_LARGEFILE
 
 #option: utils
+MAYBE_UTILS="utils"
 AC_ARG_ENABLE([utils],
               [AC_HELP_STRING([--enable-utils],
                               [Build util programs])],
-             [MAYBE_UTILS=""],
-             [MAYBE_UTILS="utils"])
+             [if test $enableval = no ; then
+                   MAYBE_UTILS=""
+              fi])
 AC_SUBST(MAYBE_UTILS)
 
 #option: examples
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/examples/nfs-fh.c 
new/libnfs-libnfs-4.0.0/examples/nfs-fh.c
--- old/libnfs-libnfs-3.0.0/examples/nfs-fh.c   2018-06-24 00:53:52.000000000 
+0200
+++ new/libnfs-libnfs-4.0.0/examples/nfs-fh.c   2019-02-12 22:38:04.000000000 
+0100
@@ -122,6 +122,7 @@
        if (nfsfh) {
                nfs_close(nfs, nfsfh);
        }
+        nfs_umount(nfs);
        if (url) {
                nfs_destroy_url(url);
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/include/libnfs-private.h 
new/libnfs-libnfs-4.0.0/include/libnfs-private.h
--- old/libnfs-libnfs-3.0.0/include/libnfs-private.h    2018-06-24 
00:53:52.000000000 +0200
+++ new/libnfs-libnfs-4.0.0/include/libnfs-private.h    2019-02-12 
22:38:04.000000000 +0100
@@ -463,10 +463,13 @@
                       int no_follow, nfs_cb cb, void *private_data);
 int nfs3_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
                        void *private_data);
+int nfs3_statvfs64_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
+                         void *private_data);
 int nfs3_symlink_async(struct nfs_context *nfs, const char *oldpath,
                        const char *newpath, nfs_cb cb, void *private_data);
 int nfs3_truncate_async(struct nfs_context *nfs, const char *path,
                         uint64_t length, nfs_cb cb, void *private_data);
+int nfs3_umount_async(struct nfs_context *nfs, nfs_cb cb, void *private_data);
 int nfs3_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
                       void *private_data);
 int nfs3_utime_async(struct nfs_context *nfs, const char *path,
@@ -540,6 +543,8 @@
                       int no_follow, nfs_cb cb, void *private_data);
 int nfs4_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
                        void *private_data);
+int nfs4_statvfs64_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
+                         void *private_data);
 int nfs4_symlink_async(struct nfs_context *nfs, const char *oldpath,
                        const char *newpath, nfs_cb cb, void *private_data);
 int nfs4_truncate_async(struct nfs_context *nfs, const char *path,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/include/nfsc/libnfs.h 
new/libnfs-libnfs-4.0.0/include/nfsc/libnfs.h
--- old/libnfs-libnfs-3.0.0/include/nfsc/libnfs.h       2018-06-24 
00:53:52.000000000 +0200
+++ new/libnfs-libnfs-4.0.0/include/nfsc/libnfs.h       2019-02-12 
22:38:04.000000000 +0100
@@ -53,8 +53,10 @@
 #if defined(WIN32)
 #define EXTERN __declspec( dllexport )
 #else
+#ifndef EXTERN
 #define EXTERN
 #endif
+#endif
 
 #ifdef WIN32
 #ifdef HAVE_FUSE_H
@@ -314,6 +316,39 @@
                      const char *exportname);
 
 
+/*
+ * UNMOUNT THE EXPORT
+ */
+/*
+ * Async nfs umount.
+ * For NFSv4 this is a NO-OP.
+ * For NFSv3 this function returns unregisters the mount from the MOUNT Daemon.
+ *
+ *  0 : The command was queued successfully. The callback will be invoked once
+ *      the command completes.
+ * <0 : An error occured when trying to queue the command.
+ *      The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ *      0 : Success.
+ *          data is NULL
+ * -errno : An error occured.
+ *          data is the error string.
+ */
+EXTERN int nfs_umount_async(struct nfs_context *nfs, nfs_cb cb,
+                           void *private_data);
+/*
+ * Sync nfs umount.
+ * For NFSv4 this is a NO-OP.
+ * For NFSv3 this function returns unregisters the mount from the MOUNT Daemon.
+ *
+ * Function returns
+ *      0 : The operation was successful.
+ * -errno : The command failed.
+ */
+EXTERN int nfs_umount(struct nfs_context *nfs);
+
+
 
 
 /*
@@ -1290,8 +1325,23 @@
 /*
  * STATVFS()
  */
+struct nfs_statvfs_64 {
+       uint64_t        f_bsize;
+       uint64_t        f_frsize;
+       uint64_t        f_blocks;
+       uint64_t        f_bfree;
+       uint64_t        f_bavail;
+       uint64_t        f_files;
+       uint64_t        f_ffree;
+       uint64_t        f_favail;
+       uint64_t        f_fsid;
+       uint64_t        f_flag;
+       uint64_t        f_namemax;
+};
 /*
  * Async statvfs(<dirname>)
+ * This function is deprecated. Use nfs_statvfs64_async() instead.
+ *
  * Function returns
  *  0 : The command was queued successfully. The callback will be invoked once
  *      the command completes.
@@ -1309,13 +1359,40 @@
                              nfs_cb cb, void *private_data);
 /*
  * Sync statvfs(<dirname>)
+ * This function is deprecated. Use nfs_statvfs64() instead.
+ *
  * Function returns
  *      0 : The operation was successful.
  * -errno : The command failed.
  */
 EXTERN int nfs_statvfs(struct nfs_context *nfs, const char *path,
                        struct statvfs *svfs);
-
+/*
+ * Async statvfs64(<dirname>)
+ *
+ * Function returns
+ *  0 : The command was queued successfully. The callback will be invoked once
+ *      the command completes.
+ * <0 : An error occured when trying to queue the command.
+ *      The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ *      0 : Success.
+ *          data is struct nfs_statvfs_64 *
+ * -errno : An error occured.
+ *          data is the error string.
+ */
+EXTERN int nfs_statvfs64_async(struct nfs_context *nfs, const char *path,
+                               nfs_cb cb, void *private_data);
+/*
+ * Sync statvfs64(<dirname>)
+ *
+ * Function returns
+ *      0 : The operation was successful.
+ * -errno : The command failed.
+ */
+EXTERN int nfs_statvfs64(struct nfs_context *nfs, const char *path,
+                         struct nfs_statvfs_64 *svfs);
 
 /*
  * READLINK()
@@ -1336,7 +1413,6 @@
  * -errno : An error occured.
  *          data is the error string.
  */
-struct statvfs;
 EXTERN int nfs_readlink_async(struct nfs_context *nfs, const char *path,
                               nfs_cb cb, void *private_data);
 /*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/lib/CMakeLists.txt 
new/libnfs-libnfs-4.0.0/lib/CMakeLists.txt
--- old/libnfs-libnfs-3.0.0/lib/CMakeLists.txt  2018-06-24 00:53:52.000000000 
+0200
+++ new/libnfs-libnfs-4.0.0/lib/CMakeLists.txt  2019-02-12 22:38:04.000000000 
+0100
@@ -9,6 +9,7 @@
 
 add_library(nfs ${SOURCES})
 target_link_libraries(nfs PUBLIC ${core_DEPENDS})
+target_include_directories(nfs PUBLIC ../include)
 set_target_properties(nfs PROPERTIES
                           VERSION ${PROJECT_VERSION}
                           SOVERSION ${SOVERSION})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/lib/Makefile.am 
new/libnfs-libnfs-4.0.0/lib/Makefile.am
--- old/libnfs-libnfs-3.0.0/lib/Makefile.am     2018-06-24 00:53:52.000000000 
+0200
+++ new/libnfs-libnfs-4.0.0/lib/Makefile.am     2019-02-12 22:38:04.000000000 
+0100
@@ -25,7 +25,7 @@
        socket.c \
        ../win32/win32_compat.c
 
-SOCURRENT=12
+SOCURRENT=13
 SOREVISION=0
 SOAGE=0
 libnfs_la_LDFLAGS = -version-info $(SOCURRENT):$(SOREVISION):$(SOAGE)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/lib/init.c 
new/libnfs-libnfs-4.0.0/lib/init.c
--- old/libnfs-libnfs-3.0.0/lib/init.c  2018-06-24 00:53:52.000000000 +0200
+++ new/libnfs-libnfs-4.0.0/lib/init.c  2019-02-12 22:38:04.000000000 +0100
@@ -81,7 +81,9 @@
                free(rpc);
                return NULL;
        }
-       rpc->xid = salt + (uint32_t)rpc_current_time() + (getpid() << 16);
+       // Add PID to rpc->xid for easier debugging, making sure to cast
+       // pid to 32-bit type to avoid invalid left-shifts.
+       rpc->xid = salt + rpc_current_time() + ((uint32_t)getpid() << 16);
        salt += 0x01000000;
        rpc->fd = -1;
        rpc->tcp_syncnt = RPC_PARAM_UNDEFINED;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/lib/libnfs-sync.c 
new/libnfs-libnfs-4.0.0/lib/libnfs-sync.c
--- old/libnfs-libnfs-3.0.0/lib/libnfs-sync.c   2018-06-24 00:53:52.000000000 
+0200
+++ new/libnfs-libnfs-4.0.0/lib/libnfs-sync.c   2019-02-12 22:38:04.000000000 
+0100
@@ -229,6 +229,57 @@
 
 
 /*
+ * unregister the mount
+ */
+static void
+umount_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
+{
+       struct sync_cb_data *cb_data = private_data;
+
+       cb_data->is_finished = 1;
+       cb_data->status = status;
+
+       if (status < 0) {
+               nfs_set_error(nfs, "%s: %s",
+                              __FUNCTION__, nfs_get_error(nfs));
+               return;
+       }
+}
+
+int
+nfs_umount(struct nfs_context *nfs)
+{
+       struct sync_cb_data cb_data;
+       struct rpc_context *rpc = nfs_get_rpc_context(nfs);
+
+       assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+       cb_data.is_finished = 0;
+
+       if (nfs_umount_async(nfs, umount_cb, &cb_data) != 0) {
+               nfs_set_error(nfs, "nfs_umount_async failed. %s",
+                             nfs_get_error(nfs));
+               return -1;
+       }
+
+       wait_for_nfs_reply(nfs, &cb_data);
+
+       /* Dont want any more callbacks even if the socket is closed */
+       rpc->connect_cb = NULL;
+
+       /* Ensure that no RPCs are pending. In error case (e.g. timeout in
+        * wait_for_nfs_reply()) we can disconnect; in success case all RPCs
+        * are completed by definition.
+        */
+       if (cb_data.status) {
+               rpc_disconnect(rpc, "failed mount");
+       }
+
+       return cb_data.status;
+}
+
+
+/*
  * stat()
  */
 static void
@@ -1166,6 +1217,46 @@
        return cb_data.status;
 }
 
+/*
+ * statvfs64()
+ */
+static void
+statvfs64_cb(int status, struct nfs_context *nfs, void *data,
+             void *private_data)
+{
+       struct sync_cb_data *cb_data = private_data;
+
+       cb_data->is_finished = 1;
+       cb_data->status = status;
+
+       if (status < 0) {
+               nfs_set_error(nfs, "statvfs64 call failed with \"%s\"",
+                              (char *)data);
+               return;
+       }
+
+       memcpy(cb_data->return_data, data, sizeof(struct nfs_statvfs_64));
+}
+
+int
+nfs_statvfs64(struct nfs_context *nfs, const char *path,
+              struct nfs_statvfs_64 *svfs)
+{
+       struct sync_cb_data cb_data;
+
+       cb_data.is_finished = 0;
+       cb_data.return_data = svfs;
+
+       if (nfs_statvfs64_async(nfs, path, statvfs64_cb, &cb_data) != 0) {
+               nfs_set_error(nfs, "nfs_statvfs64_async failed. %s",
+                              nfs_get_error(nfs));
+               return -1;
+       }
+
+       wait_for_nfs_reply(nfs, &cb_data);
+
+       return cb_data.status;
+}
 
 /*
  * readlink()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/lib/libnfs-win32.def 
new/libnfs-libnfs-4.0.0/lib/libnfs-win32.def
--- old/libnfs-libnfs-3.0.0/lib/libnfs-win32.def        2018-06-24 
00:53:52.000000000 +0200
+++ new/libnfs-libnfs-4.0.0/lib/libnfs-win32.def        2019-02-12 
22:38:04.000000000 +0100
@@ -95,10 +95,14 @@
 nfs_stat64_async
 nfs_statvfs
 nfs_statvfs_async
+nfs_statvfs64
+nfs_statvfs64_async
 nfs_symlink
 nfs_symlink_async
 nfs_truncate
 nfs_truncate_async
+nfs_umount
+nfs_umount_async
 nfs_unlink
 nfs_unlink_async
 nfs_utime
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/lib/libnfs.c 
new/libnfs-libnfs-4.0.0/lib/libnfs.c
--- old/libnfs-libnfs-3.0.0/lib/libnfs.c        2018-06-24 00:53:52.000000000 
+0200
+++ new/libnfs-libnfs-4.0.0/lib/libnfs.c        2019-02-12 22:38:04.000000000 
+0100
@@ -66,10 +66,15 @@
 #include <sys/sysmacros.h>
 #endif
 
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
 #include <errno.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include "slist.h"
 #include "libnfs.h"
 #include "libnfs-raw.h"
@@ -860,6 +865,26 @@
         }
 }
 
+/*
+ * Async call for umounting an nfs share
+ */
+int
+nfs_umount_async(struct nfs_context *nfs, nfs_cb cb, void *private_data)
+{
+       switch (nfs->version) {
+        case NFS_V3:
+                return nfs3_umount_async(nfs, cb, private_data);
+        case NFS_V4:
+                /* umount is a no-op in v4 */
+                (*cb)(0, nfs, NULL, private_data);
+                return 0;
+        default:
+                nfs_set_error(nfs, "%s does not support NFSv%d",
+                              __FUNCTION__, nfs->version);
+                return -1;
+        }
+}
+
 int
 nfs_normalize_path(struct nfs_context *nfs, char *path)
 {
@@ -1462,6 +1487,22 @@
         default:
                 nfs_set_error(nfs, "%s does not support NFSv%d",
                               __FUNCTION__, nfs->version);
+                return -1;
+        }
+}
+
+int
+nfs_statvfs64_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
+                    void *private_data)
+{
+       switch (nfs->version) {
+        case NFS_V3:
+                return nfs3_statvfs64_async(nfs, path, cb, private_data);
+        case NFS_V4:
+                return nfs4_statvfs64_async(nfs, path, cb, private_data);
+        default:
+                nfs_set_error(nfs, "%s does not support NFSv%d",
+                              __FUNCTION__, nfs->version);
                 return -1;
         }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/lib/nfs_v3.c 
new/libnfs-libnfs-4.0.0/lib/nfs_v3.c
--- old/libnfs-libnfs-3.0.0/lib/nfs_v3.c        2018-06-24 00:53:52.000000000 
+0200
+++ new/libnfs-libnfs-4.0.0/lib/nfs_v3.c        2019-02-12 22:38:04.000000000 
+0100
@@ -1152,6 +1152,92 @@
        return 0;
 }
 
+static void
+nfs3_umount_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 (check_nfs3_error(nfs, status, data, command_data)) {
+               free_nfs_cb_data(data);
+               return;
+       }
+
+       rpc_disconnect(rpc, "umount");
+       data->cb(0, nfs, NULL, data->private_data);
+       free_nfs_cb_data(data);
+}
+
+static void
+nfs3_umount_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);
+
+       if (check_nfs3_error(nfs, status, data, command_data)) {
+               free_nfs_cb_data(data);
+               return;
+       }
+
+       if (rpc_mount3_umnt_async(rpc, nfs3_umount_2_cb, nfs->export,
+                                 data) != 0) {
+                nfs_set_error(nfs, "%s: %s.", __FUNCTION__, 
nfs_get_error(nfs));
+               data->cb(-ENOMEM, nfs, nfs_get_error(nfs), data->private_data);
+               free_nfs_cb_data(data);
+               return;
+       }
+}
+
+int
+nfs3_umount_async(struct nfs_context *nfs, nfs_cb cb, void *private_data)
+{
+       struct nfs_cb_data *data;
+
+       data = malloc(sizeof(struct nfs_cb_data));
+       if (data == NULL) {
+               nfs_set_error(nfs, "out of memory. failed to allocate "
+                             "memory for nfs mount data");
+               return -1;
+       }
+       memset(data, 0, sizeof(struct nfs_cb_data));
+
+       data->nfs          = nfs;
+       data->cb           = cb;
+       data->private_data = private_data;
+
+       rpc_disconnect(nfs->rpc, "umount");
+
+        if (nfs->mountport) {
+                if (rpc_connect_port_async(nfs->rpc, nfs->server,
+                                           nfs->mountport,
+                                           MOUNT_PROGRAM, MOUNT_V3,
+                                           nfs3_umount_1_cb, data) != 0) {
+                        nfs_set_error(nfs, "Failed to start connection. %s",
+                                      nfs_get_error(nfs));
+                        free_nfs_cb_data(data);
+                        return -1;
+                }
+                return 0;
+        }
+
+       if (rpc_connect_program_async(nfs->rpc, nfs->server,
+                                     MOUNT_PROGRAM, MOUNT_V3,
+                                     nfs3_umount_1_cb, data) != 0) {
+               nfs_set_error(nfs, "Failed to start connection. %s",
+                              nfs_get_error(nfs));
+               free_nfs_cb_data(data);
+               return -1;
+       }
+
+       return 0;
+}
+
 
 struct nfs_link_data {
        char *oldpath;
@@ -2272,6 +2358,7 @@
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        struct statvfs svfs;
+       struct nfs_statvfs_64 svfs64;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -2292,21 +2379,39 @@
                return;
        }
 
-       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   = (uint32_t)res->FSSTAT3res_u.resok.tfiles;
-       svfs.f_ffree   = (uint32_t)res->FSSTAT3res_u.resok.ffiles;
+        if (data->continue_int == 0) {
+                /* statvfs */
+                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   = (uint32_t)res->FSSTAT3res_u.resok.tfiles;
+                svfs.f_ffree   = (uint32_t)res->FSSTAT3res_u.resok.ffiles;
 #if !defined(__ANDROID__)
-       svfs.f_favail  = (uint32_t)res->FSSTAT3res_u.resok.afiles;
-       svfs.f_fsid    = 0;
-       svfs.f_flag    = 0;
-       svfs.f_namemax = 256;
+                svfs.f_favail  = (uint32_t)res->FSSTAT3res_u.resok.afiles;
+                svfs.f_fsid    = 0;
+                svfs.f_flag    = 0;
+                svfs.f_namemax = 256;
 #endif
+                data->cb(0, nfs, &svfs, data->private_data);
+        } else {
+                /* statvfs64 */
+                svfs64.f_bsize   = NFS_BLKSIZE;
+                svfs64.f_frsize  = NFS_BLKSIZE;
+                svfs64.f_blocks  = res->FSSTAT3res_u.resok.tbytes/NFS_BLKSIZE;
+                svfs64.f_bfree   = res->FSSTAT3res_u.resok.fbytes/NFS_BLKSIZE;
+                svfs64.f_bavail  = res->FSSTAT3res_u.resok.abytes/NFS_BLKSIZE;
+                svfs64.f_files   = res->FSSTAT3res_u.resok.tfiles;
+                svfs64.f_ffree   = res->FSSTAT3res_u.resok.ffiles;
+                svfs64.f_favail  = res->FSSTAT3res_u.resok.afiles;
+                svfs64.f_fsid    = 0;
+                svfs64.f_flag    = 0;
+                svfs64.f_namemax = 256;
+
+                data->cb(0, nfs, &svfs64, data->private_data);
+        }
 
-       data->cb(0, nfs, &svfs, data->private_data);
        free_nfs_cb_data(data);
 }
 
@@ -2344,6 +2449,19 @@
        return 0;
 }
 
+int
+nfs3_statvfs64_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
+                     void *private_data)
+{
+       if (nfs3_lookuppath_async(nfs, path, 0, cb, private_data,
+                                  nfs3_statvfs_continue_internal,
+                                  NULL, NULL, 1) != 0) {
+               return -1;
+       }
+
+       return 0;
+}
+
 static void
 nfs3_lseek_1_cb(struct rpc_context *rpc, int status, void *command_data,
                 void *private_data)
@@ -4169,6 +4287,12 @@
 {
         struct nfs_cb_data *data;
 
+        if (!nfsfh->is_dirty) {
+                nfs_free_nfsfh(nfsfh);
+                cb(0, nfs, NULL, private_data);
+                return 0;
+        }
+
         data = malloc(sizeof(struct nfs_cb_data));
         if (data == NULL) {
                 nfs_set_error(nfs, "out of memory: failed to allocate "
@@ -4341,6 +4465,7 @@
 {
        struct nfs_cb_data *data;
 
+        nfsfh->is_dirty = 1;
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
                nfs_set_error(nfs, "out of memory: failed to allocate "
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/lib/nfs_v4.c 
new/libnfs-libnfs-4.0.0/lib/nfs_v4.c
--- old/libnfs-libnfs-3.0.0/lib/nfs_v4.c        2018-06-24 00:53:52.000000000 
+0200
+++ new/libnfs-libnfs-4.0.0/lib/nfs_v4.c        2019-02-12 22:38:04.000000000 
+0100
@@ -141,7 +141,8 @@
 /* Do not follow symlinks for the final component on a lookup.
  * I.e. stat vs lstat
  */
-#define LOOKUP_FLAG_NO_FOLLOW 0x0001
+#define LOOKUP_FLAG_NO_FOLLOW    0x0001
+#define LOOKUP_FLAG_IS_STATVFS64 0x0002
         int flags;
 
         /* Internal callback for open-with-continuation use */
@@ -1964,6 +1965,37 @@
 }
 
 static void
+nfs4_open_chmod_cb(struct rpc_context *rpc, int status, void *command_data,
+                      void *private_data)
+{
+        struct nfs4_cb_data *data = private_data;
+        struct nfs_context *nfs = data->nfs;
+        struct nfsfh *fh = data->filler.blob0.val;
+        COMPOUND4res *res = command_data;
+        COMPOUND4args args;
+        nfs_argop4 op[2];
+        int i;
+
+        if (check_nfs4_error(nfs, status, data, res, "OPEN")) {
+                return;
+        }
+
+        i = nfs4_op_putfh(nfs, op, fh);
+        i += nfs4_op_chmod(nfs, &op[i], fh, data->filler.blob3.val);
+
+        memset(&args, 0, sizeof(args));
+        args.argarray.argarray_len = i;
+        args.argarray.argarray_val = op;
+
+        if (rpc_nfs4_compound_async(nfs->rpc, nfs4_open_setattr_cb, &args,
+                                    data) != 0) {
+                data->cb(-ENOMEM, nfs, nfs_get_error(nfs), data->private_data);
+                free_nfs4_cb_data(data);
+                return;
+        }
+}
+
+static void
 nfs4_open_confirm_cb(struct rpc_context *rpc, int status, void *command_data,
                      void *private_data)
 {
@@ -2118,6 +2150,25 @@
         free_nfs4_cb_data(data);
 }
 
+static void
+nfs4_init_random_verifier(char *verifier)
+{
+        static uint64_t seed = 0, v;
+        int i;
+
+        if (seed == 0) {
+                seed = ~rpc_current_time() << 32 | getpid();
+        } else {
+                seed *= 1337;
+        }
+
+        v = seed;
+        for (i = 0; i < NFS4_VERIFIER_SIZE; i++) {
+                verifier[i] = v & 0xff;
+                v >>= 8;
+        }
+}
+
 /* filler.flags are the open flags
  * filler.data is the object name
  */
@@ -2127,6 +2178,7 @@
         struct nfs_context *nfs = data->nfs;
         OPEN4args *oargs;
         uint32_t access_mask = 0;
+        verifier4 verifier;
         int i;
 
         if (data->filler.flags & O_WRONLY) {
@@ -2135,7 +2187,7 @@
         if (data->filler.flags & O_RDWR) {
                 access_mask |= ACCESS4_READ|ACCESS4_MODIFY;
         }
-        if (!(data->filler.flags & (O_WRONLY|O_RDWR))) {
+        if (!(data->filler.flags & O_WRONLY)) {
                 access_mask |= ACCESS4_READ;
         }
         
@@ -2166,12 +2218,20 @@
                 fa = &ch->createhow4_u.createattrs;
 
                 oargs->openhow.opentype = OPEN4_CREATE;
-                ch->mode = UNCHECKED4;
-                fa->attrmask.bitmap4_len = data->filler.blob1.len;
-                fa->attrmask.bitmap4_val = data->filler.blob1.val;
+                if (data->filler.flags|O_EXCL) {
+                        ch->mode = EXCLUSIVE4;
 
-                fa->attr_vals.attrlist4_len = data->filler.blob2.len;
-                fa->attr_vals.attrlist4_val = data->filler.blob2.val;
+                        nfs4_init_random_verifier(&verifier[0]);
+                        memcpy(ch->createhow4_u.createverf, verifier,
+                               sizeof(verifier4));
+                } else {
+                        ch->mode = UNCHECKED4;
+                        fa->attrmask.bitmap4_len = data->filler.blob1.len;
+                        fa->attrmask.bitmap4_val = data->filler.blob1.val;
+
+                        fa->attr_vals.attrlist4_len = data->filler.blob2.len;
+                        fa->attr_vals.attrlist4_val = data->filler.blob2.val;
+                }
         } else {
                 oargs->openhow.opentype = OPEN4_NOCREATE;
         }
@@ -2373,6 +2433,7 @@
                 int mode, nfs_cb cb, void *private_data)
 {
         struct nfs4_cb_data *data;
+        uint32_t m;
 
         data = init_cb_data_split_path(nfs, path);
         if (data == NULL) {
@@ -2386,6 +2447,10 @@
         if (flags & O_TRUNC && !(flags & (O_RDWR|O_WRONLY))) {
                 flags &= ~O_TRUNC;
         }
+        /* Successful O_EXCL means the file is 0 size already. */
+        if (flags & O_EXCL) {
+                flags &= ~O_TRUNC;
+        }
 
         if (flags & O_TRUNC) {
                 data->open_cb = nfs4_open_truncate_cb;
@@ -2400,6 +2465,20 @@
 
                 memset(data->filler.blob3.val, 0, 12);
         }
+        if (flags & O_EXCL) {
+                data->open_cb = nfs4_open_chmod_cb;
+
+                data->filler.blob3.val = malloc(4);
+                if (data->filler.blob3.val == NULL) {
+                        nfs_set_error(nfs, "Out of memory");
+                        free_nfs4_cb_data(data);
+                        return -1;
+                }
+                data->filler.blob3.free = free;
+
+                m = htonl(mode);
+                memcpy(data->filler.blob3.val, &m, sizeof(uint32_t));
+        }
 
         return nfs4_open_async_internal(nfs, data, flags, mode);
 }
@@ -3536,7 +3615,7 @@
         struct nfs4_cb_data *data;
        struct nfsdir *nfsdir;
 
-        data = init_cb_data_split_path(nfs, path);
+        data = init_cb_data_full_path(nfs, path);
         if (data == NULL) {
                 return -1;
         }
@@ -4311,6 +4390,83 @@
         return 0;
 }
 
+static int
+nfs_parse_statvfs64(struct nfs_context *nfs, struct nfs4_cb_data *data,
+                    struct nfs_statvfs_64 *svfs64, const char *buf, int len)
+{
+        uint64_t u64;
+        uint32_t u32;
+
+       svfs64->f_bsize   = NFS_BLKSIZE;
+       svfs64->f_frsize  = NFS_BLKSIZE;
+       svfs64->f_flag    = 0;
+
+        /* FSID
+         * NFSv4 FSID is 2*64 bit but statvfs fsid is just an
+         * unsigmed long. Mix the 2*64 bits and hope for the best.
+         */
+        CHECK_GETATTR_BUF_SPACE(len, 16);
+        memcpy(&u64, buf, 8);
+       svfs64->f_fsid = nfs_ntoh64(u64);
+        buf += 8;
+        len -= 8;
+        memcpy(&u64, buf, 8);
+       svfs64->f_fsid |= nfs_ntoh64(u64);
+        buf += 8;
+        len -= 8;
+
+        /* Files Avail */
+        CHECK_GETATTR_BUF_SPACE(len, 8);
+        memcpy(&u64, buf, 8);
+       svfs64->f_favail = nfs_ntoh64(u64);
+        buf += 8;
+        len -= 8;
+
+        /* Files Free */
+        CHECK_GETATTR_BUF_SPACE(len, 8);
+        memcpy(&u64, buf, 8);
+       svfs64->f_ffree = nfs_ntoh64(u64);
+        buf += 8;
+        len -= 8;
+
+        /* Files Total */
+        CHECK_GETATTR_BUF_SPACE(len, 8);
+        memcpy(&u64, buf, 8);
+       svfs64->f_files = nfs_ntoh64(u64);
+        buf += 8;
+        len -= 8;
+
+        /* Max Name */
+        CHECK_GETATTR_BUF_SPACE(len, 4);
+        memcpy(&u32, buf, 4);
+       svfs64->f_namemax = ntohl(u32);
+        buf += 4;
+        len -= 4;
+
+        /* Space Avail */
+        CHECK_GETATTR_BUF_SPACE(len, 8);
+        memcpy(&u64, buf, 8);
+       svfs64->f_bavail = nfs_ntoh64(u64) / svfs64->f_frsize;
+        buf += 8;
+        len -= 8;
+
+        /* Space Free */
+        CHECK_GETATTR_BUF_SPACE(len, 8);
+        memcpy(&u64, buf, 8);
+       svfs64->f_bfree = nfs_ntoh64(u64) / svfs64->f_frsize;
+        buf += 8;
+        len -= 8;
+
+        /* Space Total */
+        CHECK_GETATTR_BUF_SPACE(len, 8);
+        memcpy(&u64, buf, 8);
+       svfs64->f_blocks = nfs_ntoh64(u64) / svfs64->f_frsize;
+        buf += 8;
+        len -= 8;
+
+        return 0;
+}
+
 static void
 nfs4_statvfs_cb(struct rpc_context *rpc, int status, void *command_data,
               void *private_data)
@@ -4320,6 +4476,7 @@
         COMPOUND4res *res = command_data;
         GETATTR4resok *garesok;
        struct statvfs svfs;
+       struct nfs_statvfs_64 svfs64;
         int i;
 
         assert(rpc->magic == RPC_CONTEXT_MAGIC);
@@ -4329,27 +4486,44 @@
         }
 
         memset(&svfs, 0, sizeof(svfs));
+        memset(&svfs64, 0, sizeof(svfs64));
 
         if ((i = nfs4_find_op(nfs, data, res, OP_GETATTR, "GETATTR")) < 0) {
                 return;
         }
         garesok = 
&res->resarray.resarray_val[i].nfs_resop4_u.opgetattr.GETATTR4res_u.resok4;
 
-        if (nfs_parse_statvfs(nfs, data, &svfs,
+        if (data->flags & LOOKUP_FLAG_IS_STATVFS64) {
+                /* statvfs64 */
+                if (nfs_parse_statvfs64(nfs, data, &svfs64,
                               garesok->obj_attributes.attr_vals.attrlist4_val,
                               garesok->obj_attributes.attr_vals.attrlist4_len) 
< 0) {
-                data->cb(-EINVAL, nfs, nfs_get_error(nfs), data->private_data);
-                free_nfs4_cb_data(data);
-                return;
+                        data->cb(-EINVAL, nfs, nfs_get_error(nfs), 
data->private_data);
+                        free_nfs4_cb_data(data);
+                        return;
+                }
+
+                data->cb(0, nfs, &svfs64, data->private_data);
+        } else {
+                /* statvfs */
+                if (nfs_parse_statvfs(nfs, data, &svfs,
+                              garesok->obj_attributes.attr_vals.attrlist4_val,
+                              garesok->obj_attributes.attr_vals.attrlist4_len) 
< 0) {
+                        data->cb(-EINVAL, nfs, nfs_get_error(nfs), 
data->private_data);
+                        free_nfs4_cb_data(data);
+                        return;
+                }
+
+                data->cb(0, nfs, &svfs, data->private_data);
         }
 
-       data->cb(0, nfs, &svfs, data->private_data);
        free_nfs4_cb_data(data);
 }
 
-int
-nfs4_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
-                   void *private_data)
+static int
+nfs4_statvfs_async_internal(struct nfs_context *nfs, const char *path,
+                            int is_statvfs64,
+                            nfs_cb cb, void *private_data)
 {
         struct nfs4_cb_data *data;
         COMPOUND4args args;
@@ -4367,6 +4541,9 @@
         data->nfs          = nfs;
         data->cb           = cb;
         data->private_data = private_data;
+        if (is_statvfs64) {
+                data->flags |= LOOKUP_FLAG_IS_STATVFS64;
+        }
 
         fh.fh.len = nfs->rootfh.len;
         fh.fh.val = nfs->rootfh.val;
@@ -4387,6 +4564,22 @@
         return 0;
 }
 
+int
+nfs4_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
+                   void *private_data)
+{
+        return nfs4_statvfs_async_internal(nfs, path, 0,
+                                           cb, private_data);
+}
+
+int
+nfs4_statvfs64_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
+                     void *private_data)
+{
+        return nfs4_statvfs_async_internal(nfs, path, 1,
+                                           cb, private_data);
+}
+
 static void
 nfs4_chmod_open_cb(struct rpc_context *rpc, int status, void *command_data,
                    void *private_data)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/lib/socket.c 
new/libnfs-libnfs-4.0.0/lib/socket.c
--- old/libnfs-libnfs-3.0.0/lib/socket.c        2018-06-24 00:53:52.000000000 
+0200
+++ new/libnfs-libnfs-4.0.0/lib/socket.c        2019-02-12 22:38:04.000000000 
+0100
@@ -86,6 +86,12 @@
 #include "win32_errnowrapper.h"
 #endif
 
+#ifndef MSG_NOSIGNAL
+#if (defined(__APPLE__) && defined(__MACH__))
+#define MSG_NOSIGNAL 0
+#endif
+#endif
+
 static int
 rpc_reconnect_requeue(struct rpc_context *rpc);
 
@@ -93,13 +99,15 @@
 create_socket(int domain, int type, int protocol)
 {
 #ifdef SOCK_CLOEXEC
-       /* Linux-specific extension (since 2.6.27): set the
+#ifdef __linux__
+    /* Linux-specific extension (since 2.6.27): set the
           close-on-exec flag on all sockets to avoid leaking file
           descriptors to child processes */
        int fd = socket(domain, type|SOCK_CLOEXEC, protocol);
        if (fd >= 0 || errno != EINVAL)
                return fd;
 #endif
+#endif
 
        return socket(domain, type, protocol);
 }
@@ -589,11 +597,18 @@
        }
 
        if (rpc->old_fd) {
+#if !defined(WIN32)
                if (dup2(rpc->fd, rpc->old_fd) == -1) {
                        return -1;
                }
                close(rpc->fd);
                rpc->fd = rpc->old_fd;
+#else
+               /* On Windows dup2 does not work on sockets
+                * instead just close the old socket */
+               close(rpc->old_fd);
+               rpc->old_fd = 0;
+#endif
        }
 
        /* Some systems allow you to set capabilities on an executable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/packaging/RPM/libnfs.spec.in 
new/libnfs-libnfs-4.0.0/packaging/RPM/libnfs.spec.in
--- old/libnfs-libnfs-3.0.0/packaging/RPM/libnfs.spec.in        2018-06-24 
00:53:52.000000000 +0200
+++ new/libnfs-libnfs-4.0.0/packaging/RPM/libnfs.spec.in        2019-02-12 
22:38:04.000000000 +0100
@@ -113,6 +113,17 @@
 %{_mandir}/man1/nfs-ls.1.gz
 
 %changelog
+* Wed Feb 13 2019 : Version 4.0.0
+- Fix the versioning in makerpms.sh
+- Fix some compile issues in the test programs.
+- NFSv3: skip commit on close if the file has not been written to.
+- Add nfs_umount() to NFSv3
+- Add nfs_statvfs64()
+- Fix invalid shift of pid_t when generating rpc->xid
+- Compile fixes for Mac OSX
+- Fix for dup2() on Windows
+- NFSv4 fix for directory handling
+- Improvements to configure/bulding
 * Sun Jun 24 2018 : Version 3.0.0
  - NFSv4 support.
  - lockf() support (NFSv4 only).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/packaging/RPM/makerpms.sh 
new/libnfs-libnfs-4.0.0/packaging/RPM/makerpms.sh
--- old/libnfs-libnfs-3.0.0/packaging/RPM/makerpms.sh   2018-06-24 
00:53:52.000000000 +0200
+++ new/libnfs-libnfs-4.0.0/packaging/RPM/makerpms.sh   2019-02-12 
22:38:04.000000000 +0100
@@ -50,7 +50,7 @@
 #
 # If we're not directly on a tag, this is a devel release; we append
 # .0.<patchnum>.<checksum>.devel to the release.
-TAG=`git describe`
+TAG=`git describe --tags`
 case "$TAG" in
     libnfs-*)
        TAG=${TAG##libnfs-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/tests/CMakeLists.txt 
new/libnfs-libnfs-4.0.0/tests/CMakeLists.txt
--- old/libnfs-libnfs-3.0.0/tests/CMakeLists.txt        2018-06-24 
00:53:52.000000000 +0200
+++ new/libnfs-libnfs-4.0.0/tests/CMakeLists.txt        2019-02-12 
22:38:04.000000000 +0100
@@ -19,6 +19,7 @@
             prog_mount
             prog_open_read
             prog_open_write
+            prog_opendir
             prog_rename
             prog_rmdir
             prog_stat
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/tests/Makefile.am 
new/libnfs-libnfs-4.0.0/tests/Makefile.am
--- old/libnfs-libnfs-3.0.0/tests/Makefile.am   2018-06-24 00:53:52.000000000 
+0200
+++ new/libnfs-libnfs-4.0.0/tests/Makefile.am   2019-02-12 22:38:04.000000000 
+0100
@@ -7,7 +7,7 @@
 noinst_PROGRAMS = prog_access prog_access2 prog_chmod prog_chown prog_create \
        prog_fchmod prog_fchown prog_fstat prog_ftruncate prog_lchmod \
        prog_lchown prog_link prog_lseek prog_lstat prog_mkdir \
-       prog_mknod prog_mount prog_open_read prog_open_write \
+       prog_mknod prog_mount prog_opendir prog_open_read prog_open_write \
        prog_rename prog_rmdir prog_stat prog_statvfs prog_symlink \
        prog_timeout prog_truncate prog_unlink prog_utimes
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/tests/prog_open_read.c 
new/libnfs-libnfs-4.0.0/tests/prog_open_read.c
--- old/libnfs-libnfs-3.0.0/tests/prog_open_read.c      2018-06-24 
00:53:52.000000000 +0200
+++ new/libnfs-libnfs-4.0.0/tests/prog_open_read.c      2019-02-12 
22:38:04.000000000 +0100
@@ -43,7 +43,7 @@
        struct nfs_context *nfs = NULL;
        struct nfs_url *url = NULL;
        int ret = 0;
-        int flags = 0, count;
+        int flags = 0, count, res, pos;
         struct nfsfh *fh;
         char buf[1024];
 
@@ -111,7 +111,17 @@
                goto finished;
        }
 
-        write(1, buf, count);
+        pos = 0;
+        while (count) {
+                res = write(1, &buf[pos], count);
+                if (res < 0) {
+                        fprintf(stderr, "write() failed\n");
+                        ret = 1;
+                        goto finished;
+                }
+                count -= res;
+                pos += res;
+        }
 
        if (nfs_close(nfs, fh)) {
                fprintf(stderr, "Failed to close(): %s\n",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/tests/prog_opendir.c 
new/libnfs-libnfs-4.0.0/tests/prog_opendir.c
--- old/libnfs-libnfs-3.0.0/tests/prog_opendir.c        1970-01-01 
01:00:00.000000000 +0100
+++ new/libnfs-libnfs-4.0.0/tests/prog_opendir.c        2019-02-12 
22:38:04.000000000 +0100
@@ -0,0 +1,99 @@
+/* -*-  mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil;  -*- */
+/* 
+   Copyright (C) by Ronnie Sahlberg <[email protected]> 2017
+   
+   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/>.
+*/
+
+#define _FILE_OFFSET_BITS 64
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "libnfs.h"
+
+void usage(void)
+{
+       fprintf(stderr, "Usage: prog_opendir <url> <cwd> <path>\n");
+       exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nfs_context *nfs = NULL;
+       struct nfs_url *url = NULL;
+       struct nfsdirent *nfsdirent;
+       struct nfsdir *nfsdir;
+       int ret = 0;
+
+       if (argc != 4) {
+               usage();
+       }
+
+       nfs = nfs_init_context();
+       if (nfs == NULL) {
+               printf("failed to init context\n");
+               exit(1);
+       }
+
+       nfs_set_timeout(nfs, 300);
+
+       url = nfs_parse_url_full(nfs, argv[1]);
+       if (url == NULL) {
+               fprintf(stderr, "%s\n", nfs_get_error(nfs));
+               exit(1);
+       }
+
+       if (nfs_mount(nfs, url->server, url->path) != 0) {
+               fprintf(stderr, "Failed to mount nfs share : %s\n",
+                       nfs_get_error(nfs));
+               ret = 1;
+               goto finished;
+       }
+
+       if (nfs_chdir(nfs, argv[2]) != 0) {
+               fprintf(stderr, "Failed to chdir to \"%s\" : %s\n",
+                       argv[2], nfs_get_error(nfs));
+               ret = 1;
+               goto finished;
+       }
+
+       if (nfs_opendir(nfs, argv[3], &nfsdir)) {
+               fprintf(stderr, "Failed to opendir() : %s\n",
+                       nfs_get_error(nfs));
+               ret = 1;
+               goto finished;
+       }
+
+       while((nfsdirent = nfs_readdir(nfs, nfsdir)) != NULL) {
+               if (!strcmp(nfsdirent->name, ".") || !strcmp(nfsdirent->name, 
"..")) {
+                       continue;
+               }
+               printf("%s\n", nfsdirent->name);
+        }
+       nfs_closedir(nfs, nfsdir);
+
+finished:
+       nfs_destroy_url(url);
+       nfs_destroy_context(nfs);
+
+       return ret;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/tests/prog_statvfs.c 
new/libnfs-libnfs-4.0.0/tests/prog_statvfs.c
--- old/libnfs-libnfs-3.0.0/tests/prog_statvfs.c        2018-06-24 
00:53:52.000000000 +0200
+++ new/libnfs-libnfs-4.0.0/tests/prog_statvfs.c        2019-02-12 
22:38:04.000000000 +0100
@@ -40,7 +40,7 @@
 {
        struct nfs_context *nfs = NULL;
        struct nfs_url *url = NULL;
-       struct statvfs svfs;
+       struct nfs_statvfs_64 svfs;
        int ret = 0;
 
        if (argc != 4) {
@@ -75,23 +75,23 @@
                goto finished;
        }
 
-       if (nfs_statvfs(nfs, argv[3], &svfs)) {
-               fprintf(stderr, "statvfs failed : %s\n",
+       if (nfs_statvfs64(nfs, argv[3], &svfs)) {
+               fprintf(stderr, "statvfs64 failed : %s\n",
                        nfs_get_error(nfs));
                ret = 1;
                goto finished;
        }
 
-       printf("bsize:%lu\n", svfs.f_bsize);
-       printf("frsize:%lu\n", svfs.f_frsize);
-       printf("blocks:%lu\n", svfs.f_blocks);
-       printf("bfree:%lu\n", svfs.f_bfree);
-       printf("bavail:%lu\n", svfs.f_bavail);
-       printf("files:%lu\n", svfs.f_files);
-       printf("ffree:%lu\n", svfs.f_ffree);
-       printf("favail:%lu\n", svfs.f_favail);
-       printf("fsid:%lu\n", svfs.f_fsid);
-       printf("namemax:%lu\n", svfs.f_namemax);
+       printf("bsize:%" PRIu64 "\n", svfs.f_bsize);
+       printf("frsize:%" PRIu64 "\n", svfs.f_frsize);
+       printf("blocks:%" PRIu64 "\n", svfs.f_blocks);
+       printf("bfree:%" PRIu64 "\n", svfs.f_bfree);
+       printf("bavail:%" PRIu64 "\n", svfs.f_bavail);
+       printf("files:%" PRIu64 "\n", svfs.f_files);
+       printf("ffree:%" PRIu64 "\n", svfs.f_ffree);
+       printf("favail:%" PRIu64 "\n", svfs.f_favail);
+       printf("fsid:%" PRIu64 "\n", svfs.f_fsid);
+       printf("namemax:%" PRIu64 "\n", svfs.f_namemax);
 
 finished:
        nfs_destroy_url(url);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/tests/test_0460_opendir.sh 
new/libnfs-libnfs-4.0.0/tests/test_0460_opendir.sh
--- old/libnfs-libnfs-3.0.0/tests/test_0460_opendir.sh  1970-01-01 
01:00:00.000000000 +0100
+++ new/libnfs-libnfs-4.0.0/tests/test_0460_opendir.sh  2019-02-12 
22:38:04.000000000 +0100
@@ -0,0 +1,58 @@
+#!/bin/sh
+#
+# NFS servers generally want us to be root in order to create device nodes.
+# We can lie and impersonate root by setting uid=0 in the URL.
+
+. ./functions.sh
+
+echo "NFSv${VERS} Basic opendir test."
+
+start_share
+
+mkdir "${TESTDIR}/subdir"
+mkdir "${TESTDIR}/subdir/subdir2"
+touch "${TESTDIR}/subdir/subdir2/file"
+
+echo -n "Open '.' in the root directory (1)... "
+./prog_opendir "${TESTURL}/?uid=0&version=${VERS}" "." "." > 
"${TESTDIR}/output" || failure
+success
+
+echo -n "Check the directory listing ... "
+grep "^subdir$" "${TESTDIR}/output" >/dev/null || failure
+success
+
+echo -n "Open a subdir in the root directory (2)... "
+./prog_opendir "${TESTURL}/?uid=0&version=${VERS}" "." "subdir" > 
"${TESTDIR}/output" || failure
+success
+
+echo -n "Check the directory listing ... "
+grep "^subdir2$" "${TESTDIR}/output" >/dev/null || failure
+success
+
+echo -n "Open '.' in a subdir (3)... "
+./prog_opendir "${TESTURL}/?uid=0&version=${VERS}" "subdir" "." > 
"${TESTDIR}/output" || failure
+success
+
+echo -n "Check the directory listing ... "
+grep "^subdir2$" "${TESTDIR}/output" >/dev/null || failure
+success
+
+echo -n "Open 'subdir2' in a subdir (4)... "
+./prog_opendir "${TESTURL}/?uid=0&version=${VERS}" "subdir" "subdir2" > 
"${TESTDIR}/output" || failure
+success
+
+echo -n "Check the directory listing ... "
+grep "^file$" "${TESTDIR}/output" >/dev/null || failure
+success
+
+echo -n "Open '..' in a subdir (5)... "
+./prog_opendir "${TESTURL}/?uid=0&version=${VERS}" "subdir/subdir2" ".." > 
"${TESTDIR}/output" || failure
+success
+
+echo -n "Check the directory listing ... "
+grep "^subdir2$" "${TESTDIR}/output" >/dev/null || failure
+success
+
+stop_share
+
+exit 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnfs-libnfs-3.0.0/utils/nfs-cp.c 
new/libnfs-libnfs-4.0.0/utils/nfs-cp.c
--- old/libnfs-libnfs-3.0.0/utils/nfs-cp.c      2018-06-24 00:53:52.000000000 
+0200
+++ new/libnfs-libnfs-4.0.0/utils/nfs-cp.c      2019-02-12 22:38:04.000000000 
+0100
@@ -197,8 +197,9 @@
                        return NULL;
                }
        } else {
-               if (nfs_creat(file_context->nfs, file_context->url->file, 0660,
-                               &file_context->nfsfh) != 0) {
+               if (nfs_create(file_context->nfs, file_context->url->file,
+                              flags, 0660,
+                              &file_context->nfsfh) != 0) {
                        fprintf(stderr, "Failed to creat file %s: %s\n",
                                       file_context->url->file,
                                       nfs_get_error(file_context->nfs));
@@ -241,7 +242,7 @@
                return 10;
        }
 
-       dst = open_file(argv[2], O_WRONLY|O_CREAT|O_TRUNC);
+       dst = open_file(argv[2], O_WRONLY|O_CREAT|O_EXCL|O_TRUNC);
        if (dst == NULL) {
                fprintf(stderr, "Failed to open %s\n", argv[2]);
                free_file_context(src);


Reply via email to