--- /dev/null
+Libnfs components fall under two separate licences
+
+
+The lib 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 src and examples directories
+================================
+The utility and example applications using this library, i.e. the src and the
+examples directories, are licenced under 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.
+
+
+To avoid any confusion, every source file contains a licence boilerplate.
+
--- /dev/null
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+libdir = @libdir@
+bindir = @bindir@
+LIBS=@LIBS@
+
+INSTALLCMD = @install@ -c
+
+CC=gcc
+CFLAGS=-g -O0 -fPIC -Wall -W -I. -Iinclude -Imount -Infs -Iportmap "-D_U_=__attribute__((unused))" -D_FILE_OFFSET_BITS=64
+
+LIBNFS_A=lib/libnfs.a
+LIBNFS_SO_NAME=libnfs.so.1
+VERSION=1.0.0
+LIBNFS_SO=lib/libnfs.so.$(VERSION)
+
+LIB_OBJS = lib/pdu.o lib/init.o lib/socket.o \
+lib/libnfs.o lib/libnfs-sync.o
+
+LIBNFS_OBJS = \
+mount/libnfs-raw-mount.o mount/mount.o \
+portmap/libnfs-raw-portmap.o portmap/portmap.o \
+nfs/libnfs-raw-nfs.o nfs/nfs.o
+
+EXAMPLES=bin/nfsclient-raw bin/nfsclient-async bin/nfsclient-sync
+
+all: $(LIBNFS_SO) $(EXAMPLES)
+
+bin/nfsclient-async: examples/nfsclient-async.c $(LIBNFS_A)
+ mkdir -p bin
+ $(CC) $(CFLAGS) -o $@ examples/nfsclient-async.c $(LIBNFS_A) $(LIBS)
+
+bin/nfsclient-sync: examples/nfsclient-sync.c $(LIBNFS_A)
+ mkdir -p bin
+ $(CC) $(CFLAGS) -o $@ examples/nfsclient-sync.c $(LIBNFS_A) $(LIBS)
+
+bin/nfsclient-raw: examples/nfsclient-raw.c $(LIBNFS_A)
+ mkdir -p bin
+ $(CC) $(CFLAGS) -o $@ examples/nfsclient-raw.c $(LIBNFS_A) $(LIBS)
+
+$(LIBNFS_A): $(LIBNFS_OBJS) $(LIB_OBJS)
+ @echo Creating library $@
+ ar r $(LIBNFS_A) $(LIBNFS_OBJS) $(LIB_OBJS)
+ ranlib $(LIBNFS_A)
+
+$(LIBNFS_SO): $(LIBNFS_OBJS) $(LIB_OBJS)
+ @echo Creating shared library $@
+ $(CC) -shared -Wl,-soname=$(LIBNFS_SO_NAME) -o $@ $(LIBNFS_OBJS) $(LIB_OBJS)
+
+portmap/libnfs-raw-portmap.h: portmap/portmap.x
+ @echo Generating $@
+ rpcgen -h portmap/portmap.x > portmap/libnfs-raw-portmap.h
+
+portmap/libnfs-raw-portmap.c: portmap/portmap.x
+ @echo Generating $@
+ rpcgen -c portmap/portmap.x | sed -e "s/#include \"portmap\/portmap.h\"/#include \"libnfs-raw-portmap.h\"/" > portmap/libnfs-raw-portmap.c
+
+portmap/libnfs-raw-portmap.o: portmap/libnfs-raw-portmap.c portmap/libnfs-raw-portmap.h
+ @echo Compiling $@
+ $(CC) $(CFLAGS) -c portmap/libnfs-raw-portmap.c -o $@
+
+mount/libnfs-raw-mount.h: mount/mount.x
+ @echo Generating $@
+ rpcgen -h mount/mount.x > mount/libnfs-raw-mount.h
+
+mount/libnfs-raw-mount.c: mount/mount.x
+ @echo Generating $@
+ rpcgen -c mount/mount.x | sed -e "s/#include \"mount\/mount.h\"/#include \"libnfs-raw-mount.h\"/" > mount/libnfs-raw-mount.c
+
+mount/libnfs-raw-mount.o: mount/libnfs-raw-mount.c mount/libnfs-raw-mount.h
+ @echo Compiling $@
+ $(CC) $(CFLAGS) -c mount/libnfs-raw-mount.c -o $@
+
+nfs/libnfs-raw-nfs.h: nfs/nfs.x
+ @echo Generating $@
+ rpcgen -h nfs/nfs.x > nfs/libnfs-raw-nfs.h
+
+nfs/libnfs-raw-nfs.c: nfs/nfs.x
+ @echo Generating $@
+ rpcgen -c nfs/nfs.x | sed -e "s/#include \"nfs\/nfs.h\"/#include \"libnfs-raw-nfs.h\"/" > nfs/libnfs-raw-nfs.c
+
+nfs/libnfs-raw-nfs.o: nfs/libnfs-raw-nfs.c nfs/libnfs-raw-nfs.h
+ @echo Compiling $@
+ $(CC) $(CFLAGS) -c nfs/libnfs-raw-nfs.c -o $@
+
+install: $(LIBNFS_A) $(LIBNFS_SO)
+ifeq ("$(LIBDIR)x","x")
+ $(INSTALLCMD) -m 755 $(LIBNFS_SO) $(libdir)
+ $(INSTALLCMD) -m 755 $(LIBNFS_A) $(libdir)
+ @ldconfig@
+else
+ $(INSTALLCMD) -m 755 $(LIBISCSI_SO) $(LIBDIR)
+ $(INSTALLCMD) -m 755 $(LIBNFS_A) $(LIBDIR)
+endif
+ mkdir -p $(DESTDIR)/usr/include/nfsc
+ $(INSTALLCMD) -m 644 include/libnfs.h $(DESTDIR)/usr/include/nfsc
+ $(INSTALLCMD) -m 644 include/libnfs-private.h $(DESTDIR)/usr/include/nfsc
+ $(INSTALLCMD) -m 644 mount/libnfs-raw-mount.h $(DESTDIR)/usr/include/nfsc
+ $(INSTALLCMD) -m 644 nfs/libnfs-raw-nfs.h $(DESTDIR)/usr/include/nfsc
+ $(INSTALLCMD) -m 644 portmap/libnfs-raw-portmap.h $(DESTDIR)/usr/include/nfsc
+
+distclean: clean
+ rm -f config.h config.log config.status configure Makefile
+
+clean:
+ rm -f bin/* lib/*.o lib/*.a $(LIBNFS_SO)
+ rm -f mount/*.o mount/libnfs-raw-mount.h mount/libnfs-raw-mount.c
+ rm -f nfs/*.o nfs/libnfs-raw-nfs.h nfs/libnfs-raw-nfs.c
+ rm -f portmap/*.o portmap/libnfs-raw-portmap.h portmap/libnfs-raw-portmap.c
+ rm -f nfsclient-raw nfsclient-async nfsclient-sync
+
--- /dev/null
+LIBNFS is a client library for accessing NFS shares over a network.
+
+LIBNFS offers three different APIs, for different use :
+1, RAW : A fully async low level rpc library for nfs protocols
+This API is described in include/libnfs-raw.h
+it offers a fully async interface to raw XDR encoded blobs.
+This api provides very flexible and precice control of the RPC issued.
+
+examples/nfsclient-raw.c provides examples on how to use the raw API
+
+2, NFS ASYNC : A fully asynchronous library for high level vfs functions
+This API is described by the *_async() fucntions in include/libnfs.h.
+This API provides a fully async access to posix vfs like functions such as
+stat(), read(), ...
+
+examples/nfsclient-async.c provides examples on how to use this API
+
+
+3, NFS SYNC : A synchronous library for high level vfs functions
+This API is described by the *_sync() fucntions in include/libnfs.h.
+This API provides access to posix vfs like functions such as
+stat(), read(), ...
+
+examples/nfsclient-sync.c provides examples on how to use this API
--- /dev/null
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f configure config.h.in libnfs.pc
+
+IPATHS="-I ./include -I ../include -I ./include -I ./mount -I ./nfs -I ./portmap"
+
+autoheader $IPATHS || exit 1
+autoconf $IPATHS || exit 1
+
+rm -rf autom4te.cache
+
+echo "Now run ./configure and then make."
+exit 0
+
--- /dev/null
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Whether the sockaddr_in struct has a sin_len property */
+#undef HAVE_SOCK_SIN_LEN
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
--- /dev/null
+AC_PREREQ(2.50)
+AC_INIT(libnfs, m4_esyscmd([grep 'Version:' ./packaging/RPM/libnfs.spec.in 2>/dev/null | head -1 | sed -e 's/[ \t]*Version:[ \t]*\([^ \t]*\)[ \t]*.*/\1/' | tr -d '\n']))
+AC_CONFIG_SRCDIR([lib/init.c])
+
+if test "${libdir}" = '${exec_prefix}/lib'; then
+ case `uname -m` in
+ x86_64|ppc64|powerpc64)
+ libdir='${exec_prefix}/lib64'
+ ;;
+ *)
+ libdir='${exec_prefix}/lib'
+ ;;
+ esac
+fi
+
+is_solaris="no"
+install="/usr/bin/install"
+ldconfig="ldconfig"
+
+case `uname` in
+ Linux*)
+ ;;
+ AIX*)
+ ;;
+ SunOS)
+ is_solaris="yes"
+ install="ginstall"
+ ldconfig="echo no ldconfig on solaris"
+ LIBS="$LIBS -lsocket -lnsl"
+ ;;
+ *)
+ ;;
+esac
+
+if test "$ac_cv_prog_gcc" = yes; then
+ CFLAGS="$CFLAGS -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings"
+fi
+
+LOGDIR='${localstatedir}/log'
+AC_ARG_WITH([logdir],
+ [ --with-logdir=DIR path to log directory [[LOCALSTATEDIR/log]]],
+ LOGDIR=$withval)
+if test ! -z "$LOGDIR"; then
+ if test "$LOGDIR" = "yes" -o "$LOGDIR" = "no"; then
+ AC_MSG_ERROR([--with-logdir must specify a path])
+ fi
+fi
+AC_SUBST(LOGDIR)
+
+AC_CONFIG_HEADER(config.h)
+
+EXTRA_OBJ=""
+
+#AC_CHECK_HEADERS(sched.h)
+#AC_CHECK_FUNCS(mlockall)
+
+AC_CACHE_CHECK([for sin_len in sock],libnfs_cv_HAVE_SOCK_SIN_LEN,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>],
+[struct sockaddr_in sock; sock.sin_len = sizeof(sock);],
+libnfs_cv_HAVE_SOCK_SIN_LEN=yes,libnfs_cv_HAVE_SOCK_SIN_LEN=no)])
+if test x"$libnfs_cv_HAVE_SOCK_SIN_LEN" = x"yes"; then
+ AC_DEFINE(HAVE_SOCK_SIN_LEN,1,[Whether the sockaddr_in struct has a sin_len property])
+fi
+
+AC_MSG_CHECKING(whether libpopt is available)
+ac_save_CFLAGS="$CFLAGS"
+ac_save_LIBS="$LIBS"
+CFLAGS="$CFLAGS $GLIB_CFLAGS"
+LIBS="$GLIB_LIBS $LIBS -lpopt"
+AC_TRY_RUN([
+/*
+ * Just see if we can compile/link with popt
+ */
+#include <popt.h>
+
+int main(int argc, const char *argv[])
+{
+ struct poptOption popt_options[] = {
+ POPT_TABLEEND
+ };
+ poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+ return 0;
+}
+], ac_cv_have_popt=yes, ac_cv_have_popt=no,
+ [echo $ac_n "compile with POPT. Assuming OK... $ac_c"
+ ac_cv_have_popt=yes])
+CFLAGS="$ac_save_CFLAGS"
+LIBS="$ac_save_LIBS"
+if test "$ac_cv_have_popt" = yes ; then
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+ AC_MSG_NOTICE(You need libpopt to compile libnfs. Install the libpopt-dev package.)
+ exit
+fi
+
+AC_SUBST(libdir)
+AC_SUBST(install)
+AC_SUBST(ldconfig)
+#AC_SUBST(LIBNFS_LDFLAGS)
+
+AC_OUTPUT(Makefile)
--- /dev/null
+/*
+ Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2010
+
+ 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 highlevel async interface.
+ */
+
+#define SERVER "10.1.1.27"
+#define EXPORT "/VIRTUAL"
+#define NFSFILE "/BOOKS/Classics/Dracula.djvu"
+#define NFSDIR "/BOOKS/Classics/"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include "libnfs.h"
+
+struct client {
+ char *server;
+ char *export;
+ uint32_t mount_port;
+ struct nfsfh *nfsfh;
+ int is_finished;
+};
+
+void nfs_opendir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
+{
+ struct client *client = private_data;
+ struct nfsdir *nfsdir = data;
+ struct nfsdirent *nfsdirent;
+
+ if (status < 0) {
+ printf("opendir failed with \"%s\"\n", (char *)data);
+ exit(10);
+ }
+
+ printf("opendir successful\n");
+ while((nfsdirent = nfs_readdir(nfs, nfsdir)) != NULL) {
+ printf("Inode:%d Name:%s\n", (int)nfsdirent->inode, nfsdirent->name);
+ }
+ nfs_closedir(nfs, nfsdir);
+
+ client->is_finished = 1;
+}
+
+void nfs_close_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
+{
+ struct client *client = private_data;
+
+ if (status < 0) {
+ printf("close failed with \"%s\"\n", (char *)data);
+ exit(10);
+ }
+
+ printf("close successful\n");
+ printf("call opendir(%s)\n", NFSDIR);
+ if (nfs_opendir_async(nfs, NFSDIR, nfs_opendir_cb, client) != 0) {
+ printf("Failed to start async nfs close\n");
+ exit(10);
+ }
+}
+
+void nfs_fstat_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
+{
+ struct client *client = private_data;
+ struct stat *st;
+
+ if (status < 0) {
+ printf("fstat call failed with \"%s\"\n", (char *)data);
+ exit(10);
+ }
+
+ printf("Got reply from server for fstat(%s).\n", NFSFILE);
+ st = (struct stat *)data;
+ printf("Mode %04o\n", st->st_mode);
+ printf("Size %d\n", (int)st->st_size);
+ printf("Inode %04o\n", (int)st->st_ino);
+
+ printf("Close file\n");
+ if (nfs_close_async(nfs, client->nfsfh, nfs_close_cb, client) != 0) {
+ printf("Failed to start async nfs close\n");
+ exit(10);
+ }
+}
+
+void nfs_read_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
+{
+ struct client *client = private_data;
+ char *read_data;
+ int i;
+
+ if (status < 0) {
+ printf("read failed with \"%s\"\n", (char *)data);
+ exit(10);
+ }
+
+ printf("read successful with %d bytes of data\n", status);
+ read_data = data;
+ for (i=0;i<16;i++) {
+ printf("%02x ", read_data[i]&0xff);
+ }
+ printf("\n");
+ printf("Fstat file :%s\n", NFSFILE);
+ if (nfs_fstat_async(nfs, client->nfsfh, nfs_fstat_cb, client) != 0) {
+ printf("Failed to start async nfs fstat\n");
+ exit(10);
+ }
+}
+
+void nfs_open_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
+{
+ struct client *client = private_data;
+ struct nfsfh *nfsfh;
+
+ if (status < 0) {
+ printf("open call failed with \"%s\"\n", (char *)data);
+ exit(10);
+ }
+
+ nfsfh = data;
+ client->nfsfh = nfsfh;
+ printf("Got reply from server for open(%s). Handle:%p\n", NFSFILE, data);
+ printf("Read first 16 bytes\n");
+ if (nfs_pread_async(nfs, nfsfh, 0, 16, nfs_read_cb, client) != 0) {
+ printf("Failed to start async nfs open\n");
+ exit(10);
+ }
+}
+
+void nfs_stat_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
+{
+ struct client *client = private_data;
+ struct stat *st;
+
+ if (status < 0) {
+ printf("stat call failed with \"%s\"\n", (char *)data);
+ exit(10);
+ }
+
+ printf("Got reply from server for stat(%s).\n", NFSFILE);
+ st = (struct stat *)data;
+ printf("Mode %04o\n", st->st_mode);
+ printf("Size %d\n", (int)st->st_size);
+ printf("Inode %04o\n", (int)st->st_ino);
+
+ printf("Open file for reading :%s\n", NFSFILE);
+ if (nfs_open_async(nfs, NFSFILE, O_RDONLY, nfs_open_cb, client) != 0) {
+ printf("Failed to start async nfs open\n");
+ exit(10);
+ }
+}
+
+void nfs_mount_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
+{
+ struct client *client = private_data;
+
+ if (status < 0) {
+ printf("mount/mnt call failed with \"%s\"\n", (char *)data);
+ exit(10);
+ }
+
+ printf("Got reply from server for MOUNT/MNT procedure.\n");
+ printf("Stat file :%s\n", NFSFILE);
+ if (nfs_stat_async(nfs, NFSFILE, nfs_stat_cb, client) != 0) {
+ printf("Failed to start async nfs stat\n");
+ exit(10);
+ }
+}
+
+
+
+int main(int argc, char *argv[])
+{
+ struct nfs_context *nfs;
+ struct pollfd pfd;
+ int ret;
+ struct client client;
+
+ client.server = SERVER;
+ client.export = EXPORT;
+ client.is_finished = 0;
+
+ nfs = nfs_init_context();
+ if (nfs == NULL) {
+ printf("failed to init context\n");
+ exit(10);
+ }
+
+ ret = nfs_mount_async(nfs, client.server, client.export, nfs_mount_cb, &client);
+ if (ret != 0) {
+ printf("Failed to start async nfs mount\n");
+ exit(10);
+ }
+
+ for (;;) {
+ pfd.fd = nfs_get_fd(nfs);
+ pfd.events = nfs_which_events(nfs);
+
+ if (poll(&pfd, 1, -1) < 0) {
+ printf("Poll failed");
+ exit(10);
+ }
+ if (nfs_service(nfs, pfd.revents) < 0) {
+ printf("nfs_service failed\n");
+ break;
+ }
+ if (client.is_finished) {
+ break;
+ }
+ }
+
+ nfs_destroy_context(nfs);
+ printf("nfsclient finished\n");
+ return 0;
+}
--- /dev/null
+/*
+ Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2010
+
+ 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.
+ */
+
+#define SERVER "10.1.1.27"
+#define EXPORT "/VIRTUAL"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <poll.h>
+#include "libnfs.h"
+#include "libnfs-raw.h"
+#include "libnfs-raw-mount.h"
+
+struct client {
+ char *server;
+ char *export;
+ uint32_t mount_port;
+ int is_finished;
+};
+
+void mount_mnt_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+ struct client *client = private_data;
+
+ if (status == RPC_STATUS_ERROR) {
+ printf("mount/mnt call failed with \"%s\"\n", (char *)data);
+ exit(10);
+ }
+ if (status != RPC_STATUS_SUCCESS) {
+ printf("mount/mnt call to server %s failed, status:%d\n", client->server, status);
+ exit(10);
+ }
+
+ printf("Got reply from server for MOUNT/MNT procedure.\n");
+ client->is_finished = 1;
+}
+
+
+void mount_null_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+ struct client *client = private_data;
+
+ if (status == RPC_STATUS_ERROR) {
+ printf("mount null call failed with \"%s\"\n", (char *)data);
+ exit(10);
+ }
+ if (status != RPC_STATUS_SUCCESS) {
+ printf("mount null call to server %s failed, status:%d\n", client->server, status);
+ exit(10);
+ }
+
+ printf("Got reply from server for MOUNT/NULL procedure.\n");
+ printf("Send MOUNT/MNT command for %s\n", client->export);
+ if (rpc_mount_mnt_async(rpc, mount_mnt_cb, client->export, client) != 0) {
+ printf("Failed to send mnt request\n");
+ exit(10);
+ }
+
+}
+
+void mount_connect_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+ struct client *client = private_data;
+
+ if (status != RPC_STATUS_SUCCESS) {
+ printf("connection to RPC.MOUNTD on server %s failed\n", client->server);
+ exit(10);
+ }
+
+ printf("Connected to RPC.MOUNTD on %s:%d\n", client->server, client->mount_port);
+ printf("Send NULL request to check if RPC.MOUNTD is actually running\n");
+ if (rpc_mount_null_async(rpc, mount_null_cb, client) != 0) {
+ printf("Failed to send null request\n");
+ exit(10);
+ }
+}
+
+
+void pmap_getport_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+ struct client *client = private_data;
+ uint32_t port;
+
+ if (status == RPC_STATUS_ERROR) {
+ printf("portmapper getport call failed with \"%s\"\n", (char *)data);
+ exit(10);
+ }
+ if (status != RPC_STATUS_SUCCESS) {
+ printf("portmapper getport call to server %s failed, status:%d\n", client->server, status);
+ exit(10);
+ }
+
+ client->mount_port = *(uint32_t *)data;
+ printf("GETPORT returned Port:%d\n", client->mount_port);
+ if (client->mount_port == 0) {
+ printf("RPC.MOUNTD is not available on server : %s\n", client->server, client->mount_port);
+ exit(10);
+ }
+
+ printf("Disconnect socket from portmap server\n");
+ if (rpc_disconnect(rpc, "normal disconnect") != 0) {
+ printf("Failed to disconnect socket to portmapper\n");
+ exit(10);
+ }
+
+ printf("Connect to RPC.MOUNTD on %s:%d\n", client->server, client->mount_port);
+ if (rpc_connect_async(rpc, client->server, client->mount_port, mount_connect_cb, client) != 0) {
+ printf("Failed to start connection\n");
+ exit(10);
+ }
+}
+
+
+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("portmapper null call failed with \"%s\"\n", (char *)data);
+ exit(10);
+ }
+ if (status != RPC_STATUS_SUCCESS) {
+ printf("portmapper null call to server %s failed, status:%d\n", client->server, status);
+ exit(10);
+ }
+
+ printf("Got reply from server for PORTMAP/NULL procedure.\n");
+ printf("Send getport request asking for MOUNT port\n");
+ if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, pmap_getport_cb, client) != 0) {
+ printf("Failed to send getport request\n");
+ exit(10);
+ }
+}
+
+void pmap_connect_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+ struct client *client = private_data;
+
+ printf("pmap_connect_cb status:%d.\n", status);
+ if (status != RPC_STATUS_SUCCESS) {
+ printf("connection to portmapper on server %s failed\n", client->server);
+ exit(10);
+ }
+
+ printf("Send NULL request to check if portmapper is actually running\n");
+ if (rpc_pmap_null_async(rpc, pmap_null_cb, client) != 0) {
+ printf("Failed to send null request\n");
+ exit(10);
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct rpc_context *rpc;
+ struct pollfd pfd;
+ int ret;
+ struct client client;
+
+ rpc = rpc_init_context();
+ if (rpc == NULL) {
+ printf("failed to init context\n");
+ exit(10);
+ }
+
+ client.server = SERVER;
+ client.export = EXPORT;
+ client.is_finished = 0;
+ if (rpc_connect_async(rpc, client.server, 111, pmap_connect_cb, &client) != 0) {
+ printf("Failed to start connection\n");
+ exit(10);
+ }
+
+ 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;
+ }
+ }
+
+ rpc_destroy_context(rpc);
+ rpc=NULL;
+ printf("nfsclient finished\n");
+ return 0;
+}
--- /dev/null
+/*
+ Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2010
+
+ 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 highlevel sync interface
+ */
+
+#define SERVER "10.1.1.27"
+#define EXPORT "/VIRTUAL"
+#define NFSFILE "/BOOKS/Classics/Dracula.djvu"
+#define NFSFILER "/BOOKS/Classics/Dracula.djvu.renamed"
+#define NFSFILEW "/BOOKS/Classics/foo"
+#define NFSDIR "/BOOKS/Classics/"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "libnfs.h"
+#include <rpc/rpc.h> /* for authunix_create() */
+
+struct client {
+ char *server;
+ char *export;
+ uint32_t mount_port;
+ int is_finished;
+};
+
+
+int main(int argc, char *argv[])
+{
+ struct nfs_context *nfs;
+ int i, ret;
+ struct client client;
+ struct stat st;
+ struct nfsfh *nfsfh;
+ struct nfsdir *nfsdir;
+ struct nfsdirent *nfsdirent;
+ client.server = SERVER;
+ client.export = EXPORT;
+ client.is_finished = 0;
+ char buf[16];
+ off_t offset;
+ struct statvfs svfs;
+
+ nfs = nfs_init_context();
+ if (nfs == NULL) {
+ printf("failed to init context\n");
+ exit(10);
+ }
+
+ ret = nfs_mount_sync(nfs, client.server, client.export);
+ if (ret != 0) {
+ printf("Failed to mount nfs share : %s\n", nfs_get_error(nfs));
+ exit(10);
+ }
+ printf("mounted share successfully\n");
+
+
+ ret = nfs_stat_sync(nfs, NFSFILE, &st);
+ if (ret != 0) {
+ printf("Failed to stat(%s) %s\n", NFSFILE, nfs_get_error(nfs));
+ exit(10);
+ }
+ printf("Mode %04o\n", st.st_mode);
+ printf("Size %d\n", (int)st.st_size);
+ printf("Inode %04o\n", (int)st.st_ino);
+
+ ret = nfs_open_sync(nfs, NFSFILE, O_RDONLY, &nfsfh);
+ if (ret != 0) {
+ printf("Failed to open(%s) %s\n", NFSFILE, nfs_get_error(nfs));
+ exit(10);
+ }
+
+ ret = nfs_read_sync(nfs, nfsfh, 16, buf);
+ if (ret < 0) {
+ printf("Failed to pread(%s) %s\n", NFSFILE, nfs_get_error(nfs));
+ exit(10);
+ }
+ printf("read %d bytes\n", ret);
+ for (i=0;i<16;i++) {
+ printf("%02x ", buf[i]&0xff);
+ }
+ printf("\n");
+ ret = nfs_read_sync(nfs, nfsfh, 16, buf);
+ if (ret < 0) {
+ printf("Failed to pread(%s) %s\n", NFSFILE, nfs_get_error(nfs));
+ exit(10);
+ }
+ printf("read %d bytes\n", ret);
+ for (i=0;i<16;i++) {
+ printf("%02x ", buf[i]&0xff);
+ }
+ printf("\n");
+
+ ret = (int)nfs_lseek_sync(nfs, nfsfh, 0, SEEK_CUR, &offset);
+ if (ret < 0) {
+ printf("Failed to lseek(%s) %s\n", NFSFILE, nfs_get_error(nfs));
+ exit(10);
+ }
+ printf("File position is %d\n", (int)offset);
+
+ printf("seek to end of file\n");
+ ret = (int)nfs_lseek_sync(nfs, nfsfh, 0, SEEK_END, &offset);
+ if (ret < 0) {
+ printf("Failed to lseek(%s) %s\n", NFSFILE, nfs_get_error(nfs));
+ exit(10);
+ }
+ printf("File position is %d\n", (int)offset);
+
+ ret = nfs_fstat_sync(nfs, nfsfh, &st);
+ if (ret != 0) {
+ printf("Failed to stat(%s) %s\n", NFSFILE, nfs_get_error(nfs));
+ exit(10);
+ }
+ printf("Mode %04o\n", st.st_mode);
+ printf("Size %d\n", (int)st.st_size);
+ printf("Inode %04o\n", (int)st.st_ino);
+
+
+ ret = nfs_close_sync(nfs, nfsfh);
+ if (ret < 0) {
+ printf("Failed to close(%s)\n", NFSFILE, nfs_get_error(nfs));
+ exit(10);
+ }
+
+ ret = nfs_opendir_sync(nfs, NFSDIR, &nfsdir);
+ if (ret != 0) {
+ printf("Failed to open(%s) %s\n", NFSFILE, nfs_get_error(nfs));
+ exit(10);
+ }
+ while((nfsdirent = nfs_readdir(nfs, nfsdir)) != NULL) {
+ printf("Inode:%d Name:%s\n", (int)nfsdirent->inode, nfsdirent->name);
+ }
+ nfs_closedir(nfs, nfsdir);
+
+
+ ret = nfs_open_sync(nfs, NFSFILEW, O_WRONLY, &nfsfh);
+ if (ret != 0) {
+ printf("Failed to open(%s) %s\n", NFSFILEW, nfs_get_error(nfs));
+ exit(10);
+ }
+ ret = nfs_pwrite_sync(nfs, nfsfh, 0, 16, buf);
+ if (ret < 0) {
+ printf("Failed to pwrite(%s) %s\n", NFSFILEW, nfs_get_error(nfs));
+ exit(10);
+ }
+ ret = nfs_fsync_sync(nfs, nfsfh);
+ if (ret < 0) {
+ printf("Failed to fsync(%s) %s\n", NFSFILEW, nfs_get_error(nfs));
+ exit(10);
+ }
+ ret = nfs_close_sync(nfs, nfsfh);
+ if (ret < 0) {
+ printf("Failed to close(%s)\n", NFSFILEW, nfs_get_error(nfs));
+ exit(10);
+ }
+
+
+ ret = nfs_statvfs_sync(nfs, NFSDIR, &svfs);
+ if (ret < 0) {
+ printf("Failed to statvfs(%s)\n", NFSDIR, nfs_get_error(nfs));
+ exit(10);
+ }
+ printf("files %d/%d/%d\n", (int)svfs.f_files, (int)svfs.f_ffree, (int)svfs.f_favail);
+
+
+ ret = nfs_access_sync(nfs, NFSFILE, R_OK);
+ if (ret != 0) {
+ printf("Failed to access(%s) %s\n", NFSFILE, nfs_get_error(nfs));
+ }
+
+ /* become root */
+ nfs_set_auth(nfs, authunix_create("Ronnies-Laptop", 0, 0, 0, NULL));
+
+ ret = nfs_link_sync(nfs, NFSFILE, NFSFILER);
+ if (ret != 0) {
+ printf("Failed to link(%s) %s\n", NFSFILE, nfs_get_error(nfs));
+ }
+
+
+ nfs_destroy_context(nfs);
+ printf("nfsclient finished\n");
+ return 0;
+}
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+#include <rpc/auth.h>
+
+struct rpc_context {
+ int fd;
+ int is_connected;
+
+ char *error_string;
+
+ rpc_cb connect_cb;
+ void *connect_data;
+
+ AUTH *auth;
+ unsigned long xid;
+
+ /* buffer used for encoding RPC PDU */
+ char *encodebuf;
+ int encodebuflen;
+
+ struct rpc_pdu *outqueue;
+ struct rpc_pdu *waitpdu;
+
+ int insize;
+ int inpos;
+ char *inbuf;
+};
+
+struct rpc_pdu {
+ struct rpc_pdu *next;
+
+ unsigned long xid;
+ XDR xdr;
+
+ int written;
+ struct rpc_data outdata;
+
+ rpc_cb cb;
+ void *private_data;
+
+ /* function to decode the xdr reply data and buffer to decode into */
+ xdrproc_t xdr_decode_fn;
+ caddr_t xdr_decode_buf;
+ int xdr_decode_bufsize;
+};
+
+struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, xdrproc_t xdr_decode_fn, int xdr_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);
+int rpc_get_pdu_size(char *buf);
+int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size);
+void rpc_error_all_pdus(struct rpc_context *rpc, char *error);
+
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+/*
+ * This is the lowlevel interface to access NFS resources.
+ * Through this interface you have access to the full gamut of nfs and nfs related
+ * protocol as well as the XDR encoded/decoded structures.
+ */
+#include <stdint.h>
+
+struct rpc_data {
+ int size;
+ unsigned char *data;
+};
+
+struct rpc_context;
+struct rpc_context *rpc_init_context(void);
+void rpc_destroy_context(struct rpc_context *rpc);
+
+struct AUTH;
+void rpc_set_auth(struct rpc_context *rpc, struct AUTH *auth);
+
+int rpc_get_fd(struct rpc_context *rpc);
+int rpc_which_events(struct rpc_context *rpc);
+int rpc_service(struct rpc_context *rpc, int revents);
+char *rpc_get_error(struct rpc_context *rpc);
+
+
+#define RPC_STATUS_SUCCESS 0
+#define RPC_STATUS_ERROR 1
+#define RPC_STATUS_CANCEL 2
+
+typedef void (*rpc_cb)(struct rpc_context *rpc, int status, void *data, void *private_data);
+
+/*
+ * Async connection to the tcp port at server:port.
+ * 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 : The tcp connection was successfully established.
+ * data is NULL.
+ * RPC_STATUS_ERROR : The connection failed to establish.
+ * data is the erro string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * : data is NULL.
+ */
+int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, 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.
+ */
+int rpc_disconnect(struct rpc_context *rpc, char *error);
+
+void rpc_set_error(struct rpc_context *rpc, char *error_string, ...);
+
+
+/*
+ * PORTMAP FUNCTIONS
+ */
+
+/*
+ * Call PORTMAPPER/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.
+ */
+int rpc_pmap_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
+
+
+/*
+ * Call PORTMAPPER/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.
+ *
+ * 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 *), containing the port returned.
+ * 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.
+ */
+int rpc_pmap_getport_async(struct rpc_context *rpc, int program, int version, rpc_cb cb, void *private_data);
+
+
+
+/*
+ * MOUNT FUNCTIONS
+ */
+char *mountstat3_to_str(int stat);
+int mountstat3_to_errno(int error);
+
+/*
+ * Call MOUNT/NULL
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 mount daemon.
+ * data is NULL.
+ * RPC_STATUS_ERROR : An error occured when trying to contact the mount daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_mount_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
+
+/*
+ * Call MOUNT/MNT
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 mount daemon.
+ * data is union mountres3.
+ * RPC_STATUS_ERROR : An error occured when trying to contact the mount daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_mount_mnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void *private_data);
+
+/*
+ * Call MOUNT/DUMP
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 mount daemon.
+ * data is a mountlist.
+ * RPC_STATUS_ERROR : An error occured when trying to contact the mount daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_mount_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
+
+/*
+ * Call MOUNT/UMNT
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 mount daemon.
+ * data NULL.
+ * RPC_STATUS_ERROR : An error occured when trying to contact the mount daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_mount_umnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void *private_data);
+
+/*
+ * Call MOUNT/UMNTALL
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 mount daemon.
+ * data NULL.
+ * RPC_STATUS_ERROR : An error occured when trying to contact the mount daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_mount_umntall_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
+
+/*
+ * Call MOUNT/EXPORT
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 mount daemon.
+ * data is an exports.
+ * RPC_STATUS_ERROR : An error occured when trying to contact the mount daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_mount_export_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
+
+
+
+
+/*
+ * NFS FUNCTIONS
+ */
+struct nfs_fh3;
+char *nfsstat3_to_str(int error);
+int nfsstat3_to_errno(int error);
+
+/*
+ * Call NFS/NULL
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is NULL.
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
+
+/*
+ * Call NFS/GETATTR
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is GETATTR3res
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_getattr_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, void *private_data);
+
+/*
+ * Call NFS/LOOKUP
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is LOOKUP3res
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_lookup_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *name, void *private_data);
+
+/*
+ * Call NFS/ACCESS
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is ACCESS3res
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_access_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, int access, void *private_data);
+
+/*
+ * Call NFS/READ
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is ACCESS3res
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_read_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, off_t offset, size_t count, void *private_data);
+
+/*
+ * Call NFS/WRITE
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is WRITE3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_write_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *buf, off_t offset, size_t count, int stable_how, void *private_data);
+
+/*
+ * Call NFS/COMMIT
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is COMMIT3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_commit_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, void *private_data);
+
+
+/*
+ * Call NFS/SETATTR
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is SETATTR3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+struct SETATTR3args;
+int rpc_nfs_setattr_async(struct rpc_context *rpc, rpc_cb cb, struct SETATTR3args *args, void *private_data);
+
+
+
+/*
+ * Call NFS/MKDIR
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is MKDIR3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_mkdir_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *dir, void *private_data);
+
+
+
+
+
+/*
+ * Call NFS/RMDIR
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is RMDIR3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_rmdir_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *dir, void *private_data);
+
+
+
+
+/*
+ * Call NFS/CREATE
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is CREATE3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_create_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *name, int mode, void *private_data);
+
+
+
+
+/*
+ * Call NFS/REMOVE
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is REMOVE3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_remove_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *name, void *private_data);
+
+
+
+/*
+ * Call NFS/REMOVE
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is READDIR3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_readdir_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, uint64_t cookie, char *cookieverf, int count, void *private_data);
+
+/*
+ * Call NFS/FSSTAT
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is FSSTAT3res
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_fsstat_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, void *private_data);
+
+
+
+
+/*
+ * Call NFS/READLINK
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is READLINK3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_readlink_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, void *private_data);
+
+
+
+/*
+ * Call NFS/SYMLINK
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is SYMLINK3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_symlink_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *newname, char *oldpath, void *private_data);
+
+
+/*
+ * Call NFS/RENAME
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is RENAME3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_rename_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *olddir, char *oldname, struct nfs_fh3 *newdir, char *newname, void *private_data);
+
+
+
+/*
+ * Call NFS/LINK
+ * Function returns
+ * 0 : The call was initiated. The callback will be invoked when the call completes.
+ * <0 : An error occured when trying to set up the call. 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 nfs daemon.
+ * data is LINK3res *
+ * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
+ * data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ * data is NULL.
+ */
+int rpc_nfs_link_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *file, struct nfs_fh3 *newdir, char *newname, void *private_data);
+
+
+
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+/*
+ * This is the highlevel interface to access NFS resources using a posix-like interface
+ */
+#include <stdint.h>
+
+struct nfs_context;
+
+/*
+ * Used for interfacing the async version of the api into an external eventsystem
+ */
+int nfs_get_fd(struct nfs_context *nfs);
+int nfs_which_events(struct nfs_context *nfs);
+int nfs_service(struct nfs_context *nfs, int revents);
+
+/*
+ * Used if you need different credentials than the default for the current user.
+ */
+struct AUTH;
+void nfs_set_auth(struct nfs_context *nfs, struct AUTH *auth);
+
+
+/*
+ * When an operation failed, this function can extract a detailed error string.
+ */
+char *nfs_get_error(struct nfs_context *nfs);
+
+
+/*
+ * Callback for all ASYNC nfs functions
+ */
+typedef void (*nfs_cb)(int err, struct nfs_context *nfs, void *data, void *private_data);
+
+
+
+
+/*
+ * NFS CONTEXT.
+ */
+/*
+ * Create an NFS c, the context.
+ * Function returns
+ * NULL : Failed to create a context.
+ * *nfs : A pointer to an nfs context.
+ */
+struct nfs_context *nfs_init_context(void);
+/*
+ * Destroy an nfs context.
+ */
+void nfs_destroy_context(struct nfs_context *nfs);
+
+
+struct nfsfh;
+
+
+/*
+ * MOUNT THE EXPORT
+ */
+/*
+ * Async nfs mount.
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *export, nfs_cb cb, void *private_data);
+/*
+ * Sync nfs mount.
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_mount_sync(struct nfs_context *nfs, const char *server, const char *export);
+
+
+
+
+/*
+ * STAT()
+ */
+/*
+ * Async stat(<filename>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is struct stat *
+ * -errno : An error occured.
+ * data is the error string.
+ */
+struct stat;
+int nfs_stat_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data);
+/*
+ * Sync stat(<filename>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_stat_sync(struct nfs_context *nfs, const char *path, struct stat *st);
+
+
+/*
+ * FSTAT()
+ */
+/*
+ * Async fstat(nfsfh *)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is struct stat *
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data);
+/*
+ * Sync fstat(nfsfh *)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_fstat_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat *st);
+
+
+
+/*
+ * OPEN()
+ */
+/*
+ * Async open(<filename>)
+ *
+ * mode is a combination of the flags : O_RDOLNY, O_WRONLY, O_RDWR , O_SYNC
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is a struct *nfsfh;
+ * The nfsfh is close using nfs_close().
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_open_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data);
+/*
+ * Sync stat(<filename>)
+ * Function returns
+ * 0 : The operation was successfull. *nfsfh is filled in.
+ * -errno : The command failed.
+ */
+int nfs_open_sync(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh);
+
+
+
+
+/*
+ * CLOSE
+ */
+/*
+ * Async close(nfsfh)
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data);
+/*
+ * Sync close(nfsfh)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_close_sync(struct nfs_context *nfs, struct nfsfh *nfsfh);
+
+
+/*
+ * PREAD()
+ */
+/*
+ * Async pread()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * >=0 : Success.
+ * status is numer of bytes read.
+ * data is a pointer to the returned data.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, nfs_cb cb, void *private_data);
+/*
+ * Sync pread()
+ * Function returns
+ * >=0 : numer of bytes read.
+ * -errno : An error occured.
+ */
+int nfs_pread_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buf);
+
+
+
+/*
+ * READ()
+ */
+/*
+ * Async read()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * >=0 : Success.
+ * status is numer of bytes read.
+ * data is a pointer to the returned data.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, nfs_cb cb, void *private_data);
+/*
+ * Sync read()
+ * Function returns
+ * >=0 : numer of bytes read.
+ * -errno : An error occured.
+ */
+int nfs_read_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buf);
+
+
+
+
+/*
+ * PWRITE()
+ */
+/*
+ * Async pwrite()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * >=0 : Success.
+ * status is numer of bytes written.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buf, nfs_cb cb, void *private_data);
+/*
+ * Sync pwrite()
+ * Function returns
+ * >=0 : numer of bytes written.
+ * -errno : An error occured.
+ */
+int nfs_pwrite_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buf);
+
+
+/*
+ * WRITE()
+ */
+/*
+ * Async write()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * >=0 : Success.
+ * status is numer of bytes written.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buf, nfs_cb cb, void *private_data);
+/*
+ * Sync write()
+ * Function returns
+ * >=0 : numer of bytes written.
+ * -errno : An error occured.
+ */
+int nfs_write_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buf);
+
+
+/*
+ * LSEEK()
+ */
+/*
+ * Async lseek()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * >=0 : Success.
+ * data is off_t * for the current position.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, int whence, nfs_cb cb, void *private_data);
+/*
+ * Sync lseek()
+ * Function returns
+ * >=0 : numer of bytes read.
+ * -errno : An error occured.
+ */
+int nfs_lseek_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, int whence, off_t *current_offset);
+
+
+/*
+ * FSYNC()
+ */
+/*
+ * Async fsync()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_fsync_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data);
+/*
+ * Sync fsync()
+ * Function returns
+ * 0 : Success
+ * -errno : An error occured.
+ */
+int nfs_fsync_sync(struct nfs_context *nfs, struct nfsfh *nfsfh);
+
+
+
+/*
+ * TRUNCATE()
+ */
+/*
+ * Async truncate()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_truncate_async(struct nfs_context *nfs, const char *path, off_t length, nfs_cb cb, void *private_data);
+/*
+ * Sync truncate()
+ * Function returns
+ * 0 : Success
+ * -errno : An error occured.
+ */
+int nfs_truncate_sync(struct nfs_context *nfs, const char *path, off_t length);
+
+
+
+/*
+ * FTRUNCATE()
+ */
+/*
+ * Async ftruncate()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t length, nfs_cb cb, void *private_data);
+/*
+ * Sync ftruncate()
+ * Function returns
+ * 0 : Success
+ * -errno : An error occured.
+ */
+int nfs_ftruncate_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t length);
+
+
+
+
+
+
+/*
+ * MKDIR()
+ */
+/*
+ * Async mkdir()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data);
+/*
+ * Sync mkdir()
+ * Function returns
+ * 0 : Success
+ * -errno : An error occured.
+ */
+int nfs_mkdir_sync(struct nfs_context *nfs, const char *path);
+
+
+
+/*
+ * RMDIR()
+ */
+/*
+ * Async rmdir()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_rmdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data);
+/*
+ * Sync rmdir()
+ * Function returns
+ * 0 : Success
+ * -errno : An error occured.
+ */
+int nfs_rmdir_sync(struct nfs_context *nfs, const char *path);
+
+
+
+
+/*
+ * CREAT()
+ */
+/*
+ * Async creat()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is a struct *nfsfh;
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data);
+/*
+ * Sync creat()
+ * Function returns
+ * 0 : Success
+ * -errno : An error occured.
+ */
+int nfs_creat_sync(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh);
+
+
+
+
+
+/*
+ * UNLINK()
+ */
+/*
+ * Async unlink()
+ *
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data);
+/*
+ * Sync unlink()
+ * Function returns
+ * 0 : Success
+ * -errno : An error occured.
+ */
+int nfs_unlink_sync(struct nfs_context *nfs, const char *path);
+
+
+
+
+/*
+ * OPENDIR()
+ */
+struct nfsdir;
+/*
+ * Async opendir()
+ *
+ * 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.
+ *
+ * When struct nfsdir * is returned, this resource is closed/freed by calling nfs_closedir()
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is struct nfsdir *
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_opendir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data);
+/*
+ * Sync opendir()
+ * Function returns
+ * 0 : Success
+ * -errno : An error occured.
+ */
+int nfs_opendir_sync(struct nfs_context *nfs, const char *path, struct nfsdir **nfsdir);
+
+
+
+/*
+ * READDIR()
+ */
+struct nfsdirent {
+ struct nfsdirent *next;
+ char *name;
+ uint64_t inode;
+};
+/*
+ * nfs_readdir() never blocks, so no special sync/async versions are available
+ */
+struct nfsdirent *nfs_readdir(struct nfs_context *nfs, struct nfsdir *nfsdir);
+
+
+
+/*
+ * READDIR()
+ */
+/*
+ * nfs_closedir() never blocks, so no special sync/async versions are available
+ */
+void nfs_closedir(struct nfs_context *nfs, struct nfsdir *nfsdir);
+
+
+
+/*
+ * STATVFS()
+ */
+/*
+ * Async statvfs(<dirname>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is struct statvfs *
+ * -errno : An error occured.
+ * data is the error string.
+ */
+struct statvfs;
+int nfs_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data);
+/*
+ * Sync statvfs(<dirname>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_statvfs_sync(struct nfs_context *nfs, const char *path, struct statvfs *svfs);
+
+
+/*
+ * READLINK()
+ */
+/*
+ * Async readlink(<name>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is a char *
+ * data is only valid during the callback and is automatically freed when the callback returns.
+ * -errno : An error occured.
+ * data is the error string.
+ */
+struct statvfs;
+int nfs_readlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data);
+/*
+ * Sync readlink(<name>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_readlink_sync(struct nfs_context *nfs, const char *path, char *buf, int bufsize);
+
+
+
+/*
+ * CHMOD()
+ */
+/*
+ * Async chmod(<name>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_chmod_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data);
+/*
+ * Sync chmod(<name>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_chmod_sync(struct nfs_context *nfs, const char *path, int mode);
+
+
+
+/*
+ * FCHMOD()
+ */
+/*
+ * Async fchmod(<handle>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode, nfs_cb cb, void *private_data);
+/*
+ * Sync fchmod(<handle>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_fchmod_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode);
+
+
+
+/*
+ * CHOWN()
+ */
+/*
+ * Async chown(<name>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, int gid, nfs_cb cb, void *private_data);
+/*
+ * Sync chown(<name>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_chown_sync(struct nfs_context *nfs, const char *path, int uid, int gid);
+
+
+
+/*
+ * FCHOWN()
+ */
+/*
+ * Async fchown(<handle>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int gid, nfs_cb cb, void *private_data);
+/*
+ * Sync fchown(<handle>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_fchown_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int gid);
+
+
+
+
+/*
+ * UTIMES()
+ */
+/*
+ * Async utimes(<path>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct timeval *times, nfs_cb cb, void *private_data);
+/*
+ * Sync utimes(<path>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_utimes_sync(struct nfs_context *nfs, const char *path, struct timeval *times);
+
+
+/*
+ * UTIME()
+ */
+/*
+ * Async utime(<path>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+struct utimbuf;
+int nfs_utime_async(struct nfs_context *nfs, const char *path, struct utimbuf *times, nfs_cb cb, void *private_data);
+/*
+ * Sync utime(<path>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_utime_sync(struct nfs_context *nfs, const char *path, struct utimbuf *times);
+
+
+
+
+/*
+ * ACCESS()
+ */
+/*
+ * Async access(<path>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_access_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data);
+/*
+ * Sync access(<path>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_access_sync(struct nfs_context *nfs, const char *path, int mode);
+
+
+
+
+/*
+ * SYMLINK()
+ */
+/*
+ * Async symlink(<path>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_symlink_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data);
+/*
+ * Sync symlink(<path>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_symlink_sync(struct nfs_context *nfs, const char *oldpath, const char *newpath);
+
+
+/*
+ * RENAME()
+ */
+/*
+ * Async rename(<oldpath>, <newpath>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data);
+/*
+ * Sync rename(<oldpath>, <newpath>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_rename_sync(struct nfs_context *nfs, const char *oldpath, const char *newpath);
+
+
+
+/*
+ * LINK()
+ */
+/*
+ * Async link(<oldpath>, <newpath>)
+ * 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.
+ *
+ * When the callback is invoked, status indicates the result:
+ * 0 : Success.
+ * data is NULL
+ * -errno : An error occured.
+ * data is the error string.
+ */
+int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data);
+/*
+ * Sync link(<oldpath>, <newpath>)
+ * Function returns
+ * 0 : The operation was successfull.
+ * -errno : The command failed.
+ */
+int nfs_link_sync(struct nfs_context *nfs, const char *oldpath, const char *newpath);
+
+
+
+//qqq replace later with lseek(cur, 0)
+off_t nfs_get_current_offset(struct nfsfh *nfsfh);
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+
+#define SLIST_ADD(list, item) \
+ do { \
+ (item)->next = (*list); \
+ (*list) = (item); \
+ } while (0);
+
+#define SLIST_ADD_END(list, item) \
+ if ((*list) == NULL) { \
+ SLIST_ADD((list), (item)); \
+ } else { \
+ void *head = (*list); \
+ while ((*list)->next) \
+ (*list) = (*list)->next; \
+ (*list)->next = (item); \
+ (item)->next = NULL; \
+ (*list) = head; \
+ }
+
+#define SLIST_REMOVE(list, item) \
+ if ((*list) == (item)) { \
+ (*list) = (item)->next; \
+ } else { \
+ void *head = (*list); \
+ while ((*list)->next && (*list)->next != (item)) \
+ (*list) = (*list)->next; \
+ if ((*list)->next != NULL) { \
+ (*list)->next = (*list)->next->next; \
+ } \
+ (*list) = head; \
+ }
+
+
+
+
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <rpc/xdr.h>
+#include "slist.h"
+#include "libnfs.h"
+#include "libnfs-raw.h"
+#include "libnfs-private.h"
+
+struct rpc_context *rpc_init_context(void)
+{
+ struct rpc_context *rpc;
+
+ rpc = malloc(sizeof(struct rpc_context));
+ if (rpc == NULL) {
+ printf("Failed to allocate rpc context\n");
+ return NULL;
+ }
+ bzero(rpc, sizeof(struct rpc_context));
+
+ rpc->encodebuflen = 65536;
+ rpc->encodebuf = malloc(rpc->encodebuflen);
+ if (rpc->encodebuf == NULL) {
+ printf("Failed to allocate a buffer for rpc encoding\n");
+ free(rpc);
+ return NULL;
+ }
+
+ rpc->auth = authunix_create_default();
+ if (rpc->auth == NULL) {
+ printf("failed to create authunix\n");
+ free(rpc->encodebuf);
+ free(rpc);
+ return NULL;
+ }
+ rpc->xid = 1;
+ rpc->fd = -1;
+
+ return rpc;
+}
+
+
+void rpc_set_auth(struct rpc_context *rpc, struct AUTH *auth)
+{
+ if (rpc->auth != NULL) {
+ auth_destroy(rpc->auth);
+ }
+ rpc->auth = auth;
+}
+
+
+void rpc_set_error(struct rpc_context *rpc, char *error_string, ...)
+{
+ va_list ap;
+ char *str;
+
+ if (rpc->error_string != NULL) {
+ free(rpc->error_string);
+ }
+ va_start(ap, error_string);
+ vasprintf(&str, error_string, ap);
+ rpc->error_string = str;
+ va_end(ap);
+}
+
+char *rpc_get_error(struct rpc_context *rpc)
+{
+ return rpc->error_string;
+}
+
+void rpc_error_all_pdus(struct rpc_context *rpc, char *error)
+{
+ struct rpc_pdu *pdu;
+
+ while((pdu = rpc->outqueue) != NULL) {
+ pdu->cb(rpc, RPC_STATUS_ERROR, error, pdu->private_data);
+ SLIST_REMOVE(&rpc->outqueue, pdu);
+ rpc_free_pdu(rpc, pdu);
+ }
+ while((pdu = rpc->waitpdu) != NULL) {
+ pdu->cb(rpc, RPC_STATUS_ERROR, error, pdu->private_data);
+ SLIST_REMOVE(&rpc->waitpdu, pdu);
+ rpc_free_pdu(rpc, pdu);
+ }
+}
+
+
+void rpc_destroy_context(struct rpc_context *rpc)
+{
+ struct rpc_pdu *pdu;
+
+ while((pdu = rpc->outqueue) != NULL) {
+ pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
+ SLIST_REMOVE(&rpc->outqueue, 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);
+ }
+
+ auth_destroy(rpc->auth);
+ rpc->auth =NULL;
+
+ if (rpc->fd != -1) {
+ close(rpc->fd);
+ }
+
+ if (rpc->encodebuf != NULL) {
+ free(rpc->encodebuf);
+ rpc->encodebuf = NULL;
+ }
+
+ if (rpc->error_string != NULL) {
+ free(rpc->error_string);
+ rpc->error_string = NULL;
+ }
+
+ free(rpc);
+}
+
+
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+/*
+ * High level api to nfs filesystems
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <poll.h>
+#include "libnfs.h"
+#include "libnfs-raw.h"
+#include "libnfs-raw-mount.h"
+#include "libnfs-raw-nfs.h"
+
+struct sync_cb_data {
+ int is_finished;
+ int status;
+ off_t offset;
+ void *return_data;
+ int return_int;
+};
+
+
+static void wait_for_reply(struct nfs_context *nfs, struct sync_cb_data *cb_data)
+{
+ struct pollfd pfd;
+
+ for (;;) {
+ if (cb_data->is_finished) {
+ break;
+ }
+ pfd.fd = nfs_get_fd(nfs);
+ pfd.events = nfs_which_events(nfs);
+
+ if (poll(&pfd, 1, -1) < 0) {
+ printf("Poll failed");
+ cb_data->status = -EIO;
+ break;
+ }
+ if (nfs_service(nfs, pfd.revents) < 0) {
+ printf("nfs_service failed\n");
+ cb_data->status = -EIO;
+ break;
+ }
+ }
+}
+
+
+
+
+
+
+/*
+ * connect to the server and mount the export
+ */
+static void mount_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("mount/mnt call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_mount_sync(struct nfs_context *nfs, const char *server, const char *export)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_mount_async(nfs, server, export, mount_cb, &cb_data) != 0) {
+ printf("nfs_mount_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+/*
+ * stat()
+ */
+static void stat_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("stat call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+
+ memcpy(cb_data->return_data, data, sizeof(struct stat));
+}
+
+int nfs_stat_sync(struct nfs_context *nfs, const char *path, struct stat *st)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+ cb_data.return_data = st;
+
+ if (nfs_stat_async(nfs, path, stat_cb, &cb_data) != 0) {
+ printf("nfs_stat_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+
+/*
+ * open()
+ */
+static void open_cb(int status, struct nfs_context *nfs _U_, void *data, void *private_data)
+{
+ struct sync_cb_data *cb_data = private_data;
+ struct nfsfh *fh, **nfsfh;
+
+ cb_data->is_finished = 1;
+ cb_data->status = status;
+
+ if (status < 0) {
+ printf("open call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+
+ fh = data;
+ nfsfh = cb_data->return_data;
+ *nfsfh = fh;
+}
+
+int nfs_open_sync(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+ cb_data.return_data = nfsfh;
+
+ if (nfs_open_async(nfs, path, mode, open_cb, &cb_data) != 0) {
+ printf("nfs_open_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+
+/*
+ * pread()
+ */
+static void pread_cb(int status, struct nfs_context *nfs _U_, void *data, void *private_data)
+{
+ struct sync_cb_data *cb_data = private_data;
+ char *buffer;
+ cb_data->is_finished = 1;
+ cb_data->status = status;
+
+ if (status < 0) {
+ printf("pread call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+
+ buffer = cb_data->return_data;
+ memcpy(buffer, (char *)data, status);
+}
+
+int nfs_pread_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buffer)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+ cb_data.return_data = buffer;
+
+ if (nfs_pread_async(nfs, nfsfh, offset, count, pread_cb, &cb_data) != 0) {
+ printf("nfs_pread_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+/*
+ * read()
+ */
+int nfs_read_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buffer)
+{
+ return nfs_pread_sync(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buffer);
+}
+
+/*
+ * close()
+ */
+static void close_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("close call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_close_sync(struct nfs_context *nfs, struct nfsfh *nfsfh)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_close_async(nfs, nfsfh, close_cb, &cb_data) != 0) {
+ printf("nfs_close_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+
+/*
+ * fstat()
+ */
+int nfs_fstat_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat *st)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+ cb_data.return_data = st;
+
+ if (nfs_fstat_async(nfs, nfsfh, stat_cb, &cb_data) != 0) {
+ printf("nfs_fstat_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+/*
+ * pwrite()
+ */
+static void pwrite_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("pwrite call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_pwrite_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buf)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_pwrite_async(nfs, nfsfh, offset, count, buf, pwrite_cb, &cb_data) != 0) {
+ printf("nfs_pwrite_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+/*
+ * write()
+ */
+int nfs_write_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buf)
+{
+ return nfs_pwrite_sync(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buf);
+}
+
+
+/*
+ * fsync()
+ */
+static void fsync_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("fsync call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_fsync_sync(struct nfs_context *nfs, struct nfsfh *nfsfh)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_fsync_async(nfs, nfsfh, fsync_cb, &cb_data) != 0) {
+ printf("nfs_fsync_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+
+/*
+ * ftruncate()
+ */
+static void ftruncate_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("ftruncate call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_ftruncate_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t length)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_ftruncate_async(nfs, nfsfh, length, ftruncate_cb, &cb_data) != 0) {
+ printf("nfs_ftruncate_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+/*
+ * truncate()
+ */
+static void truncate_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("truncate call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_truncate_sync(struct nfs_context *nfs, const char *path, off_t length)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_truncate_async(nfs, path, length, truncate_cb, &cb_data) != 0) {
+ printf("nfs_ftruncate_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+
+
+/*
+ * mkdir()
+ */
+static void mkdir_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("mkdir call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_mkdir_sync(struct nfs_context *nfs, const char *path)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_mkdir_async(nfs, path, mkdir_cb, &cb_data) != 0) {
+ printf("nfs_mkdir_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+
+
+/*
+ * rmdir()
+ */
+static void rmdir_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("rmdir call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_rmdir_sync(struct nfs_context *nfs, const char *path)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_rmdir_async(nfs, path, rmdir_cb, &cb_data) != 0) {
+ printf("nfs_rmdir_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+/*
+ * creat()
+ */
+static void creat_cb(int status, struct nfs_context *nfs _U_, void *data, void *private_data)
+{
+ struct sync_cb_data *cb_data = private_data;
+ struct nfsfh *fh, **nfsfh;
+
+ cb_data->is_finished = 1;
+ cb_data->status = status;
+
+ if (status < 0) {
+ printf("creat call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+
+ fh = data;
+ nfsfh = cb_data->return_data;
+ *nfsfh = fh;
+}
+
+int nfs_creat_sync(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+ cb_data.return_data = nfsfh;
+
+ if (nfs_creat_async(nfs, path, mode, creat_cb, &cb_data) != 0) {
+ printf("nfs_creat_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+
+/*
+ * unlink()
+ */
+static void unlink_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("unlink call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_unlink_sync(struct nfs_context *nfs, const char *path)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_unlink_async(nfs, path, unlink_cb, &cb_data) != 0) {
+ printf("nfs_unlink_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+/*
+ * opendir()
+ */
+static void opendir_cb(int status, struct nfs_context *nfs _U_, void *data, void *private_data)
+{
+ struct sync_cb_data *cb_data = private_data;
+ struct nfsdir *dir, **nfsdir;
+
+ cb_data->is_finished = 1;
+ cb_data->status = status;
+
+ if (status < 0) {
+ printf("opendir call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+
+ dir = data;
+ nfsdir = cb_data->return_data;
+ *nfsdir = dir;
+}
+
+int nfs_opendir_sync(struct nfs_context *nfs, const char *path, struct nfsdir **nfsdir)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+ cb_data.return_data = nfsdir;
+
+ if (nfs_opendir_async(nfs, path, opendir_cb, &cb_data) != 0) {
+ printf("nfs_opendir_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+/*
+ * lseek()
+ */
+static void lseek_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("lseek call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+
+ if (cb_data->return_data != NULL) {
+ memcpy(cb_data->return_data, data, sizeof(off_t));
+ }
+}
+
+int nfs_lseek_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, int whence, off_t *current_offset)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+ cb_data.return_data = current_offset;
+
+ if (nfs_lseek_async(nfs, nfsfh, offset, whence, lseek_cb, &cb_data) != 0) {
+ printf("nfs_lseek_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+/*
+ * statvfs()
+ */
+static void statvfs_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("statvfs call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+
+ memcpy(cb_data->return_data, data, sizeof(struct statvfs));
+}
+
+int nfs_statvfs_sync(struct nfs_context *nfs, const char *path, struct statvfs *svfs)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+ cb_data.return_data = svfs;
+
+ if (nfs_statvfs_async(nfs, path, statvfs_cb, &cb_data) != 0) {
+ printf("nfs_statvfs_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+
+
+/*
+ * readlink()
+ */
+static void readlink_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("readlink call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+
+ if (strlen(data) > (size_t)cb_data->return_int) {
+ printf("Too small buffer for readlink\n");
+ cb_data->status = -ENAMETOOLONG;
+ return;
+ }
+
+ memcpy(cb_data->return_data, data, strlen(data)+1);
+}
+
+int nfs_readlink_sync(struct nfs_context *nfs, const char *path, char *buf, int bufsize)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+ cb_data.return_data = buf;
+ cb_data.return_int = bufsize;
+
+ if (nfs_readlink_async(nfs, path, readlink_cb, &cb_data) != 0) {
+ printf("nfs_readlink_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+/*
+ * chmod()
+ */
+static void chmod_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("chmod call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_chmod_sync(struct nfs_context *nfs, const char *path, int mode)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_chmod_async(nfs, path, mode, chmod_cb, &cb_data) != 0) {
+ printf("nfs_chmod_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+
+/*
+ * fchmod()
+ */
+static void fchmod_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("fchmod call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_fchmod_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_fchmod_async(nfs, nfsfh, mode, fchmod_cb, &cb_data) != 0) {
+ printf("nfs_fchmod_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+
+/*
+ * chown()
+ */
+static void chown_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("chown call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_chown_sync(struct nfs_context *nfs, const char *path, int uid, int gid)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_chown_async(nfs, path, uid, gid, chown_cb, &cb_data) != 0) {
+ printf("nfs_chown_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+/*
+ * fchown()
+ */
+static void fchown_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("fchown call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_fchown_sync(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int gid)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_fchown_async(nfs, nfsfh, uid, gid, fchown_cb, &cb_data) != 0) {
+ printf("nfs_fchown_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+/*
+ * utimes()
+ */
+static void utimes_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("utimes call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_utimes_sync(struct nfs_context *nfs, const char *path, struct timeval *times)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_utimes_async(nfs, path, times, utimes_cb, &cb_data) != 0) {
+ printf("nfs_utimes_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+/*
+ * utime()
+ */
+static void utime_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("utime call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_utime_sync(struct nfs_context *nfs, const char *path, struct utimbuf *times)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_utime_async(nfs, path, times, utime_cb, &cb_data) != 0) {
+ printf("nfs_utimes_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+
+/*
+ * access()
+ */
+static void access_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("access call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_access_sync(struct nfs_context *nfs, const char *path, int mode)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_access_async(nfs, path, mode, access_cb, &cb_data) != 0) {
+ printf("nfs_access_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+/*
+ * symlink()
+ */
+static void symlink_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("symlink call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_symlink_sync(struct nfs_context *nfs, const char *oldpath, const char *newpath)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_symlink_async(nfs, oldpath, newpath, symlink_cb, &cb_data) != 0) {
+ printf("nfs_symlink_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+/*
+ * rename()
+ */
+static void rename_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("rename call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_rename_sync(struct nfs_context *nfs, const char *oldpath, const char *newpath)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_rename_async(nfs, oldpath, newpath, rename_cb, &cb_data) != 0) {
+ printf("nfs_rename_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
+
+
+
+/*
+ * link()
+ */
+static void link_cb(int status, struct nfs_context *nfs _U_, 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) {
+ printf("link call failed with \"%s\"\n", (char *)data);
+ return;
+ }
+}
+
+int nfs_link_sync(struct nfs_context *nfs, const char *oldpath, const char *newpath)
+{
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+
+ if (nfs_link_async(nfs, oldpath, newpath, link_cb, &cb_data) != 0) {
+ printf("nfs_link_async failed\n");
+ return -1;
+ }
+
+ wait_for_reply(nfs, &cb_data);
+
+ return cb_data.status;
+}
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+/*
+ * High level api to nfs filesystems
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <utime.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "libnfs.h"
+#include "libnfs-raw.h"
+#include "libnfs-raw-mount.h"
+#include "libnfs-raw-nfs.h"
+
+struct nfsfh {
+ struct nfs_fh3 fh;
+ int is_sync;
+ off_t offset;
+};
+
+struct nfsdir {
+ struct nfsdirent *entries;
+ struct nfsdirent *current;
+};
+
+void nfs_free_nfsdir(struct nfsdir *nfsdir)
+{
+ while (nfsdir->entries) {
+ struct nfsdirent *dirent = nfsdir->entries->next;
+ if (nfsdir->entries->name != NULL) {
+ free(nfsdir->entries->name);
+ }
+ free(nfsdir->entries);
+ nfsdir->entries = dirent;
+ }
+ free(nfsdir);
+}
+
+struct nfs_context {
+ struct rpc_context *rpc;
+ char *server;
+ char *export;
+ struct nfs_fh3 rootfh;
+};
+
+struct nfs_cb_data;
+typedef int (*continue_func)(struct nfs_context *nfs, struct nfs_cb_data *data);
+
+struct nfs_cb_data {
+ struct nfs_context *nfs;
+ struct nfsfh *nfsfh;
+ char *saved_path, *path;
+
+ nfs_cb cb;
+ void *private_data;
+
+ continue_func continue_cb;
+ void *continue_data;
+ void (*free_continue_data)(void *);
+ int continue_int;
+
+ struct nfs_fh3 fh;
+};
+
+static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh);
+
+
+void nfs_set_auth(struct nfs_context *nfs, struct AUTH *auth)
+{
+ return rpc_set_auth(nfs->rpc, auth);
+}
+
+int nfs_get_fd(struct nfs_context *nfs)
+{
+ return rpc_get_fd(nfs->rpc);
+}
+
+int nfs_which_events(struct nfs_context *nfs)
+{
+ return rpc_which_events(nfs->rpc);
+}
+
+int nfs_service(struct nfs_context *nfs, int revents)
+{
+ return rpc_service(nfs->rpc, revents);
+}
+
+char *nfs_get_error(struct nfs_context *nfs)
+{
+ return rpc_get_error(nfs->rpc);
+};
+
+struct nfs_context *nfs_init_context(void)
+{
+ struct nfs_context *nfs;
+
+ nfs = malloc(sizeof(struct nfs_context));
+ if (nfs == NULL) {
+ printf("Failed to allocate nfs context\n");
+ return NULL;
+ }
+ nfs->rpc = rpc_init_context();
+ if (nfs->rpc == NULL) {
+ printf("Failed to allocate rpc sub-context\n");
+ free(nfs);
+ return NULL;
+ }
+
+ return nfs;
+}
+
+void nfs_destroy_context(struct nfs_context *nfs)
+{
+ rpc_destroy_context(nfs->rpc);
+ nfs->rpc = NULL;
+
+ if (nfs->server) {
+ free(nfs->server);
+ nfs->server = NULL;
+ }
+
+ if (nfs->export) {
+ free(nfs->export);
+ nfs->export = NULL;
+ }
+
+ if (nfs->rootfh.data.data_val != NULL) {
+ free(nfs->rootfh.data.data_val);
+ nfs->rootfh.data.data_val = NULL;
+ }
+
+ free(nfs);
+}
+
+void free_nfs_cb_data(struct nfs_cb_data *data)
+{
+ if (data->saved_path != NULL) {
+ free(data->saved_path);
+ data->saved_path = NULL;
+ }
+
+ if (data->continue_data != NULL) {
+ data->free_continue_data(data->continue_data);
+ data->continue_data = NULL;
+ }
+
+ if (data->fh.data.data_val != NULL) {
+ free(data->fh.data.data_val);
+ data->fh.data.data_val = NULL;
+ }
+
+ free(data);
+}
+
+
+
+
+
+static void nfs_mount_9_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+
+ 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static void nfs_mount_8_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;
+
+ 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_nfs_getattr_async(rpc, nfs_mount_9_cb, &nfs->rootfh, data) != 0) {
+ data->cb(-ENOMEM, nfs, command_data, data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+}
+
+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;
+
+ 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_nfs_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;
+ struct nfs_context *nfs = data->nfs;
+ mountres3 *res;
+
+ 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->fhs_status != MNT3_OK) {
+ rpc_set_error(rpc, "RPC error: Mount failed with error %s(%d) %s(%d)", mountstat3_to_str(res->fhs_status), res->fhs_status, strerror(-mountstat3_to_errno(res->fhs_status)), -mountstat3_to_errno(res->fhs_status));
+ data->cb(mountstat3_to_errno(res->fhs_status), nfs, rpc_get_error(rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+
+ nfs->rootfh.data.data_len = res->mountres3_u.mountinfo.fhandle.fhandle3_len;
+ nfs->rootfh.data.data_val = malloc(nfs->rootfh.data.data_len);
+ if (nfs->rootfh.data.data_val == NULL) {
+ rpc_set_error(rpc, "Out of memory. Could not allocate memory to store root filehandle");
+ data->cb(-ENOMEM, nfs, rpc_get_error(rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+ 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) {
+ data->cb(-ENOMEM, nfs, command_data, data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+}
+
+
+static void nfs_mount_5_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;
+
+ 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_mount_mnt_async(rpc, nfs_mount_6_cb, nfs->export, data) != 0) {
+ data->cb(-ENOMEM, nfs, command_data, data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+}
+
+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;
+
+ 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_mount_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;
+
+ 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;
+
+ 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, 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;
+
+ 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
+ */
+int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *export, nfs_cb cb, void *private_data)
+{
+ struct nfs_cb_data *data;
+
+ data = malloc(sizeof(struct nfs_cb_data));
+ if (data == NULL) {
+ rpc_set_error(nfs->rpc, "out of memory");
+ printf("failed to allocate memory for nfs mount data\n");
+ return -1;
+ }
+ bzero(data, sizeof(struct nfs_cb_data));
+ nfs->server = strdup(server);
+ nfs->export = strdup(export);
+ data->nfs = nfs;
+ data->cb = cb;
+ data->private_data = private_data;
+
+ if (rpc_connect_async(nfs->rpc, server, 111, nfs_mount_1_cb, data) != 0) {
+ printf("Failed to start connection\n");
+ free_nfs_cb_data(data);
+ return -4;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Functions to first look up a path, component by component, and then finally call a specific function once
+ * the filehandle for the final component is found.
+ */
+static void nfs_lookup_path_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ LOOKUP3res *res;
+
+ 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: Lookup 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;
+ }
+
+ 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;
+ }
+}
+
+static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh)
+{
+ char *path, *str;
+
+ while (*data->path == '/') {
+ data->path++;
+ }
+
+ path = data->path;
+ str = index(path, '/');
+ if (str != NULL) {
+ *str = 0;
+ data->path = str+1;
+ } else {
+ while (*data->path != 0) {
+ data->path++;
+ }
+ }
+
+ if (*path == 0) {
+ data->fh.data.data_len = fh->data.data_len;
+ data->fh.data.data_val = malloc(data->fh.data.data_len);
+ if (data->fh.data.data_val == NULL) {
+ rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ memcpy(data->fh.data.data_val, fh->data.data_val, data->fh.data.data_len);
+ data->continue_cb(nfs, data);
+ return 0;
+ }
+
+ if (rpc_nfs_lookup_async(nfs->rpc, nfs_lookup_path_1_cb, fh, path, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send lookup call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+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;
+
+ if (path[0] != '/') {
+ rpc_set_error(nfs->rpc, "Pathname is not absulute %s", path);
+ return -1;
+ }
+
+ 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");
+ printf("failed to allocate memory for nfs cb data\n");
+ free_nfs_cb_data(data);
+ return -2;
+ }
+ bzero(data, sizeof(struct nfs_cb_data));
+ data->nfs = nfs;
+ data->cb = cb;
+ data->continue_cb = continue_cb;
+ data->continue_data = continue_data;
+ data->free_continue_data = free_continue_data;
+ data->continue_int = continue_int;
+ data->private_data = private_data;
+ data->saved_path = strdup(path);
+ if (data->saved_path == NULL) {
+ rpc_set_error(nfs->rpc, "out of memory: failed to copy path string");
+ printf("failed to allocate memory for path string\n");
+ free_nfs_cb_data(data);
+ return -2;
+ }
+ data->path = data->saved_path;
+
+ if (nfs_lookup_path_async_internal(nfs, data, &nfs->rootfh) != 0) {
+ printf("failed to lookup path\n");
+ /* return 0 here since the callback will be invoked if there is a failure */
+ return 0;
+ }
+ return 0;
+}
+
+
+
+
+
+/*
+ * Async stat()
+ */
+static void nfs_stat_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ GETATTR3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ struct stat st;
+
+ 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;
+ }
+
+ st.st_dev = -1;
+ st.st_ino = res->GETATTR3res_u.resok.obj_attributes.fileid;
+ st.st_mode = res->GETATTR3res_u.resok.obj_attributes.mode;
+ st.st_nlink = res->GETATTR3res_u.resok.obj_attributes.nlink;
+ st.st_uid = res->GETATTR3res_u.resok.obj_attributes.uid;
+ st.st_gid = res->GETATTR3res_u.resok.obj_attributes.gid;
+ st.st_rdev = 0;
+ st.st_size = res->GETATTR3res_u.resok.obj_attributes.size;
+ st.st_blksize = 4096;
+ st.st_blocks = res->GETATTR3res_u.resok.obj_attributes.size / 4096;
+ st.st_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds;
+ st.st_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds;
+ st.st_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds;
+
+ data->cb(0, nfs, &st, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_stat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ if (rpc_nfs_getattr_async(nfs->rpc, nfs_stat_1_cb, &data->fh, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_stat_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
+{
+ if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_stat_continue_internal, NULL, NULL, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Async open()
+ */
+static void nfs_open_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ ACCESS3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ struct nfsfh *nfsfh;
+ unsigned int nfsmode = 0;
+
+ 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: ACCESS 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;
+ }
+
+ if (data->continue_int & O_WRONLY) {
+ nfsmode |= ACCESS3_MODIFY;
+ }
+ if (data->continue_int & O_RDWR) {
+ nfsmode |= ACCESS3_READ|ACCESS3_MODIFY;
+ }
+ if (!(data->continue_int & (O_WRONLY|O_RDWR))) {
+ nfsmode |= ACCESS3_READ;
+ }
+
+
+ if (res->ACCESS3res_u.resok.access != nfsmode) {
+ rpc_set_error(nfs->rpc, "NFS: ACCESS denied. Required access %c%c%c. Allowed access %c%c%c",
+ nfsmode&ACCESS3_READ?'r':'-',
+ nfsmode&ACCESS3_MODIFY?'w':'-',
+ nfsmode&ACCESS3_EXECUTE?'x':'-',
+ res->ACCESS3res_u.resok.access&ACCESS3_READ?'r':'-',
+ res->ACCESS3res_u.resok.access&ACCESS3_MODIFY?'w':'-',
+ res->ACCESS3res_u.resok.access&ACCESS3_EXECUTE?'x':'-');
+ data->cb(-EACCES, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+
+ nfsfh = malloc(sizeof(struct nfsfh));
+ if (nfsfh == NULL) {
+ rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+ bzero(nfsfh, sizeof(struct nfsfh));
+
+ if (data->continue_int & O_SYNC) {
+ nfsfh->is_sync = 1;
+ }
+
+ /* steal the filehandle */
+ nfsfh->fh.data.data_len = data->fh.data.data_len;
+ nfsfh->fh.data.data_val = data->fh.data.data_val;
+ data->fh.data.data_val = NULL;
+
+ data->cb(0, nfs, nfsfh, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_open_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ int nfsmode = 0;
+
+ if (data->continue_int & O_WRONLY) {
+ nfsmode |= ACCESS3_MODIFY;
+ }
+ if (data->continue_int & O_RDWR) {
+ nfsmode |= ACCESS3_READ|ACCESS3_MODIFY;
+ }
+ if (!(data->continue_int & (O_WRONLY|O_RDWR))) {
+ nfsmode |= ACCESS3_READ;
+ }
+
+ if (rpc_nfs_access_async(nfs->rpc, nfs_open_cb, &data->fh, nfsmode, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_open_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
+{
+ if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_open_continue_internal, NULL, NULL, mode) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -2;
+ }
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Async pread()
+ */
+static void nfs_pread_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ READ3res *res;
+
+ 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: Read 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;
+ }
+
+ data->nfsfh->offset += res->READ3res_u.resok.count;
+ data->cb(res->READ3res_u.resok.count, nfs, res->READ3res_u.resok.data.data_val, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, nfs_cb cb, void *private_data)
+{
+ 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");
+ printf("failed to allocate memory for nfs cb data\n");
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ bzero(data, sizeof(struct nfs_cb_data));
+ data->nfs = nfs;
+ data->cb = cb;
+ data->private_data = private_data;
+ data->nfsfh = nfsfh;
+
+ nfsfh->offset = offset;
+ if (rpc_nfs_read_async(nfs->rpc, nfs_pread_cb, &nfsfh->fh, offset, count, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Async read()
+ */
+int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, nfs_cb cb, void *private_data)
+{
+ return nfs_pread_async(nfs, nfsfh, nfsfh->offset, count, cb, private_data);
+}
+
+
+
+/*
+ * Async pwrite()
+ */
+static void nfs_pwrite_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ WRITE3res *res;
+
+ 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: Write 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;
+ }
+
+ data->nfsfh->offset += res->WRITE3res_u.resok.count;
+ data->cb(res->WRITE3res_u.resok.count, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buf, nfs_cb cb, void *private_data)
+{
+ 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");
+ printf("failed to allocate memory for nfs cb data\n");
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ bzero(data, sizeof(struct nfs_cb_data));
+ data->nfs = nfs;
+ data->cb = cb;
+ data->private_data = private_data;
+ data->nfsfh = nfsfh;
+
+ nfsfh->offset = offset;
+ if (rpc_nfs_write_async(nfs->rpc, nfs_pwrite_cb, &nfsfh->fh, buf, offset, count, nfsfh->is_sync?FILE_SYNC:UNSTABLE, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Async write()
+ */
+int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buf, nfs_cb cb, void *private_data)
+{
+ return nfs_pwrite_async(nfs, nfsfh, nfsfh->offset, count, buf, cb, private_data);
+}
+
+
+
+
+/*
+ * close
+ */
+
+int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
+{
+ if (nfsfh->fh.data.data_val != NULL){
+ free(nfsfh->fh.data.data_val);
+ nfsfh->fh.data.data_val = NULL;
+ }
+ free(nfsfh);
+
+ cb(0, nfs, NULL, private_data);
+ return 0;
+};
+
+
+
+
+
+/*
+ * Async fstat()
+ */
+int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
+{
+ 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");
+ printf("failed to allocate memory for nfs cb data\n");
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ bzero(data, sizeof(struct nfs_cb_data));
+ data->nfs = nfs;
+ data->cb = cb;
+ data->private_data = private_data;
+
+ if (rpc_nfs_getattr_async(nfs->rpc, nfs_stat_1_cb, &nfsfh->fh, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+
+
+/*
+ * Async fsync()
+ */
+static void nfs_fsync_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ COMMIT3res *res;
+
+ 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: Commit 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+int nfs_fsync_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
+{
+ 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");
+ printf("failed to allocate memory for nfs cb data\n");
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ bzero(data, sizeof(struct nfs_cb_data));
+ data->nfs = nfs;
+ data->cb = cb;
+ data->private_data = private_data;
+
+ if (rpc_nfs_commit_async(nfs->rpc, nfs_fsync_cb, &nfsfh->fh, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send COMMIT call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+
+
+
+/*
+ * Async ftruncate()
+ */
+static void nfs_ftruncate_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ SETATTR3res *res;
+
+ 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: Setattr 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t length, nfs_cb cb, void *private_data)
+{
+ struct nfs_cb_data *data;
+ SETATTR3args args;
+
+ 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");
+ printf("failed to allocate memory for nfs cb data\n");
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ bzero(data, sizeof(struct nfs_cb_data));
+ data->nfs = nfs;
+ data->cb = cb;
+ data->private_data = private_data;
+
+ bzero(&args, sizeof(SETATTR3args));
+ args.object.data.data_len = nfsfh->fh.data.data_len;
+ args.object.data.data_val = nfsfh->fh.data.data_val;
+ args.new_attributes.size.set_it = 1;
+ args.new_attributes.size.set_size3_u.size = length;
+
+ if (rpc_nfs_setattr_async(nfs->rpc, nfs_ftruncate_cb, &args, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ * Async truncate()
+ */
+static int nfs_truncate_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ off_t offset = data->continue_int;
+ struct nfsfh nfsfh;
+
+ nfsfh.fh.data.data_val = data->fh.data.data_val;
+ nfsfh.fh.data.data_len = data->fh.data.data_len;
+
+ if (nfs_ftruncate_async(nfs, &nfsfh, offset, data->cb, data->private_data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ free_nfs_cb_data(data);
+ return 0;
+}
+
+int nfs_truncate_async(struct nfs_context *nfs, const char *path, off_t length, nfs_cb cb, void *private_data)
+{
+ off_t offset;
+
+ offset = length;
+
+ if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_truncate_continue_internal, NULL, NULL, offset) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -2;
+ }
+
+ return 0;
+}
+
+
+
+
+/*
+ * Async mkdir()
+ */
+static void nfs_mkdir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ MKDIR3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ char *str = data->continue_data;
+
+ str = &str[strlen(str) + 1];
+
+ 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: MKDIR of %s/%s failed with %s(%d)", data->saved_path, str, 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_mkdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ char *str = data->continue_data;
+
+ str = &str[strlen(str) + 1];
+
+ if (rpc_nfs_mkdir_async(nfs->rpc, nfs_mkdir_cb, &data->fh, str, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send MKDIR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
+{
+ char *new_path;
+ char *ptr;
+
+ new_path = strdup(path);
+ if (new_path == NULL) {
+ printf("Out of memory, failed to allocate mode buffer for path\n");
+ return -1;
+ }
+
+ ptr = rindex(new_path, '/');
+ if (ptr == NULL) {
+ printf("Invalid path %s\n", path);
+ return -2;
+ }
+ *ptr = 0;
+
+ /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
+ if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_mkdir_continue_internal, new_path, free, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Async rmdir()
+ */
+static void nfs_rmdir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ RMDIR3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ char *str = data->continue_data;
+
+ str = &str[strlen(str) + 1];
+
+ 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: RMDIR of %s/%s failed with %s(%d)", data->saved_path, str, 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_rmdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ char *str = data->continue_data;
+
+ str = &str[strlen(str) + 1];
+
+ if (rpc_nfs_rmdir_async(nfs->rpc, nfs_rmdir_cb, &data->fh, str, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send RMDIR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_rmdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
+{
+ char *new_path;
+ char *ptr;
+
+ new_path = strdup(path);
+ if (new_path == NULL) {
+ printf("Out of memory, failed to allocate mode buffer for path\n");
+ return -1;
+ }
+
+ ptr = rindex(new_path, '/');
+ if (ptr == NULL) {
+ printf("Invalid path %s\n", path);
+ return -2;
+ }
+ *ptr = 0;
+
+ /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
+ if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_rmdir_continue_internal, new_path, free, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+
+/*
+ * Async creat()
+ */
+static void nfs_create_2_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ LOOKUP3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ struct nfsfh *nfsfh;
+ char *str = data->continue_data;
+
+ 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;
+ }
+
+ str = &str[strlen(str) + 1];
+ res = command_data;
+ if (res->status != NFS3_OK) {
+ rpc_set_error(nfs->rpc, "NFS: CREATE of %s/%s failed with %s(%d)", data->saved_path, str, 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);
+
+ return;
+ }
+
+ nfsfh = malloc(sizeof(struct nfsfh));
+ if (nfsfh == NULL) {
+ rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+ bzero(nfsfh, sizeof(struct nfsfh));
+
+ /* steal the filehandle */
+ nfsfh->fh.data.data_len = data->fh.data.data_len;
+ nfsfh->fh.data.data_val = data->fh.data.data_val;
+ data->fh.data.data_val = NULL;
+
+ data->cb(0, nfs, nfsfh, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+
+
+static void nfs_creat_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ CREATE3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ char *str = data->continue_data;
+
+ 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;
+ }
+
+ str = &str[strlen(str) + 1];
+ res = command_data;
+ if (res->status != NFS3_OK) {
+ rpc_set_error(nfs->rpc, "NFS: CREATE of %s/%s failed with %s(%d)", data->saved_path, str, 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);
+
+ return;
+ }
+
+ if (rpc_nfs_lookup_async(nfs->rpc, nfs_create_2_cb, &data->fh, str, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send lookup call for %s/%s", data->saved_path, str);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+ return;
+}
+
+static int nfs_creat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ char *str = data->continue_data;
+
+ str = &str[strlen(str) + 1];
+
+ if (rpc_nfs_create_async(nfs->rpc, nfs_creat_1_cb, &data->fh, str, data->continue_int, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send CREATE call for %s/%s", data->path, str);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
+{
+ char *new_path;
+ char *ptr;
+
+ new_path = strdup(path);
+ if (new_path == NULL) {
+ printf("Out of memory, failed to allocate mode buffer for path\n");
+ return -1;
+ }
+
+ ptr = rindex(new_path, '/');
+ if (ptr == NULL) {
+ printf("Invalid path %s\n", path);
+ return -2;
+ }
+ *ptr = 0;
+
+ /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
+ if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_creat_continue_internal, new_path, free, mode) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+
+/*
+ * Async unlink()
+ */
+static void nfs_unlink_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ REMOVE3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ char *str = data->continue_data;
+
+ str = &str[strlen(str) + 1];
+
+ 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: REMOVE of %s/%s failed with %s(%d)", data->saved_path, str, 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_unlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ char *str = data->continue_data;
+
+ str = &str[strlen(str) + 1];
+
+ if (rpc_nfs_remove_async(nfs->rpc, nfs_unlink_cb, &data->fh, str, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send REMOVE call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
+{
+ char *new_path;
+ char *ptr;
+
+ new_path = strdup(path);
+ if (new_path == NULL) {
+ printf("Out of memory, failed to allocate mode buffer for path\n");
+ return -1;
+ }
+
+ ptr = rindex(new_path, '/');
+ if (ptr == NULL) {
+ printf("Invalid path %s\n", path);
+ return -2;
+ }
+ *ptr = 0;
+
+ /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
+ if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_unlink_continue_internal, new_path, free, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Async opendir()
+ */
+static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ READDIR3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ struct nfsdir *nfsdir = data->continue_data;;
+ struct entry3 *entry;
+ uint64_t cookie;
+
+ if (status == RPC_STATUS_ERROR) {
+ data->cb(-EFAULT, nfs, command_data, data->private_data);
+ nfs_free_nfsdir(nfsdir);
+ data->continue_data = NULL;
+ free_nfs_cb_data(data);
+ return;
+ }
+ if (status == RPC_STATUS_CANCEL) {
+ data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
+ nfs_free_nfsdir(nfsdir);
+ data->continue_data = NULL;
+ free_nfs_cb_data(data);
+ return;
+ }
+
+ res = command_data;
+ if (res->status != NFS3_OK) {
+ rpc_set_error(nfs->rpc, "NFS: READDIR 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);
+ nfs_free_nfsdir(nfsdir);
+ data->continue_data = NULL;
+ free_nfs_cb_data(data);
+ return;
+ }
+
+ entry =res->READDIR3res_u.resok.reply.entries;
+ while (entry != NULL) {
+ struct nfsdirent *nfsdirent;
+
+ nfsdirent = malloc(sizeof(struct nfsdirent));
+ if (nfsdirent == NULL) {
+ data->cb(-ENOMEM, nfs, "Failed to allocate dirent", data->private_data);
+ nfs_free_nfsdir(nfsdir);
+ data->continue_data = NULL;
+ free_nfs_cb_data(data);
+ return;
+ }
+ bzero(nfsdirent, sizeof(struct nfsdirent));
+ nfsdirent->name = strdup(entry->name);
+ if (nfsdirent->name == NULL) {
+ data->cb(-ENOMEM, nfs, "Failed to allocate dirent->name", data->private_data);
+ nfs_free_nfsdir(nfsdir);
+ data->continue_data = NULL;
+ free_nfs_cb_data(data);
+ return;
+ }
+ nfsdirent->inode = entry->fileid;
+ nfsdirent->next = nfsdir->entries;
+ nfsdir->entries = nfsdirent;
+
+ cookie = entry->cookie;
+ entry = entry->nextentry;
+ }
+
+ if (res->READDIR3res_u.resok.reply.eof == 0) {
+ if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir_cb, &data->fh, cookie, res->READDIR3res_u.resok.cookieverf, 20000, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path);
+ 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);
+ return;
+ }
+ return;
+ }
+
+ /* steal the dirhandle */
+ data->continue_data = NULL;
+ nfsdir->current = nfsdir->entries;
+
+ data->cb(0, nfs, nfsdir, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_opendir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ cookieverf3 cv;
+
+ bzero(cv, sizeof(cookieverf3));
+ if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir_cb, &data->fh, 0, (char *)&cv, 20000, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_opendir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
+{
+ struct nfsdir *nfsdir;
+
+ nfsdir = malloc(sizeof(struct nfsdir));
+ if (nfsdir == NULL) {
+ printf("failed to allocate buffer for nfsdir\n");
+ return -1;
+ }
+ bzero(nfsdir, sizeof(struct nfsdir));
+
+ if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_opendir_continue_internal, nfsdir, free, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -2;
+ }
+
+ return 0;
+}
+
+
+struct nfsdirent *nfs_readdir(struct nfs_context *nfs _U_, struct nfsdir *nfsdir)
+{
+ struct nfsdirent *nfsdirent = nfsdir->current;
+
+ if (nfsdir->current != NULL) {
+ nfsdir->current = nfsdir->current->next;
+ }
+ return nfsdirent;
+}
+
+
+void nfs_closedir(struct nfs_context *nfs _U_, struct nfsdir *nfsdir)
+{
+ nfs_free_nfsdir(nfsdir);
+}
+
+
+
+
+
+
+
+/*
+ * Async lseek()
+ */
+struct lseek_cb_data {
+ struct nfs_context *nfs;
+ struct nfsfh *nfsfh;
+ off_t offset;
+ nfs_cb cb;
+ void *private_data;
+};
+
+static void nfs_lseek_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ GETATTR3res *res;
+ struct lseek_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+
+ if (status == RPC_STATUS_ERROR) {
+ data->cb(-EFAULT, nfs, command_data, data->private_data);
+ free(data);
+ return;
+ }
+ if (status == RPC_STATUS_CANCEL) {
+ data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
+ free(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(data);
+ return;
+ }
+
+ data->nfsfh->offset = data->offset + res->GETATTR3res_u.resok.obj_attributes.size;
+ data->cb(0, nfs, &data->nfsfh->offset, data->private_data);
+ free(data);
+}
+
+int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, int whence, nfs_cb cb, void *private_data)
+{
+ struct lseek_cb_data *data;
+
+ if (whence == SEEK_SET) {
+ 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);
+ return 0;
+ }
+
+ data = malloc(sizeof(struct lseek_cb_data));
+ if (data == NULL) {
+ rpc_set_error(nfs->rpc, "Out Of Memory: Failed to malloc lseek cb data");
+ return -1;
+ }
+
+ data->nfs = nfs;
+ data->nfsfh = nfsfh;
+ data->offset = offset;
+ data->cb = cb;
+ data->private_data = private_data;
+
+ if (rpc_nfs_getattr_async(nfs->rpc, nfs_lseek_1_cb, &nfsfh->fh, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send LSEEK GETATTR call");
+ free(data);
+ return -2;
+ }
+ return 0;
+}
+
+
+
+
+/*
+ * Async statvfs()
+ */
+static void nfs_statvfs_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ FSSTAT3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ struct statvfs svfs;
+
+ 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: FSSTAT 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;
+ }
+
+ 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_files = res->FSSTAT3res_u.resok.tfiles;
+ svfs.f_ffree = res->FSSTAT3res_u.resok.ffiles;
+ svfs.f_favail = res->FSSTAT3res_u.resok.afiles;
+ svfs.f_fsid = 0;
+ svfs.f_flag = 0;
+ svfs.f_namemax = 256;
+
+ data->cb(0, nfs, &svfs, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_statvfs_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ if (rpc_nfs_fsstat_async(nfs->rpc, nfs_statvfs_1_cb, &data->fh, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send FSSTAT call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
+{
+ if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_statvfs_continue_internal, NULL, NULL, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+/*
+ * Async readlink()
+ */
+static void nfs_readlink_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ READLINK3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+
+ 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: READLINK 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;
+ }
+
+
+ data->cb(0, nfs, res->READLINK3res_u.resok.data, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_readlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ if (rpc_nfs_readlink_async(nfs->rpc, nfs_readlink_1_cb, &data->fh, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send READLINK call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_readlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
+{
+ if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_readlink_continue_internal, NULL, NULL, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+/*
+ * Async chmod()
+ */
+static void nfs_chmod_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ SETATTR3res *res;
+
+ 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: SETATTR 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_chmod_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ SETATTR3args args;
+
+ bzero(&args, sizeof(SETATTR3args));
+ args.object.data.data_len = data->fh.data.data_len;
+ args.object.data.data_val = data->fh.data.data_val;
+ args.new_attributes.mode.set_it = 1;
+ args.new_attributes.mode.set_mode3_u.mode = data->continue_int;
+
+ if (rpc_nfs_setattr_async(nfs->rpc, nfs_chmod_cb, &args, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+
+int nfs_chmod_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
+{
+ if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chmod_continue_internal, NULL, NULL, mode) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Async fchmod()
+ */
+int nfs_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode, nfs_cb cb, void *private_data)
+{
+ struct nfs_cb_data *data;
+
+ data = malloc(sizeof(struct nfs_cb_data));
+ if (data == NULL) {
+ rpc_set_error(nfs->rpc, "out of memory");
+ printf("failed to allocate memory for nfs mount data\n");
+ return -1;
+ }
+ bzero(data, sizeof(struct nfs_cb_data));
+ data->nfs = nfs;
+ data->cb = cb;
+ data->private_data = private_data;
+ data->continue_int = mode;
+ data->fh.data.data_len = nfsfh->fh.data.data_len;
+ data->fh.data.data_val = malloc(data->fh.data.data_len);
+ if (data->fh.data.data_val == NULL) {
+ rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh");
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
+
+ if (nfs_chmod_continue_internal(nfs, data) != 0) {
+ free_nfs_cb_data(data);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Async chown()
+ */
+static void nfs_chown_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ SETATTR3res *res;
+
+ 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: SETATTR 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+struct nfs_chown_data {
+ uid_t uid;
+ gid_t gid;
+};
+
+static int nfs_chown_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ SETATTR3args args;
+ struct nfs_chown_data *chown_data = data->continue_data;
+
+ bzero(&args, sizeof(SETATTR3args));
+ args.object.data.data_len = data->fh.data.data_len;
+ args.object.data.data_val = data->fh.data.data_val;
+ if (chown_data->uid != (uid_t)-1) {
+ args.new_attributes.uid.set_it = 1;
+ args.new_attributes.uid.set_uid3_u.uid = chown_data->uid;
+ }
+ if (chown_data->gid != (gid_t)-1) {
+ args.new_attributes.gid.set_it = 1;
+ args.new_attributes.gid.set_gid3_u.gid = chown_data->gid;
+ }
+
+ if (rpc_nfs_setattr_async(nfs->rpc, nfs_chown_cb, &args, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+
+int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, int gid, nfs_cb cb, void *private_data)
+{
+ struct nfs_chown_data *chown_data;
+
+ chown_data = malloc(sizeof(struct nfs_chown_data));
+ if (chown_data == NULL) {
+ printf("Failed to allocate memory for chown data structure\n");
+ return -1;
+ }
+
+ chown_data->uid = uid;
+ chown_data->gid = gid;
+
+ if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chown_continue_internal, chown_data, free, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Async fchown()
+ */
+int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int gid, nfs_cb cb, void *private_data)
+{
+ struct nfs_cb_data *data;
+ struct nfs_chown_data *chown_data;
+
+ chown_data = malloc(sizeof(struct nfs_chown_data));
+ if (chown_data == NULL) {
+ printf("Failed to allocate memory for chown data structure\n");
+ return -1;
+ }
+
+ chown_data->uid = uid;
+ chown_data->gid = gid;
+
+
+ data = malloc(sizeof(struct nfs_cb_data));
+ if (data == NULL) {
+ rpc_set_error(nfs->rpc, "out of memory");
+ printf("failed to allocate memory for fchown data\n");
+ return -1;
+ }
+ bzero(data, sizeof(struct nfs_cb_data));
+ data->nfs = nfs;
+ data->cb = cb;
+ data->private_data = private_data;
+ data->continue_data = chown_data;
+ data->fh.data.data_len = nfsfh->fh.data.data_len;
+ data->fh.data.data_val = malloc(data->fh.data.data_len);
+ if (data->fh.data.data_val == NULL) {
+ rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh");
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
+
+
+ if (nfs_chown_continue_internal(nfs, data) != 0) {
+ free_nfs_cb_data(data);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Async utimes()
+ */
+static void nfs_utimes_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ SETATTR3res *res;
+
+ 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: SETATTR 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_utimes_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ SETATTR3args args;
+ struct timeval *utimes_data = data->continue_data;
+
+ bzero(&args, sizeof(SETATTR3args));
+ args.object.data.data_len = data->fh.data.data_len;
+ args.object.data.data_val = data->fh.data.data_val;
+ if (utimes_data != NULL) {
+ args.new_attributes.atime.set_it = SET_TO_CLIENT_TIME;
+ args.new_attributes.atime.set_atime_u.atime.seconds = utimes_data[0].tv_sec;
+ args.new_attributes.atime.set_atime_u.atime.nseconds = utimes_data[0].tv_usec * 1000;
+ args.new_attributes.mtime.set_it = SET_TO_CLIENT_TIME;
+ args.new_attributes.mtime.set_mtime_u.mtime.seconds = utimes_data[1].tv_sec;
+ args.new_attributes.mtime.set_mtime_u.mtime.nseconds = utimes_data[1].tv_usec * 1000;
+ } else {
+ args.new_attributes.atime.set_it = SET_TO_SERVER_TIME;
+ args.new_attributes.mtime.set_it = SET_TO_SERVER_TIME;
+ }
+
+ if (rpc_nfs_setattr_async(nfs->rpc, nfs_utimes_cb, &args, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+
+int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct timeval *times, nfs_cb cb, void *private_data)
+{
+ struct timeval *new_times = NULL;
+
+ if (times != NULL) {
+ new_times = malloc(sizeof(struct timeval)*2);
+ if (new_times == NULL) {
+ printf("Failed to allocate memory for timeval structure\n");
+ return -1;
+ }
+
+ memcpy(new_times, times, sizeof(struct timeval)*2);
+ }
+
+ if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Async utime()
+ */
+int nfs_utime_async(struct nfs_context *nfs, const char *path, struct utimbuf *times, nfs_cb cb, void *private_data)
+{
+ struct timeval *new_times = NULL;
+
+ if (times != NULL) {
+ new_times = malloc(sizeof(struct timeval)*2);
+ if (new_times == NULL) {
+ printf("Failed to allocate memory for timeval structure\n");
+ return -1;
+ }
+
+ new_times[0].tv_sec = times->actime;
+ new_times[0].tv_usec = 0;
+ new_times[1].tv_sec = times->modtime;
+ new_times[1].tv_usec = 0;
+ }
+
+ if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Async access()
+ */
+static void nfs_access_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ ACCESS3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ unsigned int nfsmode = 0;
+
+ 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: ACCESS 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;
+ }
+
+ if (data->continue_int & R_OK) {
+ nfsmode |= ACCESS3_READ;
+ }
+ if (data->continue_int & W_OK) {
+ nfsmode |= ACCESS3_MODIFY;
+ }
+ if (data->continue_int & X_OK) {
+ nfsmode |= ACCESS3_EXECUTE;
+ }
+
+ if (res->ACCESS3res_u.resok.access != nfsmode) {
+ rpc_set_error(nfs->rpc, "NFS: ACCESS denied. Required access %c%c%c. Allowed access %c%c%c",
+ nfsmode&ACCESS3_READ?'r':'-',
+ nfsmode&ACCESS3_MODIFY?'w':'-',
+ nfsmode&ACCESS3_EXECUTE?'x':'-',
+ res->ACCESS3res_u.resok.access&ACCESS3_READ?'r':'-',
+ res->ACCESS3res_u.resok.access&ACCESS3_MODIFY?'w':'-',
+ res->ACCESS3res_u.resok.access&ACCESS3_EXECUTE?'x':'-');
+ data->cb(-EACCES, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_access_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ int nfsmode = 0;
+
+ if (data->continue_int & R_OK) {
+ nfsmode |= ACCESS3_READ;
+ }
+ if (data->continue_int & W_OK) {
+ nfsmode |= ACCESS3_MODIFY;
+ }
+ if (data->continue_int & X_OK) {
+ nfsmode |= ACCESS3_EXECUTE;
+ }
+
+ if (rpc_nfs_access_async(nfs->rpc, nfs_access_cb, &data->fh, nfsmode, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_access_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
+{
+ if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_access_continue_internal, NULL, NULL, mode) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -2;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Async symlink()
+ */
+struct nfs_symlink_data {
+ char *oldpath;
+ char *newpathparent;
+ char *newpathobject;
+};
+
+static void free_nfs_symlink_data(void *mem)
+{
+ struct nfs_symlink_data *data = mem;
+
+ if (data->oldpath != NULL) {
+ free(data->oldpath);
+ }
+ if (data->newpathparent != NULL) {
+ free(data->newpathparent);
+ }
+ if (data->newpathobject != NULL) {
+ free(data->newpathobject);
+ }
+ free(data);
+}
+
+static void nfs_symlink_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ SYMLINK3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ struct nfs_symlink_data *symlink_data = data->continue_data;
+
+ 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: SYMLINK %s/%s -> %s failed with %s(%d)", symlink_data->newpathparent, symlink_data->newpathobject, symlink_data->oldpath, 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_symlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ struct nfs_symlink_data *symlink_data = data->continue_data;
+
+ if (rpc_nfs_symlink_async(nfs->rpc, nfs_symlink_cb, &data->fh, symlink_data->newpathobject, symlink_data->oldpath, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send SYMLINK call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_symlink_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
+{
+ char *ptr;
+ struct nfs_symlink_data *symlink_data;
+
+ symlink_data = malloc(sizeof(struct nfs_symlink_data));
+ if (symlink_data == NULL) {
+ printf("Out of memory, failed to allocate buffer for symlink data\n");
+ return -1;
+ }
+ bzero(symlink_data, sizeof(struct nfs_symlink_data));
+
+ symlink_data->oldpath = strdup(oldpath);
+ if (symlink_data->oldpath == NULL) {
+ printf("Out of memory, failed to allocate buffer for oldpath\n");
+ free_nfs_symlink_data(symlink_data);
+ return -2;
+ }
+
+ symlink_data->newpathparent = strdup(newpath);
+ if (symlink_data->newpathparent == NULL) {
+ printf("Out of memory, failed to allocate mode buffer for new path\n");
+ free_nfs_symlink_data(symlink_data);
+ return -3;
+ }
+
+ ptr = rindex(symlink_data->newpathparent, '/');
+ if (ptr == NULL) {
+ printf("Invalid path %s\n", oldpath);
+ free_nfs_symlink_data(symlink_data);
+ return -4;
+ }
+ *ptr = 0;
+ ptr++;
+
+ symlink_data->newpathobject = strdup(ptr);
+ if (symlink_data->newpathobject == NULL) {
+ printf("Out of memory, failed to allocate mode buffer for new path\n");
+ free_nfs_symlink_data(symlink_data);
+ return -5;
+ }
+
+ if (nfs_lookuppath_async(nfs, symlink_data->newpathparent, cb, private_data, nfs_symlink_continue_internal, symlink_data, free_nfs_symlink_data, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -6;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Async rename()
+ */
+struct nfs_rename_data {
+ char *oldpath;
+ char *oldobject;
+ struct nfs_fh3 olddir;
+ char *newpath;
+ char *newobject;
+ struct nfs_fh3 newdir;
+};
+
+static void free_nfs_rename_data(void *mem)
+{
+ struct nfs_rename_data *data = mem;
+
+ if (data->oldpath != NULL) {
+ free(data->oldpath);
+ }
+ if (data->olddir.data.data_val != NULL) {
+ free(data->olddir.data.data_val);
+ }
+ if (data->newpath != NULL) {
+ free(data->newpath);
+ }
+ if (data->newdir.data.data_val != NULL) {
+ free(data->newdir.data.data_val);
+ }
+ free(data);
+}
+
+static void nfs_rename_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ RENAME3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ struct nfs_rename_data *rename_data = data->continue_data;
+
+ 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: RENAME %s/%s -> %s/%s failed with %s(%d)", rename_data->oldpath, rename_data->oldobject, rename_data->newpath, rename_data->newobject, 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_rename_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ struct nfs_rename_data *rename_data = data->continue_data;
+
+ /* steal the filehandle */
+ rename_data->newdir.data.data_len = data->fh.data.data_len;
+ rename_data->newdir.data.data_val = data->fh.data.data_val;
+ data->fh.data.data_val = NULL;
+
+ if (rpc_nfs_rename_async(nfs->rpc, nfs_rename_cb, &rename_data->olddir, rename_data->oldobject, &rename_data->newdir, rename_data->newobject, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send RENAME call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int nfs_rename_continue_1_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ struct nfs_rename_data *rename_data = data->continue_data;
+
+ /* steal the filehandle */
+ rename_data->olddir.data.data_len = data->fh.data.data_len;
+ rename_data->olddir.data.data_val = data->fh.data.data_val;
+ data->fh.data.data_val = NULL;
+
+ if (nfs_lookuppath_async(nfs, rename_data->newpath, data->cb, data->private_data, nfs_rename_continue_2_internal, rename_data, free_nfs_rename_data, 0) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send LOOKUP call for %s", rename_data->newpath);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ data->continue_data = NULL;
+ free_nfs_cb_data(data);
+
+ return 0;
+}
+
+
+int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
+{
+ char *ptr;
+ struct nfs_rename_data *rename_data;
+
+ rename_data = malloc(sizeof(struct nfs_rename_data));
+ if (rename_data == NULL) {
+ printf("Out of memory, failed to allocate buffer for rename data\n");
+ return -1;
+ }
+ bzero(rename_data, sizeof(struct nfs_rename_data));
+
+ rename_data->oldpath = strdup(oldpath);
+ if (rename_data->oldpath == NULL) {
+ printf("Out of memory, failed to allocate buffer for oldpath\n");
+ free_nfs_rename_data(rename_data);
+ return -2;
+ }
+ ptr = rindex(rename_data->oldpath, '/');
+ if (ptr == NULL) {
+ printf("Invalid path %s\n", oldpath);
+ free_nfs_rename_data(rename_data);
+ return -3;
+ }
+ *ptr = 0;
+ ptr++;
+ rename_data->oldobject = ptr;
+
+
+ rename_data->newpath = strdup(newpath);
+ if (rename_data->newpath == NULL) {
+ printf("Out of memory, failed to allocate buffer for newpath\n");
+ free_nfs_rename_data(rename_data);
+ return -4;
+ }
+ ptr = rindex(rename_data->newpath, '/');
+ if (ptr == NULL) {
+ printf("Invalid path %s\n", newpath);
+ free_nfs_rename_data(rename_data);
+ return -5;
+ }
+ *ptr = 0;
+ ptr++;
+ rename_data->newobject = ptr;
+
+
+ if (nfs_lookuppath_async(nfs, rename_data->oldpath, cb, private_data, nfs_rename_continue_1_internal, rename_data, free_nfs_rename_data, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -6;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Async link()
+ */
+struct nfs_link_data {
+ char *oldpath;
+ struct nfs_fh3 oldfh;
+ char *newpath;
+ char *newobject;
+ struct nfs_fh3 newdir;
+};
+
+static void free_nfs_link_data(void *mem)
+{
+ struct nfs_link_data *data = mem;
+
+ if (data->oldpath != NULL) {
+ free(data->oldpath);
+ }
+ if (data->oldfh.data.data_val != NULL) {
+ free(data->oldfh.data.data_val);
+ }
+ if (data->newpath != NULL) {
+ free(data->newpath);
+ }
+ if (data->newdir.data.data_val != NULL) {
+ free(data->newdir.data.data_val);
+ }
+ free(data);
+}
+
+static void nfs_link_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+ LINK3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ struct nfs_link_data *link_data = data->continue_data;
+
+ 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: LINK %s -> %s/%s failed with %s(%d)", link_data->oldpath, link_data->newpath, link_data->newobject, 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;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_link_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ struct nfs_link_data *link_data = data->continue_data;
+
+ /* steal the filehandle */
+ link_data->newdir.data.data_len = data->fh.data.data_len;
+ link_data->newdir.data.data_val = data->fh.data.data_val;
+ data->fh.data.data_val = NULL;
+
+ if (rpc_nfs_link_async(nfs->rpc, nfs_link_cb, &link_data->oldfh, &link_data->newdir, link_data->newobject, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send LINK call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int nfs_link_continue_1_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+{
+ struct nfs_link_data *link_data = data->continue_data;
+
+ /* steal the filehandle */
+ link_data->oldfh.data.data_len = data->fh.data.data_len;
+ link_data->oldfh.data.data_val = data->fh.data.data_val;
+ data->fh.data.data_val = NULL;
+
+ if (nfs_lookuppath_async(nfs, link_data->newpath, data->cb, data->private_data, nfs_link_continue_2_internal, link_data, free_nfs_link_data, 0) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send LOOKUP call for %s", link_data->newpath);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ data->continue_data = NULL;
+ free_nfs_cb_data(data);
+
+ return 0;
+}
+
+
+int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
+{
+ char *ptr;
+ struct nfs_link_data *link_data;
+
+ link_data = malloc(sizeof(struct nfs_link_data));
+ if (link_data == NULL) {
+ printf("Out of memory, failed to allocate buffer for link data\n");
+ return -1;
+ }
+ bzero(link_data, sizeof(struct nfs_link_data));
+
+ link_data->oldpath = strdup(oldpath);
+ if (link_data->oldpath == NULL) {
+ printf("Out of memory, failed to allocate buffer for oldpath\n");
+ free_nfs_link_data(link_data);
+ return -2;
+ }
+
+ link_data->newpath = strdup(newpath);
+ if (link_data->newpath == NULL) {
+ printf("Out of memory, failed to allocate buffer for newpath\n");
+ free_nfs_link_data(link_data);
+ return -4;
+ }
+ ptr = rindex(link_data->newpath, '/');
+ if (ptr == NULL) {
+ printf("Invalid path %s\n", newpath);
+ free_nfs_link_data(link_data);
+ return -5;
+ }
+ *ptr = 0;
+ ptr++;
+ link_data->newobject = ptr;
+
+
+ if (nfs_lookuppath_async(nfs, link_data->oldpath, cb, private_data, nfs_link_continue_1_internal, link_data, free_nfs_link_data, 0) != 0) {
+ printf("Out of memory: failed to start parsing the path components\n");
+ return -6;
+ }
+
+ return 0;
+}
+
+
+//qqq replace later with lseek()
+off_t nfs_get_current_offset(struct nfsfh *nfsfh)
+{
+ return nfsfh->offset;
+}
+
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+
+#include <stdio.h>
+#include <strings.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc_msg.h>
+#include "slist.h"
+#include "libnfs.h"
+#include "libnfs-raw.h"
+#include "libnfs-private.h"
+
+struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, xdrproc_t xdr_decode_fn, int xdr_decode_bufsize)
+{
+ struct rpc_pdu *pdu;
+ struct rpc_msg msg;
+
+ if (rpc == NULL) {
+ printf("trying to allocate rpc pdu on NULL context\n");
+ return NULL;
+ }
+
+ pdu = malloc(sizeof(struct rpc_pdu));
+ if (pdu == NULL) {
+ printf("Failed to allocate pdu structure\n");
+ return NULL;
+ }
+ bzero(pdu, sizeof(struct rpc_pdu));
+ pdu->xid = rpc->xid++;
+ pdu->cb = cb;
+ pdu->private_data = private_data;
+ pdu->xdr_decode_fn = xdr_decode_fn;
+ pdu->xdr_decode_bufsize = xdr_decode_bufsize;
+
+ xdrmem_create(&pdu->xdr, rpc->encodebuf, rpc->encodebuflen, XDR_ENCODE);
+ xdr_setpos(&pdu->xdr, 4); /* skip past the record marker */
+
+ bzero(&msg, sizeof(struct rpc_msg));
+ msg.rm_xid = pdu->xid;
+ msg.rm_direction = CALL;
+ msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ msg.rm_call.cb_prog = program;
+ msg.rm_call.cb_vers = version;
+ msg.rm_call.cb_proc = procedure;
+ msg.rm_call.cb_cred = rpc->auth->ah_cred;
+ msg.rm_call.cb_verf = rpc->auth->ah_verf;
+
+ if (xdr_callmsg(&pdu->xdr, &msg) == 0) {
+ printf("xdr_callmsg failed\n");
+ xdr_destroy(&pdu->xdr);
+ free(pdu);
+ return NULL;
+ }
+
+ return pdu;
+}
+
+void rpc_free_pdu(struct rpc_context *rpc _U_, struct rpc_pdu *pdu)
+{
+ if (pdu->outdata.data != NULL) {
+ free(pdu->outdata.data);
+ pdu->outdata.data = NULL;
+ }
+
+ if (pdu->xdr_decode_buf != NULL) {
+ xdr_free(pdu->xdr_decode_fn, pdu->xdr_decode_buf);
+ free(pdu->xdr_decode_buf);
+ pdu->xdr_decode_buf = NULL;
+ }
+
+ xdr_destroy(&pdu->xdr);
+ free(pdu);
+}
+
+
+int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
+{
+ int size, recordmarker;
+
+ size = xdr_getpos(&pdu->xdr);
+
+ /* write recordmarker */
+ xdr_setpos(&pdu->xdr, 0);
+ recordmarker = (size - 4) | 0x80000000;
+ xdr_int(&pdu->xdr, &recordmarker);
+
+ pdu->outdata.size = size;
+ pdu->outdata.data = malloc(pdu->outdata.size);
+ if (pdu->outdata.data == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate buffer for pdu\n");
+ rpc_free_pdu(rpc, pdu);
+ return -1;
+ }
+
+ memcpy(pdu->outdata.data, rpc->encodebuf, pdu->outdata.size);
+ SLIST_ADD_END(&rpc->outqueue, pdu);
+
+ return 0;
+}
+
+int rpc_get_pdu_size(char *buf)
+{
+ uint32_t size;
+
+ size = ntohl(*(uint32_t *)buf);
+
+ if ((size & 0x80000000) == 0) {
+ printf("cant handle oncrpc fragments\n");
+ return -1;
+ }
+
+ return (size & 0x7fffffff) + 4;
+}
+
+static int rpc_process_reply(struct rpc_context *rpc, struct rpc_pdu *pdu, XDR *xdr)
+{
+ struct rpc_msg msg;
+
+ bzero(&msg, sizeof(struct rpc_msg));
+ msg.acpted_rply.ar_verf = _null_auth;
+ if (pdu->xdr_decode_bufsize > 0) {
+ pdu->xdr_decode_buf = malloc(pdu->xdr_decode_bufsize);
+ if (pdu->xdr_decode_buf == NULL) {
+ printf("xdr_replymsg failed in portmap_getport_reply\n");
+ pdu->cb(rpc, RPC_STATUS_ERROR, "Failed to allocate buffer for decoding of XDR reply", pdu->private_data);
+ return 0;
+ }
+ bzero(pdu->xdr_decode_buf, pdu->xdr_decode_bufsize);
+ }
+ msg.acpted_rply.ar_results.where = pdu->xdr_decode_buf;
+ msg.acpted_rply.ar_results.proc = pdu->xdr_decode_fn;
+
+ if (xdr_replymsg(xdr, &msg) == 0) {
+ printf("xdr_replymsg failed in portmap_getport_reply\n");
+ pdu->cb(rpc, RPC_STATUS_ERROR, "Message rejected by server", pdu->private_data);
+ if (pdu->xdr_decode_buf != NULL) {
+ free(pdu->xdr_decode_buf);
+ pdu->xdr_decode_buf = NULL;
+ }
+ return 0;
+ }
+ if (msg.rm_reply.rp_stat != MSG_ACCEPTED) {
+ pdu->cb(rpc, RPC_STATUS_ERROR, "RPC Packet not accepted by the server", pdu->private_data);
+ return 0;
+ }
+ switch (msg.rm_reply.rp_acpt.ar_stat) {
+ case SUCCESS:
+ pdu->cb(rpc, RPC_STATUS_SUCCESS, pdu->xdr_decode_buf, pdu->private_data);
+ break;
+ case PROG_UNAVAIL:
+ pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Program not available", pdu->private_data);
+ break;
+ case PROG_MISMATCH:
+ pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Program version mismatch", pdu->private_data);
+ break;
+ case PROC_UNAVAIL:
+ pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Procedure not available", pdu->private_data);
+ break;
+ case GARBAGE_ARGS:
+ pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Garbage arguments", pdu->private_data);
+ break;
+ case SYSTEM_ERR:
+ pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: System Error", pdu->private_data);
+ break;
+ default:
+ pdu->cb(rpc, RPC_STATUS_ERROR, "Unknown rpc response from server", pdu->private_data);
+ break;
+ }
+
+ return 0;
+}
+
+int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size)
+{
+ struct rpc_pdu *pdu;
+ XDR xdr;
+ int pos, recordmarker;
+ unsigned int xid;
+
+ bzero(&xdr, sizeof(XDR));
+
+ xdrmem_create(&xdr, buf, size, XDR_DECODE);
+ if (xdr_int(&xdr, &recordmarker) == 0) {
+ printf("xdr_int reading recordmarker failed\n");
+ xdr_destroy(&xdr);
+ return -1;
+ }
+ pos = xdr_getpos(&xdr);
+ if (xdr_int(&xdr, (int *)&xid) == 0) {
+ printf("xdr_int reading xid failed\n");
+ xdr_destroy(&xdr);
+ return -1;
+ }
+ xdr_setpos(&xdr, pos);
+
+ for (pdu=rpc->waitpdu; pdu; pdu=pdu->next) {
+ if (pdu->xid != xid) {
+ continue;
+ }
+ SLIST_REMOVE(&rpc->waitpdu, pdu);
+ if (rpc_process_reply(rpc, pdu, &xdr) != 0) {
+ printf("rpc_procdess_reply failed\n");
+ }
+ xdr_destroy(&xdr);
+ rpc_free_pdu(rpc, pdu);
+ return 0;
+ }
+ printf("No matching pdu found for xid:%d\n", xid);
+ xdr_destroy(&xdr);
+ return -1;
+}
+
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <string.h>
+#include <errno.h>
+#include <rpc/xdr.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include "libnfs.h"
+#include "libnfs-raw.h"
+#include "libnfs-private.h"
+#include "slist.h"
+
+static void set_nonblocking(int fd)
+{
+ unsigned v;
+ v = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, v | O_NONBLOCK);
+}
+
+int rpc_get_fd(struct rpc_context *rpc)
+{
+ return rpc->fd;
+}
+
+int rpc_which_events(struct rpc_context *rpc)
+{
+ int events = POLLIN;
+
+ if (rpc->is_connected == 0) {
+ events |= POLLOUT;
+ }
+
+ if (rpc->outqueue) {
+ events |= POLLOUT;
+ }
+ return events;
+}
+
+static int rpc_write_to_socket(struct rpc_context *rpc)
+{
+ ssize_t count;
+
+ if (rpc == NULL) {
+ printf("trying to write to socket for NULL context\n");
+ return -1;
+ }
+ if (rpc->fd == -1) {
+ printf("trying to write but not connected\n");
+ return -2;
+ }
+
+ while (rpc->outqueue != NULL) {
+ ssize_t total;
+
+ total = rpc->outqueue->outdata.size;
+
+ count = write(rpc->fd, rpc->outqueue->outdata.data + rpc->outqueue->written, total - rpc->outqueue->written);
+ if (count == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ printf("socket would block, return from write to socket\n");
+ return 0;
+ }
+ printf("Error when writing to socket :%s(%d)\n", strerror(errno), errno);
+ return -3;
+ }
+
+ rpc->outqueue->written += count;
+ if (rpc->outqueue->written == total) {
+ struct rpc_pdu *pdu = rpc->outqueue;
+
+ SLIST_REMOVE(&rpc->outqueue, pdu);
+ SLIST_ADD_END(&rpc->waitpdu, pdu);
+ }
+ }
+ return 0;
+}
+
+static int rpc_read_from_socket(struct rpc_context *rpc)
+{
+ int available;
+ int size;
+ unsigned char *buf;
+ ssize_t count;
+
+ if (ioctl(rpc->fd, FIONREAD, &available) != 0) {
+ rpc_set_error(rpc, "Ioctl FIONREAD returned error : %d. Closing socket.", errno);
+ return -1;
+ }
+ if (available == 0) {
+ rpc_set_error(rpc, "Socket has been closed");
+ return -2;
+ }
+ size = rpc->insize - rpc->inpos + available;
+ buf = malloc(size);
+ if (buf == NULL) {
+ rpc_set_error(rpc, "Out of memory: failed to allocate %d bytes for input buffer. Closing socket.", size);
+ return -3;
+ }
+ if (rpc->insize > rpc->inpos) {
+ memcpy(buf, rpc->inbuf + rpc->inpos, rpc->insize - rpc->inpos);
+ rpc->insize -= rpc->inpos;
+ rpc->inpos = 0;
+ }
+
+ count = read(rpc->fd, buf + rpc->insize, available);
+ if (count == -1) {
+ if (errno == EINTR) {
+ free(buf);
+ buf = NULL;
+ return 0;
+ }
+ rpc_set_error(rpc, "Read from socket failed, errno:%d. Closing socket.", errno);
+ free(buf);
+ buf = NULL;
+ return -4;
+ }
+
+ if (rpc->inbuf != NULL) {
+ free(rpc->inbuf);
+ }
+ rpc->inbuf = (char *)buf;
+ rpc->insize += count;
+
+ while (1) {
+ if (rpc->insize - rpc->inpos < 4) {
+ return 0;
+ }
+ count = rpc_get_pdu_size(rpc->inbuf + rpc->inpos);
+ if (rpc->insize + rpc->inpos < count) {
+ return 0;
+ }
+ if (rpc_process_pdu(rpc, rpc->inbuf + rpc->inpos, count) != 0) {
+ rpc_set_error(rpc, "Invalid/garbage pdu received from server. Closing socket");
+ return -5;
+ }
+ rpc->inpos += count;
+ if (rpc->inpos == rpc->insize) {
+ free(rpc->inbuf);
+ rpc->inbuf = NULL;
+ rpc->insize = 0;
+ rpc->inpos = 0;
+ }
+ }
+ return 0;
+}
+
+
+
+int rpc_service(struct rpc_context *rpc, int revents)
+{
+ if (revents & POLLERR) {
+ printf("rpc_service: POLLERR, socket error\n");
+ if (rpc->is_connected == 0) {
+ rpc_set_error(rpc, "Failed to connect to server socket.");
+ } else {
+ rpc_set_error(rpc, "Socket closed with POLLERR");
+ }
+ rpc->connect_cb(rpc, RPC_STATUS_ERROR, rpc->error_string, rpc->connect_data);
+ return -1;
+ }
+ if (revents & POLLHUP) {
+ printf("rpc_service: POLLHUP, socket error\n");
+ rpc_set_error(rpc, "Socket failed with POLLHUP");
+ rpc->connect_cb(rpc, RPC_STATUS_ERROR, rpc->error_string, rpc->connect_data);
+ return -2;
+ }
+
+ if (rpc->is_connected == 0 && rpc->fd != -1 && revents&POLLOUT) {
+ rpc->is_connected = 1;
+ rpc->connect_cb(rpc, RPC_STATUS_SUCCESS, NULL, rpc->connect_data);
+ return 0;
+ }
+
+ if (revents & POLLOUT && rpc->outqueue != NULL) {
+ if (rpc_write_to_socket(rpc) != 0) {
+ printf("write to socket failed\n");
+ return -3;
+ }
+ }
+
+ if (revents & POLLIN) {
+ if (rpc_read_from_socket(rpc) != 0) {
+ rpc_disconnect(rpc, rpc_get_error(rpc));
+ return -4;
+ }
+ }
+
+ return 0;
+}
+
+
+int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data)
+{
+ struct sockaddr_storage s;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&s;
+ int socksize;
+
+ if (rpc->fd != -1) {
+ rpc_set_error(rpc, "Trying to connect while already connected");
+ printf("%s\n", rpc->error_string);
+ return -1;
+ }
+
+ 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");
+ printf("%s\n", rpc->error_string);
+ return -2;
+ }
+
+ switch (s.ss_family) {
+ case AF_INET:
+ rpc->fd = socket(AF_INET, SOCK_STREAM, 0);
+ socksize = sizeof(struct sockaddr_in);
+ break;
+ }
+
+ if (rpc->fd == -1) {
+ rpc_set_error(rpc, "Failed to open socket");
+ printf("%s\n", rpc->error_string);
+ return -3;
+ }
+
+ rpc->connect_cb = cb;
+ rpc->connect_data = private_data;
+
+ set_nonblocking(rpc->fd);
+
+ if (connect(rpc->fd, (struct sockaddr *)&s, socksize) != 0 && errno != EINPROGRESS) {
+ rpc_set_error(rpc, "connect() to server failed");
+ printf("%s\n", rpc->error_string);
+ return -4;
+ }
+
+ return 0;
+}
+
+int rpc_disconnect(struct rpc_context *rpc, char *error)
+{
+ if (rpc->fd != -1) {
+ close(rpc->fd);
+ }
+ rpc->fd = -1;
+
+ rpc->is_connected = 0;
+
+ rpc_error_all_pdus(rpc, error);
+
+ return 0;
+}
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <rpc/xdr.h>
+#include "libnfs.h"
+#include "libnfs-raw.h"
+#include "libnfs-private.h"
+#include "libnfs-raw-mount.h"
+
+
+int rpc_mount_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
+{
+ struct rpc_pdu *pdu;
+
+ pdu = rpc_allocate_pdu(rpc, MOUNT_PROGRAM, MOUNT_V3, MOUNT3_NULL, cb, private_data, (xdrproc_t)xdr_void, 0);
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for mount/null call");
+ return -1;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for mount/null call");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ return 0;
+}
+
+int rpc_mount_mnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void *private_data)
+{
+ struct rpc_pdu *pdu;
+
+ pdu = rpc_allocate_pdu(rpc, MOUNT_PROGRAM, MOUNT_V3, MOUNT3_MNT, cb, private_data, (xdrproc_t)xdr_mountres3, sizeof(mountres3));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for mount/mnt call");
+ return -1;
+ }
+
+ if (xdr_dirpath(&pdu->xdr, &export) == 0) {
+ rpc_set_error(rpc, "XDR error. Failed to encode mount/mnt call");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for mount/mnt call");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ return 0;
+}
+
+int rpc_mount_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
+{
+ struct rpc_pdu *pdu;
+
+ pdu = rpc_allocate_pdu(rpc, MOUNT_PROGRAM, MOUNT_V3, MOUNT3_DUMP, cb, private_data, (xdrproc_t)xdr_mountlist, sizeof(mountlist));
+ if (pdu == NULL) {
+ printf("Failed to allocate pdu for mount/dump\n");
+ return -1;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ printf("Failed to queue mount/dump pdu\n");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ return 0;
+}
+
+int rpc_mount_umnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void *private_data)
+{
+ struct rpc_pdu *pdu;
+
+ pdu = rpc_allocate_pdu(rpc, MOUNT_PROGRAM, MOUNT_V3, MOUNT3_UMNT, cb, private_data, (xdrproc_t)xdr_void, 0);
+ if (pdu == NULL) {
+ printf("Failed to allocate pdu for mount/umnt\n");
+ return -1;
+ }
+
+ if (xdr_dirpath(&pdu->xdr, &export) == 0) {
+ printf("failed to encode dirpath for mount/umnt\n");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ printf("Failed to queue mount/umnt pdu\n");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ return 0;
+}
+
+int rpc_mount_umntall_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
+{
+ struct rpc_pdu *pdu;
+
+ pdu = rpc_allocate_pdu(rpc, MOUNT_PROGRAM, MOUNT_V3, MOUNT3_UMNTALL, cb, private_data, (xdrproc_t)xdr_void, 0);
+ if (pdu == NULL) {
+ printf("Failed to allocate pdu for mount/umntall\n");
+ return -1;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ printf("Failed to queue mount/umntall pdu\n");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ return 0;
+}
+
+int rpc_mount_export_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
+{
+ struct rpc_pdu *pdu;
+
+ pdu = rpc_allocate_pdu(rpc, MOUNT_PROGRAM, MOUNT_V3, MOUNT3_EXPORT, cb, private_data, (xdrproc_t)xdr_exports, sizeof(exports));
+ if (pdu == NULL) {
+ printf("Failed to allocate pdu for mount/export\n");
+ return -1;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ printf("Failed to queue mount/export pdu\n");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ return 0;
+}
+
+char *mountstat3_to_str(int st)
+{
+ enum mountstat3 stat = st;
+
+ char *str = "unknown mount stat";
+ switch (stat) {
+ case MNT3_OK: str="MNT3_OK"; break;
+ case MNT3ERR_PERM: str="MNT3ERR_PERM"; break;
+ case MNT3ERR_NOENT: str="MNT3ERR_NOENT"; break;
+ case MNT3ERR_IO: str="MNT3ERR_IO"; break;
+ case MNT3ERR_ACCES: str="MNT3ERR_ACCES"; break;
+ case MNT3ERR_NOTDIR: str="MNT3ERR_NOTDIR"; break;
+ case MNT3ERR_INVAL: str="MNT3ERR_INVAL"; break;
+ case MNT3ERR_NAMETOOLONG: str="MNT3ERR_NAMETOOLONG"; break;
+ case MNT3ERR_NOTSUPP: str="MNT3ERR_NOTSUPP"; break;
+ case MNT3ERR_SERVERFAULT: str="MNT3ERR_SERVERFAULT"; break;
+ }
+ return str;
+}
+
+
+int mountstat3_to_errno(int st)
+{
+ enum mountstat3 stat = st;
+
+ switch (stat) {
+ case MNT3_OK: return 0; break;
+ case MNT3ERR_PERM: return -EPERM; break;
+ case MNT3ERR_NOENT: return -EPERM; break;
+ case MNT3ERR_IO: return -EIO; break;
+ case MNT3ERR_ACCES: return -EACCES; break;
+ case MNT3ERR_NOTDIR: return -ENOTDIR; break;
+ case MNT3ERR_INVAL: return -EINVAL; break;
+ case MNT3ERR_NAMETOOLONG: return -E2BIG; break;
+ case MNT3ERR_NOTSUPP: return -EINVAL; break;
+ case MNT3ERR_SERVERFAULT: return -EIO; break;
+ }
+ return -ERANGE;
+}
--- /dev/null
+/* copied from RFC1813 */
+
+const MNTPATHLEN = 1024; /* Maximum bytes in a path name */
+const MNTNAMLEN = 255; /* Maximum bytes in a name */
+const FHSIZE3 = 64; /* Maximum bytes in a V3 file handle */
+
+
+typedef opaque fhandle3<FHSIZE3>;
+typedef string dirpath<MNTPATHLEN>;
+typedef string name<MNTNAMLEN>;
+
+enum mountstat3 {
+ MNT3_OK = 0, /* no error */
+ MNT3ERR_PERM = 1, /* Not owner */
+ MNT3ERR_NOENT = 2, /* No such file or directory */
+ MNT3ERR_IO = 5, /* I/O error */
+ MNT3ERR_ACCES = 13, /* Permission denied */
+ MNT3ERR_NOTDIR = 20, /* Not a directory */
+ MNT3ERR_INVAL = 22, /* Invalid argument */
+ MNT3ERR_NAMETOOLONG = 63, /* Filename too long */
+ MNT3ERR_NOTSUPP = 10004, /* Operation not supported */
+ MNT3ERR_SERVERFAULT = 10006 /* A failure on the server */
+};
+
+
+typedef struct mountbody *mountlist;
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+
+typedef struct groupnode *groups;
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+
+
+typedef struct exportnode *exports;
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+
+struct mountres3_ok {
+ fhandle3 fhandle;
+ int auth_flavors<>;
+};
+
+union mountres3 switch (mountstat3 fhs_status) {
+ case MNT3_OK:
+ mountres3_ok mountinfo;
+ default:
+ void;
+};
+
+program MOUNT_PROGRAM {
+ version MOUNT_V3 {
+ void MOUNT3_NULL(void) = 0;
+ mountres3 MOUNT3_MNT(dirpath) = 1;
+ mountlist MOUNT3_DUMP(void) = 2;
+ void MOUNT3_UMNT(dirpath) = 3;
+ void MOUNT3_UMNTALL(void) = 4;
+ exports MOUNT3_EXPORT(void) = 5;
+ } = 3;
+} = 100005;
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <rpc/xdr.h>
+#include "libnfs.h"
+#include "libnfs-raw.h"
+#include "libnfs-private.h"
+#include "libnfs-raw-nfs.h"
+
+
+
+char *nfsstat3_to_str(int error)
+{
+ switch (error) {
+ case NFS3_OK: return "NFS3_OK"; break;
+ case NFS3ERR_PERM: return "NFS3ERR_PERM"; break;
+ case NFS3ERR_NOENT: return "NFS3ERR_NOENT"; break;
+ case NFS3ERR_IO: return "NFS3ERR_IO"; break;
+ case NFS3ERR_NXIO: return "NFS3ERR_NXIO"; break;
+ case NFS3ERR_ACCES: return "NFS3ERR_ACCES"; break;
+ case NFS3ERR_EXIST: return "NFS3ERR_EXIST"; break;
+ case NFS3ERR_XDEV: return "NFS3ERR_XDEV"; break;
+ case NFS3ERR_NODEV: return "NFS3ERR_NODEV"; break;
+ case NFS3ERR_NOTDIR: return "NFS3ERR_NOTDIR"; break;
+ case NFS3ERR_ISDIR: return "NFS3ERR_ISDIR"; break;
+ case NFS3ERR_INVAL: return "NFS3ERR_INVAL"; break;
+ case NFS3ERR_FBIG: return "NFS3ERR_FBIG"; break;
+ case NFS3ERR_NOSPC: return "NFS3ERR_NOSPC"; break;
+ case NFS3ERR_ROFS: return "NFS3ERR_ROFS"; break;
+ case NFS3ERR_MLINK: return "NFS3ERR_MLINK"; break;
+ case NFS3ERR_NAMETOOLONG: return "NFS3ERR_NAMETOOLONG"; break;
+ case NFS3ERR_NOTEMPTY: return "NFS3ERR_NOTEMPTY"; break;
+ case NFS3ERR_DQUOT: return "NFS3ERR_DQUOT"; break;
+ case NFS3ERR_STALE: return "NFS3ERR_STALE"; break;
+ case NFS3ERR_REMOTE: return "NFS3ERR_REMOTE"; break;
+ case NFS3ERR_BADHANDLE: return "NFS3ERR_BADHANDLE"; break;
+ case NFS3ERR_NOT_SYNC: return "NFS3ERR_NOT_SYNC"; break;
+ case NFS3ERR_BAD_COOKIE: return "NFS3ERR_BAD_COOKIE"; break;
+ case NFS3ERR_NOTSUPP: return "NFS3ERR_NOTSUPP"; break;
+ case NFS3ERR_TOOSMALL: return "NFS3ERR_TOOSMALL"; break;
+ case NFS3ERR_SERVERFAULT: return "NFS3ERR_SERVERFAULT"; break;
+ case NFS3ERR_BADTYPE: return "NFS3ERR_BADTYPE"; break;
+ case NFS3ERR_JUKEBOX: return "NFS3ERR_JUKEBOX"; break;
+ };
+ return "unknown nfs error";
+}
+
+int nfsstat3_to_errno(int error)
+{
+ switch (error) {
+ case NFS3_OK: return 0; break;
+ case NFS3ERR_PERM: return -EPERM; break;
+ case NFS3ERR_NOENT: return -ENOENT; break;
+ case NFS3ERR_IO: return -EIO; break;
+ case NFS3ERR_NXIO: return -ENXIO; break;
+ case NFS3ERR_ACCES: return -EACCES; break;
+ case NFS3ERR_EXIST: return -EEXIST; break;
+ case NFS3ERR_XDEV: return -EXDEV; break;
+ case NFS3ERR_NODEV: return -ENODEV; break;
+ case NFS3ERR_NOTDIR: return -ENOTDIR; break;
+ case NFS3ERR_ISDIR: return -EISDIR; break;
+ case NFS3ERR_INVAL: return -EINVAL; break;
+ case NFS3ERR_FBIG: return -EFBIG; break;
+ case NFS3ERR_NOSPC: return -ENOSPC; break;
+ case NFS3ERR_ROFS: return -EROFS; break;
+ case NFS3ERR_MLINK: return -EMLINK; break;
+ case NFS3ERR_NAMETOOLONG: return -ENAMETOOLONG; break;
+ case NFS3ERR_NOTEMPTY: return -EEXIST; break;
+ case NFS3ERR_DQUOT: return -ERANGE; break;
+ case NFS3ERR_STALE: return -EIO; break;
+ case NFS3ERR_REMOTE: return -EIO; break;
+ case NFS3ERR_BADHANDLE: return -EIO; break;
+ case NFS3ERR_NOT_SYNC: return -EIO; break;
+ case NFS3ERR_BAD_COOKIE: return -EIO; break;
+ case NFS3ERR_NOTSUPP: return -EINVAL; break;
+ case NFS3ERR_TOOSMALL: return -EIO; break;
+ case NFS3ERR_SERVERFAULT: return -EIO; break;
+ case NFS3ERR_BADTYPE: return -EINVAL; break;
+ case NFS3ERR_JUKEBOX: return -EAGAIN; break;
+ };
+ return -ERANGE;
+}
+
+
+int rpc_nfs_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
+{
+ struct rpc_pdu *pdu;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_NULL, cb, private_data, (xdrproc_t)xdr_void, 0);
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/null call");
+ return -1;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/null call");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ return 0;
+}
+
+int rpc_nfs_getattr_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ GETATTR3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_GETATTR, cb, private_data, (xdrproc_t)xdr_GETATTR3res, sizeof(GETATTR3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/null call");
+ return -1;
+ }
+
+ args.object.data.data_len = fh->data.data_len;
+ args.object.data.data_val = fh->data.data_val;
+
+ if (xdr_GETATTR3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode GETATTR3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/null call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+int rpc_nfs_lookup_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *name, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ LOOKUP3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_LOOKUP, cb, private_data, (xdrproc_t)xdr_LOOKUP3res, sizeof(LOOKUP3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/lookup call");
+ return -1;
+ }
+
+ args.what.dir.data.data_len = fh->data.data_len;
+ args.what.dir.data.data_val = fh->data.data_val;
+ args.what.name = name;
+
+ if (xdr_LOOKUP3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode LOOKUP3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/lookup call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+int rpc_nfs_access_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, int access, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ ACCESS3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_ACCESS, cb, private_data, (xdrproc_t)xdr_ACCESS3res, sizeof(ACCESS3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/access call");
+ return -1;
+ }
+
+ args.object.data.data_len = fh->data.data_len;
+ args.object.data.data_val = fh->data.data_val;
+ args.access = access;
+
+ if (xdr_ACCESS3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode ACCESS3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/access call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+int rpc_nfs_read_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, off_t offset, size_t count, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ READ3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_READ, cb, private_data, (xdrproc_t)xdr_READ3res, sizeof(READ3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/read call");
+ return -1;
+ }
+
+ args.file.data.data_len = fh->data.data_len;
+ args.file.data.data_val = fh->data.data_val;
+ args.offset = offset;
+ args.count = count;
+
+ if (xdr_READ3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode READ3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/read call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+int rpc_nfs_write_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *buf, off_t offset, size_t count, int stable_how, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ WRITE3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_WRITE, cb, private_data, (xdrproc_t)xdr_WRITE3res, sizeof(WRITE3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/write call");
+ return -1;
+ }
+
+ args.file.data.data_len = fh->data.data_len;
+ args.file.data.data_val = fh->data.data_val;
+ args.offset = offset;
+ args.count = count;
+ args.stable = stable_how;;
+ args.data.data_len = count;
+ args.data.data_val = buf;
+
+ if (xdr_WRITE3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode WRITE3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/write call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+int rpc_nfs_commit_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ COMMIT3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_COMMIT, cb, private_data, (xdrproc_t)xdr_COMMIT3res, sizeof(COMMIT3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/commit call");
+ return -1;
+ }
+
+ args.file.data.data_len = fh->data.data_len;
+ args.file.data.data_val = fh->data.data_val;
+ args.offset = 0;
+ args.count = 0;
+
+ if (xdr_COMMIT3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode WRITE3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/commit call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+int rpc_nfs_setattr_async(struct rpc_context *rpc, rpc_cb cb, SETATTR3args *args, void *private_data)
+{
+ struct rpc_pdu *pdu;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_SETATTR, cb, private_data, (xdrproc_t)xdr_SETATTR3res, sizeof(SETATTR3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/setattr call");
+ return -1;
+ }
+
+ if (xdr_SETATTR3args(&pdu->xdr, args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode SETATTR3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/setattr call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+int rpc_nfs_mkdir_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *dir, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ MKDIR3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_MKDIR, cb, private_data, (xdrproc_t)xdr_MKDIR3res, sizeof(MKDIR3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/setattr call");
+ return -1;
+ }
+
+ bzero(&args, sizeof(MKDIR3args));
+ args.where.dir.data.data_len = fh->data.data_len;
+ args.where.dir.data.data_val = fh->data.data_val;
+ args.where.name = dir;
+ args.attributes.mode.set_it = 1;
+ args.attributes.mode.set_mode3_u.mode = 0755;
+
+ if (xdr_MKDIR3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode MKDIR3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/mkdir call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+
+int rpc_nfs_rmdir_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *dir, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ RMDIR3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_RMDIR, cb, private_data, (xdrproc_t)xdr_RMDIR3res, sizeof(RMDIR3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/rmdir call");
+ return -1;
+ }
+
+ bzero(&args, sizeof(RMDIR3args));
+ args.object.dir.data.data_len = fh->data.data_len;
+ args.object.dir.data.data_val = fh->data.data_val;
+ args.object.name = dir;
+
+ if (xdr_RMDIR3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode RMDIR3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/rmdir call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+int rpc_nfs_create_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *file, int mode, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ CREATE3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_CREATE, cb, private_data, (xdrproc_t)xdr_CREATE3res, sizeof(CREATE3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/create call");
+ return -1;
+ }
+
+ bzero(&args, sizeof(CREATE3args));
+ args.where.dir.data.data_len = fh->data.data_len;
+ args.where.dir.data.data_val = fh->data.data_val;
+ args.where.name = file;
+ args.how.mode = UNCHECKED;
+ args.how.createhow3_u.obj_attributes.mode.set_it = 1;
+ args.how.createhow3_u.obj_attributes.mode.set_mode3_u.mode = mode;
+
+ if (xdr_CREATE3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode CREATE3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/create call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+
+int rpc_nfs_remove_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *file, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ REMOVE3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_REMOVE, cb, private_data, (xdrproc_t)xdr_REMOVE3res, sizeof(REMOVE3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/remove call");
+ return -1;
+ }
+
+ bzero(&args, sizeof(REMOVE3args));
+ args.object.dir.data.data_len = fh->data.data_len;
+ args.object.dir.data.data_val = fh->data.data_val;
+ args.object.name = file;
+
+ if (xdr_REMOVE3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode REMOVE3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/remove call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+int rpc_nfs_readdir_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, uint64_t cookie, char *cookieverf, int count, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ READDIR3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_READDIR, cb, private_data, (xdrproc_t)xdr_READDIR3res, sizeof(READDIR3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/readdir call");
+ return -1;
+ }
+
+ bzero(&args, sizeof(READDIR3args));
+ args.dir.data.data_len = fh->data.data_len;
+ args.dir.data.data_val = fh->data.data_val;
+ args.cookie = cookie;
+ memcpy(&args.cookieverf, cookieverf, sizeof(cookieverf3));
+ args.count = count;
+
+ if (xdr_READDIR3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode READDIR3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/readdir call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+int rpc_nfs_fsstat_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ FSSTAT3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_FSSTAT, cb, private_data, (xdrproc_t)xdr_FSSTAT3res, sizeof(FSSTAT3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/fsstat call");
+ return -1;
+ }
+
+ args.fsroot.data.data_len = fh->data.data_len;
+ args.fsroot.data.data_val = fh->data.data_val;
+
+ if (xdr_FSSTAT3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode FSSTAT3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/fsstat call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+int rpc_nfs_readlink_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ READLINK3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_READLINK, cb, private_data, (xdrproc_t)xdr_READLINK3res, sizeof(READLINK3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/readlink call");
+ return -1;
+ }
+
+ args.symlink.data.data_len = fh->data.data_len;
+ args.symlink.data.data_val = fh->data.data_val;
+
+ if (xdr_READLINK3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode READLINK3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/readlink call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+int rpc_nfs_symlink_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *newname, char *oldpath, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ SYMLINK3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_SYMLINK, cb, private_data, (xdrproc_t)xdr_SYMLINK3res, sizeof(SYMLINK3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/symlink call");
+ return -1;
+ }
+
+ bzero(&args, sizeof(SYMLINK3args));
+ args.where.dir.data.data_len = fh->data.data_len;
+ args.where.dir.data.data_val = fh->data.data_val;
+ args.where.name = newname;
+ args.symlink.symlink_attributes.mode.set_it = 1;
+ args.symlink.symlink_attributes.mode.set_mode3_u.mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH;
+ args.symlink.symlink_data = oldpath;
+
+ if (xdr_SYMLINK3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode SYMLINK3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/symlink call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+
+int rpc_nfs_rename_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *olddir, char *oldname, struct nfs_fh3 *newdir, char *newname, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ RENAME3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_RENAME, cb, private_data, (xdrproc_t)xdr_RENAME3res, sizeof(RENAME3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/rename call");
+ return -1;
+ }
+
+ bzero(&args, sizeof(RENAME3args));
+ args.from.dir.data.data_len = olddir->data.data_len;
+ args.from.dir.data.data_val = olddir->data.data_val;
+ args.from.name = oldname;
+ args.to.dir.data.data_len = newdir->data.data_len;
+ args.to.dir.data.data_val = newdir->data.data_val;
+ args.to.name = newname;
+
+ if (xdr_RENAME3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode RENAME3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/rename call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+
+int rpc_nfs_link_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *file, struct nfs_fh3 *newdir, char *newname, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ LINK3args args;
+
+ pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_LINK, cb, private_data, (xdrproc_t)xdr_LINK3res, sizeof(LINK3res));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/link call");
+ return -1;
+ }
+
+ bzero(&args, sizeof(LINK3args));
+ args.file.data.data_len = file->data.data_len;
+ args.file.data.data_val = file->data.data_val;
+ args.link.dir.data.data_len = newdir->data.data_len;
+ args.link.dir.data.data_val = newdir->data.data_val;
+ args.link.name = newname;
+
+ if (xdr_LINK3args(&pdu->xdr, &args) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode LINK3args");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/link call");
+ rpc_free_pdu(rpc, pdu);
+ return -3;
+ }
+
+ return 0;
+}
+
+
+
+
--- /dev/null
+/* copied from rfc 1813 */
+
+const NFS3_FHSIZE = 64; /* Maximum bytes in a V3 file handle */
+const NFS3_WRITEVERFSIZE = 8;
+const NFS3_CREATEVERFSIZE = 8;
+const NFS3_COOKIEVERFSIZE = 8;
+
+typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
+
+typedef unsigned hyper uint64;
+typedef uint64 cookie3;
+
+struct nfs_fh3 {
+ opaque data<NFS3_FHSIZE>;
+};
+
+typedef string filename3<>;
+
+struct diropargs3 {
+ nfs_fh3 dir;
+ filename3 name;
+};
+
+enum ftype3 {
+ NF3REG = 1,
+ NF3DIR = 2,
+ NF3BLK = 3,
+ NF3CHR = 4,
+ NF3LNK = 5,
+ NF3SOCK = 6,
+ NF3FIFO = 7
+};
+
+typedef unsigned long uint32;
+
+typedef long int32;
+
+typedef uint32 mode3;
+
+typedef uint32 uid3;
+
+typedef uint32 gid3;
+
+typedef uint64 size3;
+
+typedef uint64 fileid3;
+
+struct specdata3 {
+ uint32 specdata1;
+ uint32 specdata2;
+};
+
+struct nfstime3 {
+ uint32 seconds;
+ uint32 nseconds;
+};
+
+struct fattr3 {
+ ftype3 type;
+ mode3 mode;
+ uint32 nlink;
+ uid3 uid;
+ gid3 gid;
+ size3 size;
+ size3 used;
+ specdata3 rdev;
+ uint64 fsid;
+ fileid3 fileid;
+ nfstime3 atime;
+ nfstime3 mtime;
+ nfstime3 ctime;
+};
+
+union post_op_attr switch (bool attributes_follow) {
+ case TRUE:
+ fattr3 attributes;
+ case FALSE:
+ void;
+};
+
+
+enum nfsstat3 {
+ NFS3_OK = 0,
+ NFS3ERR_PERM = 1,
+ NFS3ERR_NOENT = 2,
+ NFS3ERR_IO = 5,
+ NFS3ERR_NXIO = 6,
+ NFS3ERR_ACCES = 13,
+ NFS3ERR_EXIST = 17,
+ NFS3ERR_XDEV = 18,
+ NFS3ERR_NODEV = 19,
+ NFS3ERR_NOTDIR = 20,
+ NFS3ERR_ISDIR = 21,
+ NFS3ERR_INVAL = 22,
+ NFS3ERR_FBIG = 27,
+ NFS3ERR_NOSPC = 28,
+ NFS3ERR_ROFS = 30,
+ NFS3ERR_MLINK = 31,
+ NFS3ERR_NAMETOOLONG = 63,
+ NFS3ERR_NOTEMPTY = 66,
+ NFS3ERR_DQUOT = 69,
+ NFS3ERR_STALE = 70,
+ NFS3ERR_REMOTE = 71,
+ NFS3ERR_BADHANDLE = 10001,
+ NFS3ERR_NOT_SYNC = 10002,
+ NFS3ERR_BAD_COOKIE = 10003,
+ NFS3ERR_NOTSUPP = 10004,
+ NFS3ERR_TOOSMALL = 10005,
+ NFS3ERR_SERVERFAULT = 10006,
+ NFS3ERR_BADTYPE = 10007,
+ NFS3ERR_JUKEBOX = 10008
+};
+
+enum stable_how {
+ UNSTABLE = 0,
+ DATA_SYNC = 1,
+ FILE_SYNC = 2
+};
+
+typedef uint64 offset3;
+
+typedef uint32 count3;
+
+struct wcc_attr {
+ size3 size;
+ nfstime3 mtime;
+ nfstime3 ctime;
+};
+
+union pre_op_attr switch (bool attributes_follow) {
+ case TRUE:
+ wcc_attr attributes;
+ case FALSE:
+ void;
+};
+
+struct wcc_data {
+ pre_op_attr before;
+ post_op_attr after;
+};
+
+struct WRITE3args {
+ nfs_fh3 file;
+ offset3 offset;
+ count3 count;
+ stable_how stable;
+ opaque data<>;
+};
+
+typedef opaque writeverf3[NFS3_WRITEVERFSIZE];
+
+struct WRITE3resok {
+ wcc_data file_wcc;
+ count3 count;
+ stable_how committed;
+ writeverf3 verf;
+};
+
+struct WRITE3resfail {
+ wcc_data file_wcc;
+};
+
+union WRITE3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ WRITE3resok resok;
+ default:
+ WRITE3resfail resfail;
+};
+
+struct LOOKUP3args {
+ diropargs3 what;
+};
+
+struct LOOKUP3resok {
+ nfs_fh3 object;
+ post_op_attr obj_attributes;
+ post_op_attr dir_attributes;
+};
+
+struct LOOKUP3resfail {
+ post_op_attr dir_attributes;
+};
+
+
+
+union LOOKUP3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ LOOKUP3resok resok;
+ default:
+ LOOKUP3resfail resfail;
+};
+
+struct COMMIT3args {
+ nfs_fh3 file;
+ offset3 offset;
+ count3 count;
+};
+
+struct COMMIT3resok {
+ wcc_data file_wcc;
+ writeverf3 verf;
+};
+
+struct COMMIT3resfail {
+ wcc_data file_wcc;
+};
+
+union COMMIT3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ COMMIT3resok resok;
+ default:
+ COMMIT3resfail resfail;
+};
+
+const ACCESS3_READ = 0x0001;
+const ACCESS3_LOOKUP = 0x0002;
+const ACCESS3_MODIFY = 0x0004;
+const ACCESS3_EXTEND = 0x0008;
+const ACCESS3_DELETE = 0x0010;
+const ACCESS3_EXECUTE = 0x0020;
+
+struct ACCESS3args {
+ nfs_fh3 object;
+ uint32 access;
+};
+
+struct ACCESS3resok {
+ post_op_attr obj_attributes;
+ uint32 access;
+};
+
+struct ACCESS3resfail {
+ post_op_attr obj_attributes;
+};
+
+union ACCESS3res switch (nfsstat3 status) {
+case NFS3_OK:
+ ACCESS3resok resok;
+default:
+ ACCESS3resfail resfail;
+};
+
+struct GETATTR3args {
+ nfs_fh3 object;
+};
+
+struct GETATTR3resok {
+ fattr3 obj_attributes;
+};
+
+union GETATTR3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ GETATTR3resok resok;
+ default:
+ void;
+};
+
+
+
+enum time_how {
+ DONT_CHANGE = 0,
+ SET_TO_SERVER_TIME = 1,
+ SET_TO_CLIENT_TIME = 2
+};
+
+union set_mode3 switch (bool set_it) {
+ case TRUE:
+ mode3 mode;
+ default:
+ void;
+};
+
+union set_uid3 switch (bool set_it) {
+ case TRUE:
+ uid3 uid;
+ default:
+ void;
+};
+
+union set_gid3 switch (bool set_it) {
+ case TRUE:
+ gid3 gid;
+ default:
+ void;
+};
+
+union set_size3 switch (bool set_it) {
+ case TRUE:
+ size3 size;
+ default:
+ void;
+};
+
+union set_atime switch (time_how set_it) {
+ case SET_TO_CLIENT_TIME:
+ nfstime3 atime;
+ default:
+ void;
+};
+
+union set_mtime switch (time_how set_it) {
+ case SET_TO_CLIENT_TIME:
+ nfstime3 mtime;
+ default:
+ void;
+};
+
+struct sattr3 {
+ set_mode3 mode;
+ set_uid3 uid;
+ set_gid3 gid;
+ set_size3 size;
+ set_atime atime;
+ set_mtime mtime;
+};
+
+enum createmode3 {
+ UNCHECKED = 0,
+ GUARDED = 1,
+ EXCLUSIVE = 2
+};
+
+
+typedef opaque createverf3[NFS3_CREATEVERFSIZE];
+
+union createhow3 switch (createmode3 mode) {
+ case UNCHECKED:
+ case GUARDED:
+ sattr3 obj_attributes;
+ case EXCLUSIVE:
+ createverf3 verf;
+};
+
+struct CREATE3args {
+ diropargs3 where;
+ createhow3 how;
+};
+
+union post_op_fh3 switch (bool handle_follows) {
+ case TRUE:
+ nfs_fh3 handle;
+ case FALSE:
+ void;
+};
+
+struct CREATE3resok {
+ post_op_fh3 obj;
+ post_op_attr obj_attributes;
+ wcc_data dir_wcc;
+};
+
+struct CREATE3resfail {
+ wcc_data dir_wcc;
+ };
+
+union CREATE3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ CREATE3resok resok;
+ default:
+ CREATE3resfail resfail;
+};
+
+struct REMOVE3args {
+ diropargs3 object;
+};
+
+struct REMOVE3resok {
+ wcc_data dir_wcc;
+};
+
+struct REMOVE3resfail {
+ wcc_data dir_wcc;
+};
+
+union REMOVE3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ REMOVE3resok resok;
+ default:
+ REMOVE3resfail resfail;
+};
+
+struct READ3args {
+ nfs_fh3 file;
+ offset3 offset;
+ count3 count;
+};
+
+struct READ3resok {
+ post_op_attr file_attributes;
+ count3 count;
+ bool eof;
+ opaque data<>;
+};
+
+struct READ3resfail {
+ post_op_attr file_attributes;
+};
+
+union READ3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ READ3resok resok;
+ default:
+ READ3resfail resfail;
+};
+
+
+const FSF3_LINK = 0x0001;
+const FSF3_SYMLINK = 0x0002;
+const FSF3_HOMOGENEOUS = 0x0008;
+const FSF3_CANSETTIME = 0x0010;
+
+struct FSINFO3args {
+ nfs_fh3 fsroot;
+};
+
+struct FSINFO3resok {
+ post_op_attr obj_attributes;
+ uint32 rtmax;
+ uint32 rtpref;
+ uint32 rtmult;
+ uint32 wtmax;
+ uint32 wtpref;
+ uint32 wtmult;
+ uint32 dtpref;
+ size3 maxfilesize;
+ nfstime3 time_delta;
+ uint32 properties;
+};
+
+struct FSINFO3resfail {
+ post_op_attr obj_attributes;
+};
+
+union FSINFO3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ FSINFO3resok resok;
+ default:
+ FSINFO3resfail resfail;
+};
+
+
+struct FSSTAT3args {
+ nfs_fh3 fsroot;
+};
+
+struct FSSTAT3resok {
+ post_op_attr obj_attributes;
+ size3 tbytes;
+ size3 fbytes;
+ size3 abytes;
+ size3 tfiles;
+ size3 ffiles;
+ size3 afiles;
+ uint32 invarsec;
+};
+
+struct FSSTAT3resfail {
+ post_op_attr obj_attributes;
+};
+
+union FSSTAT3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ FSSTAT3resok resok;
+ default:
+ FSSTAT3resfail resfail;
+};
+
+struct PATHCONF3args {
+ nfs_fh3 object;
+};
+
+struct PATHCONF3resok {
+ post_op_attr obj_attributes;
+ uint32 linkmax;
+ uint32 name_max;
+ bool no_trunc;
+ bool chown_restricted;
+ bool case_insensitive;
+ bool case_preserving;
+};
+
+struct PATHCONF3resfail {
+ post_op_attr obj_attributes;
+};
+
+union PATHCONF3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ PATHCONF3resok resok;
+ default:
+ PATHCONF3resfail resfail;
+};
+
+typedef string nfspath3<>;
+
+struct symlinkdata3 {
+ sattr3 symlink_attributes;
+ nfspath3 symlink_data;
+};
+
+struct SYMLINK3args {
+ diropargs3 where;
+ symlinkdata3 symlink;
+};
+
+struct SYMLINK3resok {
+ post_op_fh3 obj;
+ post_op_attr obj_attributes;
+ wcc_data dir_wcc;
+};
+
+struct SYMLINK3resfail {
+ wcc_data dir_wcc;
+};
+
+union SYMLINK3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ SYMLINK3resok resok;
+ default:
+ SYMLINK3resfail resfail;
+};
+
+
+struct READLINK3args {
+ nfs_fh3 symlink;
+};
+
+struct READLINK3resok {
+ post_op_attr symlink_attributes;
+ nfspath3 data;
+};
+
+struct READLINK3resfail {
+ post_op_attr symlink_attributes;
+};
+
+union READLINK3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ READLINK3resok resok;
+ default:
+ READLINK3resfail resfail;
+};
+
+
+struct devicedata3 {
+ sattr3 dev_attributes;
+ specdata3 spec;
+};
+
+union mknoddata3 switch (ftype3 type) {
+ case NF3CHR:
+ case NF3BLK:
+ devicedata3 device;
+ case NF3SOCK:
+ case NF3FIFO:
+ sattr3 pipe_attributes;
+ default:
+ void;
+};
+
+struct MKNOD3args {
+ diropargs3 where;
+ mknoddata3 what;
+};
+
+struct MKNOD3resok {
+ post_op_fh3 obj;
+ post_op_attr obj_attributes;
+ wcc_data dir_wcc;
+};
+
+struct MKNOD3resfail {
+ wcc_data dir_wcc;
+};
+
+union MKNOD3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ MKNOD3resok resok;
+ default:
+ MKNOD3resfail resfail;
+};
+
+
+struct MKDIR3args {
+ diropargs3 where;
+ sattr3 attributes;
+};
+
+struct MKDIR3resok {
+ post_op_fh3 obj;
+ post_op_attr obj_attributes;
+ wcc_data dir_wcc;
+};
+
+struct MKDIR3resfail {
+ wcc_data dir_wcc;
+};
+
+union MKDIR3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ MKDIR3resok resok;
+ default:
+ MKDIR3resfail resfail;
+};
+
+struct RMDIR3args {
+ diropargs3 object;
+};
+
+struct RMDIR3resok {
+ wcc_data dir_wcc;
+};
+
+struct RMDIR3resfail {
+ wcc_data dir_wcc;
+};
+
+union RMDIR3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ RMDIR3resok resok;
+ default:
+ RMDIR3resfail resfail;
+};
+
+struct RENAME3args {
+ diropargs3 from;
+ diropargs3 to;
+};
+
+struct RENAME3resok {
+ wcc_data fromdir_wcc;
+ wcc_data todir_wcc;
+};
+
+struct RENAME3resfail {
+ wcc_data fromdir_wcc;
+ wcc_data todir_wcc;
+};
+
+union RENAME3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ RENAME3resok resok;
+ default:
+ RENAME3resfail resfail;
+};
+
+struct READDIRPLUS3args {
+ nfs_fh3 dir;
+ cookie3 cookie;
+ cookieverf3 cookieverf;
+ count3 dircount;
+ count3 maxcount;
+};
+
+struct entryplus3 {
+ fileid3 fileid;
+ filename3 name;
+ cookie3 cookie;
+ post_op_attr name_attributes;
+ post_op_fh3 name_handle;
+ entryplus3 *nextentry;
+};
+
+struct dirlistplus3 {
+ entryplus3 *entries;
+ bool eof;
+};
+
+struct READDIRPLUS3resok {
+ post_op_attr dir_attributes;
+ cookieverf3 cookieverf;
+ dirlistplus3 reply;
+};
+
+
+struct READDIRPLUS3resfail {
+ post_op_attr dir_attributes;
+};
+
+union READDIRPLUS3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ READDIRPLUS3resok resok;
+ default:
+ READDIRPLUS3resfail resfail;
+};
+
+struct READDIR3args {
+ nfs_fh3 dir;
+ cookie3 cookie;
+ cookieverf3 cookieverf;
+ count3 count;
+};
+
+
+struct entry3 {
+ fileid3 fileid;
+ filename3 name;
+ cookie3 cookie;
+ entry3 *nextentry;
+};
+
+struct dirlist3 {
+ entry3 *entries;
+ bool eof;
+};
+
+struct READDIR3resok {
+ post_op_attr dir_attributes;
+ cookieverf3 cookieverf;
+ dirlist3 reply;
+};
+
+struct READDIR3resfail {
+ post_op_attr dir_attributes;
+};
+
+union READDIR3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ READDIR3resok resok;
+ default:
+ READDIR3resfail resfail;
+};
+
+struct LINK3args {
+ nfs_fh3 file;
+ diropargs3 link;
+};
+
+struct LINK3resok {
+ post_op_attr file_attributes;
+ wcc_data linkdir_wcc;
+};
+
+struct LINK3resfail {
+ post_op_attr file_attributes;
+ wcc_data linkdir_wcc;
+};
+
+union LINK3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ LINK3resok resok;
+ default:
+ LINK3resfail resfail;
+};
+
+union sattrguard3 switch (bool check) {
+ case TRUE:
+ nfstime3 obj_ctime;
+ case FALSE:
+ void;
+};
+
+struct SETATTR3args {
+ nfs_fh3 object;
+ sattr3 new_attributes;
+ sattrguard3 guard;
+};
+
+struct SETATTR3resok {
+ wcc_data obj_wcc;
+};
+
+struct SETATTR3resfail {
+ wcc_data obj_wcc;
+};
+
+union SETATTR3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ SETATTR3resok resok;
+ default:
+ SETATTR3resfail resfail;
+};
+
+program NFS_PROGRAM {
+ version NFS_V3 {
+ void
+ NFS3_NULL(void) = 0;
+
+ GETATTR3res
+ NFS3_GETATTR(GETATTR3args) = 1;
+
+ SETATTR3res
+ NFS3_SETATTR(SETATTR3args) = 2;
+
+ LOOKUP3res
+ NFS3_LOOKUP(LOOKUP3args) = 3;
+
+ ACCESS3res
+ NFS3_ACCESS(ACCESS3args) = 4;
+
+ READLINK3res
+ NFS3_READLINK(READLINK3args) = 5;
+
+ READ3res
+ NFS3_READ(READ3args) = 6;
+
+ WRITE3res
+ NFS3_WRITE(WRITE3args) = 7;
+
+ CREATE3res
+ NFS3_CREATE(CREATE3args) = 8;
+
+ MKDIR3res
+ NFS3_MKDIR(MKDIR3args) = 9;
+
+ SYMLINK3res
+ NFS3_SYMLINK(SYMLINK3args) = 10;
+
+/* MKNOD3res NFSPROC3_MKNOD(MKNOD3args) = 11;*/
+
+ REMOVE3res
+ NFS3_REMOVE(REMOVE3args) = 12;
+
+ RMDIR3res
+ NFS3_RMDIR(RMDIR3args) = 13;
+
+ RENAME3res
+ NFS3_RENAME(RENAME3args) = 14;
+
+ LINK3res
+ NFS3_LINK(LINK3args) = 15;
+
+ READDIR3res
+ NFS3_READDIR(READDIR3args) = 16;
+
+ READDIRPLUS3res
+ NFS3_READDIRPLUS(READDIRPLUS3args) = 17;
+
+ FSSTAT3res
+ NFS3_FSSTAT(FSSTAT3args) = 18;
+
+ FSINFO3res
+ NFS3_FSINFO(FSINFO3args) = 19;
+
+ PATHCONF3res
+ NFS3_PATHCONF(PATHCONF3args) = 20;
+
+ COMMIT3res
+ NFS3_COMMIT(COMMIT3args) = 21;
+ } = 3;
+} = 100003;
--- /dev/null
+/*
+ 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
+ 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/>.
+*/
+
+#include <stdio.h>
+#include <rpc/xdr.h>
+#include "libnfs.h"
+#include "libnfs-raw.h"
+#include "libnfs-private.h"
+#include "libnfs-raw-portmap.h"
+
+
+int rpc_pmap_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
+{
+ struct rpc_pdu *pdu;
+
+ pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_NULL, cb, private_data, (xdrproc_t)xdr_void, 0);
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/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_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ return 0;
+}
+
+int rpc_pmap_getport_async(struct rpc_context *rpc, int program, int version, rpc_cb cb, void *private_data)
+{
+ struct rpc_pdu *pdu;
+ struct mapping m;
+
+ pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_GETPORT, cb, private_data, (xdrproc_t)xdr_int, sizeof(uint32_t));
+ if (pdu == NULL) {
+ rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/getport call");
+ return -1;
+ }
+
+ m.prog = program;
+ m.vers = version;
+ m.prot = IPPROTO_TCP;
+ m.port = 0;
+ if (xdr_mapping(&pdu->xdr, &m) == 0) {
+ rpc_set_error(rpc, "XDR error: Failed to encode data for portmap/getport call");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ if (rpc_queue_pdu(rpc, pdu) != 0) {
+ printf("Failed to queue portmap/getport pdu\n");
+ rpc_free_pdu(rpc, pdu);
+ return -2;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * From RFC1833
+ */
+
+const PMAP_PORT = 111; /* portmapper port number */
+
+struct mapping {
+ unsigned int prog;
+ unsigned int vers;
+ unsigned int prot;
+ unsigned int port;
+};
+
+struct call_args {
+ unsigned int prog;
+ unsigned int vers;
+ unsigned int proc;
+ opaque args<>;
+};
+
+
+program PMAP_PROGRAM {
+ version PMAP_V2 {
+ void
+ PMAP_NULL(void) = 0;
+
+ bool
+ PMAP_SET(mapping) = 1;
+
+ bool
+ PMAP_UNSET(mapping) = 2;
+
+ unsigned int
+ PMAP_GETPORT(mapping) = 3;
+ } = 2;
+} = 100000;
+