Merge branch 'master' into issues-199

libnfs-4.0.0-vitalif
Ronnie Sahlberg 2017-05-09 14:49:58 -07:00 committed by GitHub
commit ebd98bf966
45 changed files with 11077 additions and 440 deletions

36
CHANGELOG Normal file
View File

@ -0,0 +1,36 @@
Changes since 1.11.0
Add a new mkdir2 command that also takes a mode argument.
Add support for RPC timeouts for the async interface.
Fix NULL pointer read in nfs_link()
Clamp read/write size for servers (Ganesha) that offer very large io sizes
instead of failing to connect to the export
Tell the server to commit all data to stable storage when we close files.
Double free fix: don't call rpc_free_pdu() after rpc_queue_pdu() failure
bootstrap updates
Build fixes for Mingw and Cygwin
Update README to document two new Windows builds
Fix for memory leak in rpc_allocate_*()
Use SOCK_CLOEXEC for the sockets
Make rpc_set{g|u}id() public
Performance optimization: socket: Batch pdu read in rpc_read_from_socket
Low level support for NFSv4 and some examples
Support for building RPC servers
README updates
Fixes to build nfs-ls and nfs-cp on win32

View File

@ -1,4 +1,4 @@
SUBDIRS = doc mount nfs nlm nsm portmap rquota lib include $(MAYBE_UTILS) . $(MAYBE_EXAMPLES)
SUBDIRS = doc mount nfs nfs4 nlm nsm portmap rquota lib include $(MAYBE_UTILS) . $(MAYBE_EXAMPLES)
ACLOCAL_AMFLAGS = -I m4
pkgconfigdir = $(libdir)/pkgconfig

35
README
View File

@ -23,9 +23,21 @@ stat(), read(), ...
examples/nfsclient-sync.c provides examples on how to use this API
NFSv4:
======
NFSv4 is supported but only for the RAW ASYNC interface.
Examples/nfsv4-cat.c is a "simple" example to illustrate how to use
NFSv4 to connect to a server and read a file off the server.
SERVER SUPPORT:
===============
Libnfs supports building RPC servers.
Examples/portmapper-server.c is a small "portmapper" example written using
libnfs.
URL-FORMAT:
===========
Libnfs uses RFC2224 style URLs extended with libnfs specific url arguments some minor extensions.
Libnfs uses RFC2224 style URLs extended with some minor libnfs extensions.
The basic syntax of these URLs is :
nfs://<server|ipv4|ipv6>/path[?arg=val[&arg=val]*]
@ -54,9 +66,9 @@ both these exports as well.
The reason is because the NFSv3 protocol does not allow a client request
to return data for an object in a different filesystem/mount.
(legacy, but it is what it is. One reason for this restriction is to
guarantee that inodes are uniqe across the mounted system.)
guarantee that inodes are unique across the mounted system.)
This option, when enabled will make libnfs perform all these mounts
This option, when enabled, will make libnfs perform all these mounts
internally for you. This means that one libnfs mount may now have files
with duplicate inode values so if you cache files based on inode
make sure you cache files based on BOTH st.st_ino and st.st_dev.
@ -72,16 +84,19 @@ ports from connecting.
These servers require you use the "insecure" export option in /etc/exports
in order to allow libnfs clients to be able to connect.
Some versions of Linux support special capabilities that can be assigned to
programs to allow non-root users to bind to system ports.
On Linux we can get around this restriction by setting the NET_BIND_SERVICE
capability for the application binary.
This is set up by running
sudo setcap 'cap_net_bind_service=+ep' /path/to/executable
When libnfs is linked against an executable with this special capability
assigned to it, libnfs may be able to use system ports even when executing
under the privilege of a non-root user account.
This capability allows the binary to use systems ports like this even when
not running as root. Thus if you set this capability for your application
you no longer need to edit the export on the NFS server to set "insecure".
This is highly non-portable so IF this works on your linux system, count
yourself lucky.
I do not know what equivalent "capability" support is available on other
platforms. Please drop me an email if your os of choice has something similar
and I can add it to the README.
DOCUMENTATION

View File

@ -1,2 +1,2 @@
#!/bin/sh
autoreconf -vif
#!/bin/sh -e
exec autoreconf -vif

63
configure.ac Normal file → Executable file
View File

@ -22,7 +22,7 @@ if test "$SAVE_CFLAGS" = "x"; then
fi
# We always want 64 bit file offsets
CFLAGS="${CFLAGS} -D_FILE_OFFSET_BITS=64"
AC_SYS_LARGEFILE
#option: utils
AC_ARG_ENABLE([utils],
@ -42,29 +42,19 @@ AC_ARG_ENABLE([examples],
# We need popt to compile the examples
if test x$ENABLE_EXAMPLES = xyes; then
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([
LIBS="$LIBS -lpopt"
AC_TRY_LINK([#include <popt.h>], [
/*
* Just see if we can compile/link with popt
*/
#include <popt.h>
int main(int argc, const char *argv[])
{
int _argc;
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"
poptGetContext(_argv[0], _argc, _argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
], ac_cv_have_popt=yes, ac_cv_have_popt=no)
LIBS="$ac_save_LIBS"
if test "$ac_cv_have_popt" = yes ; then
AC_MSG_RESULT(yes)
@ -79,20 +69,9 @@ fi
AC_SUBST(MAYBE_EXAMPLES)
AC_MSG_CHECKING(whether SO_BINDTODEVICE is available)
AC_TRY_RUN([
/*
* Just see if we can compile with SO_BINDTODEVICE
*/
#include <net/if.h>
int main(int argc, const char *argv[])
{
AC_TRY_COMPILE([#include <net/if.h>], [
int i = SO_BINDTODEVICE;
return 0;
}
], ac_cv_have_so_bindtodevice=yes, ac_cv_have_so_bindtodevice=no,
[echo $ac_n "compile with SO_BINDTODEVICE. Assuming OK... $ac_c"
ac_cv_have_so_bindtodevice=yes])
], ac_cv_have_so_bindtodevice=yes, ac_cv_have_so_bindtodevice=no)
if test "$ac_cv_have_so_bindtodevice" = yes ; then
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SO_BINDTODEVICE, 1, [Whether our sockets support SO_BINDTODEVICE])
@ -123,7 +102,7 @@ case $host in
AC_CHECK_LIB([socket], [main], , [AC_MSG_ERROR([Can not find required library])])
AC_CHECK_LIB([nsl], [main], , [AC_MSG_ERROR([Can not find required library])])
;;
*mingw32* | *cygwin* | *wince* | *mingwce*)
*mingw32* | *wince* | *mingwce*)
LIBSOCKET='-lws2_32'
SYS=mingw32
;;
@ -133,6 +112,10 @@ esac
AM_CONDITIONAL(HAVE_WIN32, test "${SYS}" = "mingw32")
AC_SUBST([LIBSOCKET])
# check for sys/sysmacros.h
dnl Check for sys/sysmacros.h
AC_CHECK_HEADERS([sys/sysmacros.h])
# check for poll.h
dnl Check for poll.h
AC_CHECK_HEADERS([poll.h])
@ -169,6 +152,10 @@ AC_CHECK_HEADERS([sys/vfs.h])
dnl Check for sys/statvfs.h
AC_CHECK_HEADERS([sys/statvfs.h])
# check for fuse.h
dnl Check for fuse.h
AC_CHECK_HEADERS([fuse.h])
# check for sys/socket.h
dnl Check for sys/socket.h
AC_CHECK_HEADERS([sys/socket.h])
@ -205,6 +192,19 @@ AC_CHECK_MEMBER([struct sockaddr_storage.ss_family],
#include <sys/socket.h>
])
# check for tevent + talloc
AC_CACHE_CHECK([for talloc and tevent support],libnfs_cv_HAVE_TALLOC_TEVENT,[
AC_TRY_COMPILE([
#include <talloc.h>
#include <tevent.h>],
[struct tevent_context *ctx = tevent_context_init(NULL);
int major = talloc_version_major();],
libiscsi_cv_HAVE_TALLOC_TEVENT=yes,libiscsi_cv_HAVE_TALLOC_TEVENT=no)])
if test x"$libiscsi_cv_HAVE_TALLOC_TEVENT" = x"yes"; then
AC_DEFINE(HAVE_TALLOC_TEVENT,1,[Whether we have talloc nad tevent support])
fi
AM_CONDITIONAL([HAVE_TALLOC_TEVENT], [test $libiscsi_cv_HAVE_TALLOC_TEVENT = yes])
AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec])
# check where makedev is defined
@ -217,6 +217,7 @@ AC_CONFIG_FILES([Makefile]
[lib/Makefile]
[mount/Makefile]
[nfs/Makefile]
[nfs4/Makefile]
[nlm/Makefile]
[nsm/Makefile]
[portmap/Makefile]

View File

@ -1,4 +1,8 @@
noinst_PROGRAMS = nfsclient-async nfsclient-raw nfsclient-sync nfsclient-bcast nfsclient-listservers nfs-io portmap-client
noinst_PROGRAMS = nfsclient-async nfsclient-raw nfsclient-sync nfsclient-bcast nfsclient-listservers nfs-io nfs-ln nfs4-cat portmap-client portmap-server
if HAVE_TALLOC_TEVENT
noinst_PROGRAMS += nfs4-cat-talloc
endif
AM_CPPFLAGS = \
-I$(abs_top_srcdir)/include \
@ -6,6 +10,7 @@ AM_CPPFLAGS = \
-I$(abs_top_srcdir)/include/win32 \
-I$(abs_top_srcdir)/mount \
-I$(abs_top_srcdir)/nfs \
-I$(abs_top_srcdir)/nfs4 \
-I$(abs_top_srcdir)/portmap \
-I$(abs_top_srcdir)/rquota \
"-D_U_=__attribute__((unused))"
@ -17,4 +22,8 @@ nfsclient_sync_LDADD = $(COMMON_LIBS)
nfsclient_bcast_LDADD = $(COMMON_LIBS)
nfsclient_listservers_LDADD = $(COMMON_LIBS)
nfs_io_LDADD = $(COMMON_LIBS)
nfs_ln_LDADD = $(COMMON_LIBS)
nfs4_cat_LDADD = $(COMMON_LIBS) -levent
nfs4_cat_talloc_LDADD = $(COMMON_LIBS) -ltevent -ltalloc
portmap_client_LDADD = $(COMMON_LIBS)
portmap_server_LDADD = $(COMMON_LIBS) -levent

125
examples/nfs-ln.c Normal file
View File

@ -0,0 +1,125 @@
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
/*
Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2017
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#define _FILE_OFFSET_BITS 64
#define _GNU_SOURCE
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef AROS
#include "aros_compat.h"
#endif
#ifdef WIN32
#include "win32_compat.h"
#pragma comment(lib, "ws2_32.lib")
WSADATA wsaData;
#define PRId64 "ll"
#else
#include <inttypes.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#ifndef AROS
#include <sys/statvfs.h>
#endif
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "libnfs.h"
#include "libnfs-raw.h"
#include "libnfs-raw-mount.h"
void print_usage(void)
{
fprintf(stderr, "Usage: nfs-ln <url> <old-path> <new-path>\n");
}
int main(int argc, char *argv[])
{
int ret = 1;
struct nfs_context *nfs = NULL;
struct nfsfh *nfsfh = NULL;
struct nfs_url *url = NULL;
#ifdef WIN32
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
printf("Failed to start Winsock2\n");
exit(10);
}
#endif
#ifdef AROS
aros_init_socket();
#endif
if (argc != 4) {
print_usage();
goto finished;
}
nfs = nfs_init_context();
if (nfs == NULL) {
printf("failed to init context\n");
goto finished;
}
url = nfs_parse_url_full(nfs, argv[1]);
if (url == NULL) {
fprintf(stderr, "%s\n", nfs_get_error(nfs));
goto finished;
}
if (nfs_mount(nfs, url->server, url->path) != 0) {
fprintf(stderr, "Failed to mount nfs share : %s\n",
nfs_get_error(nfs));
goto finished;
}
ret = nfs_link(nfs, argv[2], argv[3]);
if (ret) {
fprintf(stderr, "nfs_link() failed with %s\n",
nfs_get_error(nfs));
goto finished;
}
finished:
if (ret > 0) {
print_usage();
}
nfs_destroy_url(url);
if (nfs != NULL) {
if (nfsfh) {
nfs_close(nfs, nfsfh);
}
nfs_destroy_context(nfs);
}
return !!ret;
}

968
examples/nfs4-cat-talloc.c Normal file
View File

@ -0,0 +1,968 @@
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
/* THIS IS NOT A PROPER NFS4 CLIENT!
* This software is only meant to illustrate how to plug libnfs into
* an eventsystem like libevent and then use the raw rpc api
* connect to an nfsv4 server and read a file.
* If any kind of error occurs it will immediately terminate by calling
* exit() without even attempting to cleanup.
* If the access to the server is successful it should however run valgrind
* clean.
*
* NFSv4 access is done through the raw async interface and is cumbersome
* to use for NFSv4 due to the richness of the protocol.
* A future aim will be to build better helper functions to make ease
* of use better.
*/
/*
Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2015
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#define _FILE_OFFSET_BITS 64
#define _GNU_SOURCE
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef AROS
#include "aros_compat.h"
#endif
#ifdef WIN32
#include "win32_compat.h"
#pragma comment(lib, "ws2_32.lib")
WSADATA wsaData;
#else
#include <sys/stat.h>
#include <string.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include "libnfs.h"
#include "libnfs-raw.h"
#include "libnfs-raw-nfs4.h"
#include <tevent.h>
#include <talloc.h>
struct tevent_context *ev;
struct client {
struct nfs_context *nfs;
struct rpc_context *rpc;
char *server;
char *path;
struct tevent_fd *fde;
int callback_fd;
/* For SETCLIENTID */
verifier4 verifier;
char *id;
clientid4 clientid;
verifier4 setclientid_confirm;
/* For OPEN */
char *owner;
int op_len;
/* filehandle and state for the open file */
nfs_fh4 fh;
uint32_t seqid;
stateid4 stateid;
/* offset when reading */
uint64_t offset;
int is_finished;
};
static void set_nonblocking(int fd)
{
int v = 0;
#if defined(WIN32)
long nonblocking=1;
v = ioctl(fd, FIONBIO, &nonblocking);
#else
v = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, v | O_NONBLOCK);
#endif
}
static int client_destructor(struct client *c)
{
if (c->nfs) {
nfs_destroy_context(c->nfs);
}
if (c->callback_fd != -1) {
close(c->callback_fd);
}
};
void usage(void)
{
fprintf(stderr, "Usage: nfs4-cat-talloc <file>\n");
fprintf(stderr, " <file> is an nfs url.\n");
exit(0);
}
static void update_events(struct rpc_context *rpc,
struct tevent_fd *fde)
{
int events = rpc_which_events(rpc);
int flags = 0;
if (events & POLLIN) {
flags |= TEVENT_FD_READ;
}
if (events & POLLOUT) {
flags |= TEVENT_FD_WRITE;
}
tevent_fd_set_flags(fde, flags);
}
struct server {
struct rpc_context *rpc;
struct tevent_fd *fde;
};
/*
* Helper functions to send client RPC requests.
*/
static void send_setclientid(struct rpc_context *rpc,
rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
SETCLIENTID4args *sc4args;
nfs_argop4 op[1];
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
struct sockaddr_in *in;
struct sockaddr_in6 *in6;
char *netid;
char str[240], addr[256];
unsigned short port;
if (getsockname(client->callback_fd, (struct sockaddr *)&ss, &len) < 0) {
fprintf(stderr, "getsockaddr failed\n");
talloc_free(client);
exit(10);
}
switch (ss.ss_family) {
case AF_INET:
netid = "tcp";
in = (struct sockaddr_in *)&ss;
inet_ntop(AF_INET, &in->sin_addr, str, sizeof(str));
port = ntohs(in->sin_port);
break;
case AF_INET6:
netid = "tcp6";
in6 = (struct sockaddr_in6 *)&ss;
inet_ntop(AF_INET6, &in6->sin6_addr, str, sizeof(str));
port = ntohs(in6->sin6_port);
break;
}
sprintf(addr, "%s.%d.%d", str, port >> 8, port & 0xff);
memset(op, 0, sizeof(op));
op[0].argop = OP_SETCLIENTID;
sc4args = &op[0].nfs_argop4_u.opsetclientid;
memcpy(sc4args->client.verifier, client->verifier, sizeof(verifier4));
sc4args->client.id.id_len = strlen(client->id);
sc4args->client.id.id_val = client->id;
sc4args->callback.cb_program = NFS4_CALLBACK;
sc4args->callback.cb_location.r_netid = netid;
sc4args->callback.cb_location.r_addr = addr;
sc4args->callback_ident = 0x00000001;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 SETCLIENTID request\n");
talloc_free(client);
exit(10);
}
}
static void send_setclientid_confirm(struct rpc_context *rpc,
rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
SETCLIENTID_CONFIRM4args *scc4args;
nfs_argop4 op[1];
memset(op, 0, sizeof(op));
op[0].argop = OP_SETCLIENTID_CONFIRM;
scc4args = &op[0].nfs_argop4_u.opsetclientid_confirm;
scc4args->clientid = client->clientid;
memcpy(scc4args->setclientid_confirm, client->setclientid_confirm,
NFS4_VERIFIER_SIZE);
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 SETCLIENTID_CONFIRM request\n");
talloc_free(client);
exit(10);
}
}
static void send_getrootfh(struct rpc_context *rpc,
rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
nfs_argop4 op[2];
memset(op, 0, sizeof(op));
op[0].argop = OP_PUTROOTFH;
op[1].argop = OP_GETFH;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 GETROOTFH request\n");
talloc_free(client);
exit(10);
}
}
static void send_open(struct rpc_context *rpc, nfs_fh4 dir, char *path,
rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
ACCESS4args *a4args;
LOOKUP4args *l4args;
OPEN4args *o4args;
nfs_argop4 *op;
int i = 0, idx = 0;
char *tmp;
/*
* Count how many directories we have in the path.
*/
tmp = path;
while (tmp = strchr(tmp, '/')) {
i++;
tmp++;
}
op = talloc_zero_array(client, nfs_argop4, 4 + i);
op[idx].argop = OP_PUTFH;
op[idx].nfs_argop4_u.opputfh.object = dir;
idx++;
while (i-- > 0) {
tmp = strchr(path, '/');
*tmp++ = '\0';
op[idx].argop = OP_LOOKUP;
l4args = &op[idx].nfs_argop4_u.oplookup;
l4args->objname.utf8string_len = strlen(path);
l4args->objname.utf8string_val = path;
idx++;
path = tmp;
}
op[idx].argop = OP_OPEN;
o4args = &op[idx].nfs_argop4_u.opopen;
o4args->seqid = client->seqid;
o4args->share_access = OPEN4_SHARE_ACCESS_READ;
o4args->share_deny = OPEN4_SHARE_DENY_NONE;
o4args->owner.clientid = client->clientid;
o4args->owner.owner.owner_len = strlen(client->owner);
o4args->owner.owner.owner_val = client->owner;
o4args->openhow.opentype = OPEN4_NOCREATE;
o4args->claim.claim = CLAIM_NULL;
o4args->claim.open_claim4_u.file.utf8string_len = strlen(path);
o4args->claim.open_claim4_u.file.utf8string_val = path;
idx++;
op[idx].argop = OP_GETFH;
idx++;
op[idx].argop = OP_ACCESS;
a4args = &op[idx].nfs_argop4_u.opaccess;
a4args->access = ACCESS4_READ;
client->seqid++;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = idx;
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 OPEN request\n");
talloc_free(client);
exit(10);
}
talloc_free(op);
}
static void send_open_confirm(struct rpc_context *rpc, nfs_fh4 object, rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
OPEN_CONFIRM4args *oc4args;
PUTFH4args *pfh4args;
nfs_argop4 op[2];
memset(op, 0, sizeof(op));
op[0].argop = OP_PUTFH;
pfh4args = &op[0].nfs_argop4_u.opputfh;
pfh4args->object = object;
op[1].argop = OP_OPEN_CONFIRM;
oc4args = &op[1].nfs_argop4_u.opopen_confirm;
oc4args->open_stateid.seqid = client->seqid;
memcpy(oc4args->open_stateid.other,
client->stateid.other, 12);
oc4args->seqid = client->seqid;
client->seqid++;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 CLOSE request\n");
talloc_free(client);
exit(10);
}
}
static void send_read(struct rpc_context *rpc, nfs_fh4 object,
uint64_t offset, uint32_t count,
rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
PUTFH4args *pfh4args;
READ4args *r4args;
nfs_argop4 op[3];
memset(op, 0, sizeof(op));
op[0].argop = OP_PUTFH;
pfh4args = &op[0].nfs_argop4_u.opputfh;
pfh4args->object = object;
op[1].argop = OP_READ;
r4args = &op[1].nfs_argop4_u.opread;
r4args->stateid.seqid = client->seqid;
memcpy(r4args->stateid.other, client->stateid.other, 12);
r4args->offset = offset;
r4args->count = count;
op[2].argop = OP_GETATTR;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 READ request\n");
talloc_free(client);
exit(10);
}
}
static void send_close(struct rpc_context *rpc, nfs_fh4 object,
rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
CLOSE4args *c4args;
PUTFH4args *pfh4args;
nfs_argop4 op[2];
memset(op, 0, sizeof(op));
op[0].argop = OP_PUTFH;
pfh4args = &op[0].nfs_argop4_u.opputfh;
pfh4args->object = object;
op[1].argop = OP_CLOSE;
c4args = &op[1].nfs_argop4_u.opclose;
c4args->seqid = client->seqid;
c4args->open_stateid.seqid = client->seqid;
memcpy(c4args->open_stateid.other, client->stateid.other, 12);
client->seqid++;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 CLOSE request\n");
talloc_free(client);
exit(10);
}
}
/*
* Callbacks for completed requests.
*/
void close_cb(struct rpc_context *rpc, int status, void *data,
void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
/*
* FINISHED
*/
/*
* Note that we can not start tearing down and destroying the contexts
* right here as we are still in a callback from ... rpc_service().
* Instead flag that we should abort and start doing the teardown
* in client_io once we return from libnfs.
*/
client->is_finished = 1;
}
void read_cb(struct rpc_context *rpc, int status, void *data,
void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
struct READ4res *r4res;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to read file on server %s\n",
client->server);
talloc_free(client);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to read file on server %s\n",
client->server);
talloc_free(client);
exit(10);
}
r4res = &res->resarray.resarray_val[1].nfs_resop4_u.opread;
write(1,
r4res->READ4res_u.resok4.data.data_val,
r4res->READ4res_u.resok4.data.data_len);
/*
* Are we at end-of-file? If so we can close the file and exit.
*/
if (r4res->READ4res_u.resok4.eof) {
send_close(rpc, client->fh, close_cb, client);
return;
}
/*
* We still have more data to read.
*/
client->offset += r4res->READ4res_u.resok4.data.data_len;
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
}
void open_confirm_cb(struct rpc_context *rpc, int status, void *data,
void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to confirm open file on server %s\n",
client->server);
talloc_free(client);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to confirm open file on server %s\n",
client->server);
talloc_free(client);
exit(10);
}
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
}
void open_cb(struct rpc_context *rpc, int status, void *data,
void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
GETFH4res *gfh4res;
OPEN4res *o4res;
int idx;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to open file on server %s\n",
client->server);
talloc_free(client);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to open file on server %s\n",
client->server);
talloc_free(client);
exit(10);
}
/* Find the index for the OPEN opcode */
for (idx = 1; idx < res->resarray.resarray_len - 1; idx++) {
if ((res->resarray.resarray_val[idx].resop == OP_OPEN) &&
(res->resarray.resarray_val[idx + 1].resop == OP_GETFH)) {
break;
}
}
if (idx >= res->resarray.resarray_len - 1) {
fprintf(stderr, "No OP_OPEN in server response\n");
talloc_free(client);
exit(10);
}
/* Store the open handle in the client structure */
gfh4res = &res->resarray.resarray_val[idx+1].nfs_resop4_u.opgetfh;
client->fh.nfs_fh4_len = gfh4res->GETFH4res_u.resok4.object.nfs_fh4_len;
client->fh.nfs_fh4_val = talloc_size(client, client->fh.nfs_fh4_len);
if (client->fh.nfs_fh4_val == NULL) {
fprintf(stderr, "Failed to allocate data for nfs_fh4\n");
talloc_free(client);
exit(10);
}
memcpy(client->fh.nfs_fh4_val,
gfh4res->GETFH4res_u.resok4.object.nfs_fh4_val,
client->fh.nfs_fh4_len);
/* Store stateid for the open handle in the client structure */
o4res = &res->resarray.resarray_val[idx].nfs_resop4_u.opopen;
client->stateid.seqid = o4res->OPEN4res_u.resok4.stateid.seqid;
memcpy(client->stateid.other,
o4res->OPEN4res_u.resok4.stateid.other, 12);
/* Check if server wants us to confirm the open */
if (o4res->OPEN4res_u.resok4.rflags & OPEN4_RESULT_CONFIRM) {
send_open_confirm(rpc, client->fh, open_confirm_cb, client);
return;
}
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
}
void getrootfh_cb(struct rpc_context *rpc, int status, void *data,
void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
GETFH4res *gfh4res;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to get root filehandle of server %s\n",
client->server);
talloc_free(client);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to get root filehandle of server %s\n",
client->server);
talloc_free(client);
exit(10);
}
gfh4res = &res->resarray.resarray_val[1].nfs_resop4_u.opgetfh;
send_open(rpc, gfh4res->GETFH4res_u.resok4.object,
client->path, open_cb, client);
}
void setclientid_confirm_cb(struct rpc_context *rpc, int status, void *data,
void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
char *path;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to set client id of server %s\n",
client->server);
talloc_free(client);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to set client id of server %s\n",
client->server);
talloc_free(client);
exit(10);
}
send_getrootfh(rpc, getrootfh_cb, client);
}
void setclientid_cb(struct rpc_context *rpc, int status, void *data,
void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
SETCLIENTID4res *sc4res;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to set client id on server %s\n",
client->server);
talloc_free(client);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to set client id on server %s\n",
client->server);
talloc_free(client);
exit(10);
}
sc4res = &res->resarray.resarray_val[0].nfs_resop4_u.opsetclientid;
client->clientid = sc4res->SETCLIENTID4res_u.resok4.clientid;
memcpy(client->setclientid_confirm,
sc4res->SETCLIENTID4res_u.resok4.setclientid_confirm,
NFS4_VERIFIER_SIZE);
send_setclientid_confirm(rpc, setclientid_confirm_cb, client);
}
/*
* NULL procedure for the callback protocol.
*/
static int cb_null_proc(struct rpc_context *rpc, struct rpc_msg *call)
{
rpc_send_reply(rpc, call, NULL, (zdrproc_t)zdr_void, 0);
return 0;
}
/*
* CB_COMPOUND procedure for the callback protocol.
* This is where the server will inform us about lease breaks and similar.
*/
static int cb_compound_proc(struct rpc_context *rpc, struct rpc_msg *call)
{
CB_COMPOUND4args *args = call->body.cbody.args;
fprintf(stderr, "cb_compund_cb. Do something here.\n");
return 0;
}
struct service_proc pt[] = {
{CB_NULL, cb_null_proc,
(zdrproc_t)zdr_void, 0},
{CB_COMPOUND, cb_compound_proc,
(zdrproc_t)zdr_CB_COMPOUND4args, sizeof(CB_COMPOUND4args)},
};
static void server_io(struct tevent_context *ev, struct tevent_fd *fde,
uint16_t events, void *private_data)
{
struct server *server = private_data;
int revents = 0;
if (events & TEVENT_FD_READ) {
revents |= POLLIN;
}
if (events & TEVENT_FD_WRITE) {
revents |= POLLOUT;
}
if (rpc_service(server->rpc, revents) < 0) {
talloc_free(server);
return;
}
update_events(server->rpc, server->fde);
}
static int server_destructor(struct server *s)
{
if (s->rpc) {
rpc_destroy_context(s->rpc);
}
}
/*
* This callback is invoked when others (the nfsv4 server) initiates a
* NFSv4 CALLBACK sessions to us.
* We accept() the connection and create a local rpc server context
* for the callback protocol.
*/
static void client_accept(struct tevent_context *ev, struct tevent_fd *fde,
uint16_t events, void *private_data)
{
struct client *client = private_data;
struct server *server;
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
int fd;
server = talloc_zero(client, struct server);
talloc_set_destructor(server, server_destructor);
if ((fd = accept(client->callback_fd, (struct sockaddr *)&ss, &len)) < 0) {
fprintf(stderr, "accept failed\n");
talloc_free(server);
return;
}
set_nonblocking(fd);
server->rpc = rpc_init_server_context(fd);
if (server->rpc == NULL) {
fprintf(stderr, "Failed to create server rpc context\n");
talloc_free(server);
return;
}
rpc_register_service(server->rpc, NFS4_CALLBACK, NFS_CB,
pt, sizeof(pt) / sizeof(pt[0]));
server->fde = tevent_add_fd(ev, server, fd, TEVENT_FD_READ,
server_io, server);
tevent_fd_set_auto_close(server->fde);
update_events(server->rpc, server->fde);
}
/*
* This callback is invoked when our async connect() to the server has
* completed. At this point we know which IP address was used locally for
* the connection and can bind our nfsv4 callback server instance to it.
*/
void connect_cb(struct rpc_context *rpc, int status, void *data,
void *private_data)
{
struct client *client = private_data;
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
struct sockaddr_in *in;
struct sockaddr_in6 *in6;
struct tevent_fd *fde;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "connection to NFSv4 server %s failed\n",
client->server);
talloc_free(client);
exit(10);
}
/*
* NFSv4 CALLBACK
* Now that we have a client connection we can register a callback
* server port on the same IP address as was used to the outgoing
* client connection. That way we know that the address used by the
* server is routable, and uses the same version of ip, that the client
* supports and can route to.
*/
if (getsockname(rpc_get_fd(rpc), (struct sockaddr *)&ss, &len) < 0) {
fprintf(stderr, "getsockaddr failed\n");
talloc_free(client);
exit(10);
}
switch (ss.ss_family) {
case AF_INET:
in = (struct sockaddr_in *)&ss;
in->sin_port=0;
break;
case AF_INET6:
in6 = (struct sockaddr_in6 *)&ss;
in6->sin6_port=0;
break;
default:
fprintf(stderr, "Can not handle AF_FAMILY:%d", ss.ss_family);
talloc_free(client);
exit(10);
}
client->callback_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client->callback_fd == -1) {
fprintf(stderr, "Failed to create callback socket\n");
talloc_free(client);
exit(10);
}
set_nonblocking(client->callback_fd);
if (bind(client->callback_fd, (struct sockaddr *)&ss, sizeof(ss)) < 0) {
fprintf(stderr, "Failed to bind callback socket\n");
talloc_free(client);
exit(10);
}
if (listen(client->callback_fd, 16) < 0) {
fprintf(stderr, "failed to listen to callback socket\n");
talloc_free(client);
exit(10);
}
fde = tevent_add_fd(ev, client, client->callback_fd, TEVENT_FD_READ,
client_accept, private_data);
tevent_fd_set_auto_close(fde);
update_events(client->rpc, client->fde);
/*
* Now that we are finished setting up the callback server port
* we can proceed and negotiate the nfsv4 client id.
*/
send_setclientid(rpc, setclientid_cb, client);
}
static void client_io(struct tevent_context *ev, struct tevent_fd *fde,
uint16_t events, void *private_data)
{
struct client *client = private_data;
int revents = 0;
if (events & TEVENT_FD_READ) {
revents |= POLLIN;
}
if (events & TEVENT_FD_WRITE) {
revents |= POLLOUT;
}
if (rpc_service(client->rpc, revents) < 0) {
fprintf(stderr, "rpc_service failed\n");
talloc_free(client);
exit(10);
}
update_events(client->rpc, client->fde);
if (client->is_finished) {
talloc_free(client);
}
}
int main(int argc, char *argv[])
{
TALLOC_CTX *ctx = talloc_new(NULL);
struct client *client;
struct nfs_url *url;
int i, fd;
#ifdef WIN32
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
fprintf(stderr, "Failed to start Winsock2\n");
exit(10);
}
#endif
#ifdef AROS
aros_init_socket();
#endif
srandom(time(NULL) ^ getpid());
if (argc < 2) {
usage();
}
ev = tevent_context_init(ctx);
client = talloc_zero(ctx, struct client);
talloc_set_destructor(client, client_destructor);
client->callback_fd = -1;
client->nfs = nfs_init_context();
if (client->nfs == NULL) {
fprintf(stderr, "failed to init nfs context\n");
talloc_free(ctx);
exit(10);
}
url = nfs_parse_url_dir(client->nfs, argv[1]);
if (url == NULL) {
fprintf(stderr, "failed to parse url\n");
talloc_free(ctx);
exit(10);
}
client->server = talloc_strdup(client, url->server);
client->path = talloc_strdup(client, &url->path[1]); // skip leading '/'
nfs_destroy_url(url);
for (i = 0; i < NFS4_VERIFIER_SIZE; i++) {
client->verifier[i] = random() & 0xff;
}
client->id = talloc_asprintf(client, "Libnfs %s tcp pid:%d",
argv[1], getpid());
client->owner = talloc_asprintf(client, "open id:libnfs pid:%d",
getpid());
/*
* From here on we will mainly use the rpc context directly
* and not the nfs context so lets store the rpc context here
* for easy access.
*/
client->rpc = nfs_get_rpc_context(client->nfs);
if (rpc_connect_program_async(client->rpc, client->server,
NFS4_PROGRAM, NFS_V4,
connect_cb, client) != 0) {
fprintf(stderr, "Failed to start connection: %s\n",
rpc_get_error(client->rpc));
talloc_free(ctx);
exit(10);
}
/*
* Set up the events we need for the outgoing client RPC channel.
*/
fd = rpc_get_fd(client->rpc);
client->fde = tevent_add_fd(ev, client, fd, TEVENT_FD_READ,
client_io, (void *)client);
update_events(client->rpc, client->fde);
tevent_loop_wait(ev);
talloc_free(ctx);
return 0;
}

943
examples/nfs4-cat.c Normal file
View File

@ -0,0 +1,943 @@
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
/* THIS IS NOT A PROPER NFS4 CLIENT!
* This software is only meant to illustrate how to plug libnfs into
* an eventsystem like libevent and then use the raw rpc api
* connect to an nfsv4 server and read a file.
* If any kind of error occurs it will immediately terminate by calling
* exit() without even attempting to cleanup.
* If the access to the server is successful it should however run valgrind
* clean.
*
* NFSv4 access is done through the raw async interface and is cumbersome
* to use for NFSv4 due to the richness of the protocol.
* A future aim will be to build better helper functions to make ease
* of use better.
*/
/*
Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2015
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#define _FILE_OFFSET_BITS 64
#define _GNU_SOURCE
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef AROS
#include "aros_compat.h"
#endif
#ifdef WIN32
#include "win32_compat.h"
#pragma comment(lib, "ws2_32.lib")
WSADATA wsaData;
#else
#include <sys/stat.h>
#include <string.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include "libnfs.h"
#include "libnfs-raw.h"
#include "libnfs-raw-nfs4.h"
#include <event2/event.h>
struct event_base *base;
struct client {
struct rpc_context *rpc;
struct event *read_event;
struct event *write_event;
struct event *listen_event;
char *server;
char *path;
int op_len;
int is_finished;
verifier4 verifier;
char *id;
char *owner;
clientid4 clientid;
verifier4 setclientid_confirm;
/* filehandle and state for the open file */
nfs_fh4 fh;
uint32_t seqid;
stateid4 stateid;
/* offset when reading */
uint64_t offset;
int callback_fd;
};
struct server {
struct server *next;
struct rpc_context *rpc;
struct event *read_event;
struct event *write_event;
};
struct server *server_list;
void usage(void)
{
fprintf(stderr, "Usage: nfs4-cat <file>\n");
fprintf(stderr, " <file> is an nfs url.\n");
exit(0);
}
static void update_events(struct rpc_context *rpc, struct event *read_event,
struct event *write_event)
{
int events = rpc_which_events(rpc);
if (read_event) {
if (events & POLLIN) {
event_add(read_event, NULL);
} else {
event_del(read_event);
}
}
if (write_event) {
if (events & POLLOUT) {
event_add(write_event, NULL);
} else {
event_del(write_event);
}
}
}
static void free_server(struct server *server)
{
if (server->rpc) {
rpc_disconnect(server->rpc, NULL);
rpc_destroy_context(server->rpc);
server->rpc = NULL;
}
if (server->read_event) {
event_free(server->read_event);
server->read_event = NULL;
}
if (server->write_event) {
event_free(server->write_event);
server->write_event = NULL;
}
free(server);
}
static void server_io(evutil_socket_t fd, short events, void *private_data)
{
struct server *server = private_data;
int revents = 0;
if (events & EV_READ) {
revents |= POLLIN;
}
if (events & EV_WRITE) {
revents |= POLLOUT;
}
if (rpc_service(server->rpc, revents) < 0) {
fprintf(stderr, "rpc_service() failed for server\n");
exit(10);
}
update_events(server->rpc, server->read_event, server->write_event);
}
static void client_io(evutil_socket_t fd, short events, void *private_data)
{
struct client *client = private_data;
struct server *server;
int revents = 0;
if (events & EV_READ) {
revents |= POLLIN;
}
if (events & EV_WRITE) {
revents |= POLLOUT;
}
if (rpc_service(client->rpc, revents) < 0) {
fprintf(stderr, "rpc_service failed\n");
exit(10);
}
update_events(client->rpc, client->read_event, client->write_event);
if (client->is_finished) {
/*
* Stop listening for new connections.
*/
event_free(client->listen_event);
client->listen_event = NULL;
/*
* Stop listening for events on the client context.
*/
event_free(client->read_event);
client->read_event = NULL;
event_free(client->write_event);
client->write_event = NULL;
/*
* Stop listening to server connections.
*/
for (server = server_list; server; server = server->next) {
if (server->read_event) {
event_free(server->read_event);
server->read_event = NULL;
}
if (server->write_event) {
event_free(server->write_event);
server->write_event = NULL;
}
}
}
}
/*
* Helper functions to send client RPC requests.
*/
static void send_setclientid_confirm(struct rpc_context *rpc,
rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
nfs_argop4 op[1];
memset(op, 0, sizeof(op));
op[0].argop = OP_SETCLIENTID_CONFIRM;
op[0].nfs_argop4_u.opsetclientid_confirm.clientid = client->clientid;
memcpy(op[0].nfs_argop4_u.opsetclientid_confirm.setclientid_confirm, client->setclientid_confirm, NFS4_VERIFIER_SIZE);
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 SETCLIENTID_CONFIRM request\n");
exit(10);
}
}
static void send_setclientid(struct rpc_context *rpc,
rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
nfs_argop4 op[1];
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
struct sockaddr_in *in;
struct sockaddr_in6 *in6;
char *netid;
char str[240], addr[256];
unsigned short port;
if (getsockname(client->callback_fd, (struct sockaddr *)&ss, &len) < 0) {
fprintf(stderr, "getsockaddr failed\n");
exit(10);
}
switch (ss.ss_family) {
case AF_INET:
netid = "tcp";
in = (struct sockaddr_in *)&ss;
inet_ntop(AF_INET, &in->sin_addr, str, sizeof(str));
port = ntohs(in->sin_port);
break;
case AF_INET6:
netid = "tcp6";
in6 = (struct sockaddr_in6 *)&ss;
inet_ntop(AF_INET6, &in6->sin6_addr, str, sizeof(str));
port = ntohs(in6->sin6_port);
break;
}
sprintf(addr, "%s.%d.%d", str, port >> 8, port & 0xff);
memset(op, 0, sizeof(op));
op[0].argop = OP_SETCLIENTID;
memcpy(op[0].nfs_argop4_u.opsetclientid.client.verifier, client->verifier, sizeof(verifier4));
op[0].nfs_argop4_u.opsetclientid.client.id.id_len = strlen(client->id);
op[0].nfs_argop4_u.opsetclientid.client.id.id_val = client->id;
op[0].nfs_argop4_u.opsetclientid.callback.cb_program = NFS4_CALLBACK;
op[0].nfs_argop4_u.opsetclientid.callback.cb_location.r_netid = netid;
op[0].nfs_argop4_u.opsetclientid.callback.cb_location.r_addr = addr;
op[0].nfs_argop4_u.opsetclientid.callback_ident = 0x00000001;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 SETCLIENTID request\n");
exit(10);
}
}
static void send_getrootfh(struct rpc_context *rpc,
rpc_cb cb, void *private_data)
{
COMPOUND4args args;
nfs_argop4 op[2];
memset(op, 0, sizeof(op));
op[0].argop = OP_PUTROOTFH;
op[1].argop = OP_GETFH;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 GETROOTFH request\n");
exit(10);
}
}
static void send_open(struct rpc_context *rpc, nfs_fh4 dir, char *path,
rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
nfs_argop4 *op;
int i = 0, idx = 0;
char *tmp;
printf("OPEN called\n");
/*
* Count how many directories we have in the path.
*/
tmp = path;
while (tmp = strchr(tmp, '/')) {
i++;
tmp++;
}
op = malloc(sizeof(nfs_argop4) * (4 + i));
memset(op, 0, sizeof(nfs_argop4) * (4 + i));
op[idx].argop = OP_PUTFH;
op[idx].nfs_argop4_u.opputfh.object = dir;
idx++;
while (i-- > 0) {
tmp = strchr(path, '/');
*tmp++ = '\0';
op[idx].argop = OP_LOOKUP;
op[idx].nfs_argop4_u.oplookup.objname.utf8string_len = strlen(path);
op[idx].nfs_argop4_u.oplookup.objname.utf8string_val = path;
idx++;
path = tmp;
}
op[idx].argop = OP_OPEN;
op[idx].nfs_argop4_u.opopen.seqid = client->seqid;
op[idx].nfs_argop4_u.opopen.share_access = OPEN4_SHARE_ACCESS_READ;
op[idx].nfs_argop4_u.opopen.share_deny = OPEN4_SHARE_DENY_NONE;
op[idx].nfs_argop4_u.opopen.owner.clientid = client->clientid;
op[idx].nfs_argop4_u.opopen.owner.owner.owner_len = strlen(client->owner);
op[idx].nfs_argop4_u.opopen.owner.owner.owner_val = client->owner;
op[idx].nfs_argop4_u.opopen.openhow.opentype = OPEN4_NOCREATE;
op[idx].nfs_argop4_u.opopen.claim.claim = CLAIM_NULL;
op[idx].nfs_argop4_u.opopen.claim.open_claim4_u.file.utf8string_len = strlen(path);
op[idx].nfs_argop4_u.opopen.claim.open_claim4_u.file.utf8string_val = path;
idx++;
op[idx].argop = OP_GETFH;
idx++;
op[idx].argop = OP_ACCESS;
op[idx].nfs_argop4_u.opaccess.access = ACCESS4_READ;
client->seqid++;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = idx;
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 OPEN request\n");
exit(10);
}
}
static void send_open_confirm(struct rpc_context *rpc, nfs_fh4 object, rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
nfs_argop4 op[2];
memset(op, 0, sizeof(op));
op[0].argop = OP_PUTFH;
op[0].nfs_argop4_u.opputfh.object = object;
op[1].argop = OP_OPEN_CONFIRM;
op[1].nfs_argop4_u.opopen_confirm.open_stateid.seqid = client->seqid;
memcpy(op[1].nfs_argop4_u.opopen_confirm.open_stateid.other, client->stateid.other, 12);
op[1].nfs_argop4_u.opopen_confirm.seqid = client->seqid;
client->seqid++;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 CLOSE request\n");
exit(10);
}
}
static void send_read(struct rpc_context *rpc, nfs_fh4 object,
uint64_t offset, uint32_t count,
rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
nfs_argop4 op[3];
memset(op, 0, sizeof(op));
op[0].argop = OP_PUTFH;
op[0].nfs_argop4_u.opputfh.object = object;
op[1].argop = OP_READ;
op[1].nfs_argop4_u.opread.stateid.seqid = client->seqid;
memcpy(op[1].nfs_argop4_u.opread.stateid.other, client->stateid.other, 12);
op[1].nfs_argop4_u.opread.offset = offset;
op[1].nfs_argop4_u.opread.count = count;
op[2].argop = OP_GETATTR;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 READ request\n");
exit(10);
}
}
static void send_close(struct rpc_context *rpc, nfs_fh4 object,
rpc_cb cb, void *private_data)
{
struct client *client = private_data;
COMPOUND4args args;
nfs_argop4 op[2];
memset(op, 0, sizeof(op));
op[0].argop = OP_PUTFH;
op[0].nfs_argop4_u.opputfh.object = object;
op[1].argop = OP_CLOSE;
op[1].nfs_argop4_u.opclose.seqid = client->seqid;
op[1].nfs_argop4_u.opclose.open_stateid.seqid = client->seqid;
memcpy(op[1].nfs_argop4_u.opclose.open_stateid.other, client->stateid.other, 12);
client->seqid++;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
fprintf(stderr, "Failed to send nfs4 CLOSE request\n");
exit(10);
}
}
/*
* Callbacks for completed requests.
*/
void close_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
/*
* FINISHED
*/
/*
* Note that we can not start tearing down and destroying the contexts
* right here as we are still in a callback from ... rpc_service().
* Instead flag that we should abort and start doing the teardown
* in client_io once we return from libnfs.
*/
client->is_finished = 1;
}
void read_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to read file on server %s\n",
client->server);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to read file on server %s\n",
client->server);
exit(10);
}
write(1, res->resarray.resarray_val[1].nfs_resop4_u.opread.READ4res_u.resok4.data.data_val, res->resarray.resarray_val[1].nfs_resop4_u.opread.READ4res_u.resok4.data.data_len);
/*
* Are we at end-of-file? If so we can close the file and exit.
*/
if (res->resarray.resarray_val[1].nfs_resop4_u.opread.READ4res_u.resok4.eof) {
send_close(rpc, client->fh, close_cb, client);
return;
}
/*
* We still have more data to read.
*/
client->offset += res->resarray.resarray_val[1].nfs_resop4_u.opread.READ4res_u.resok4.data.data_len;
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
}
void open_confirm_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to confirm open file on server %s\n",
client->server);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to confirm open file on server %s\n",
client->server);
exit(10);
}
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
}
void open_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
int idx;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to open file on server %s\n",
client->server);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to open file on server %s\n",
client->server);
exit(10);
}
/* Find the index for the OPEN opcode */
for (idx = 1; idx < res->resarray.resarray_len - 1; idx++) {
if ((res->resarray.resarray_val[idx].resop == OP_OPEN) &&
(res->resarray.resarray_val[idx + 1].resop == OP_GETFH)) {
break;
}
}
if (idx >= res->resarray.resarray_len - 1) {
fprintf(stderr, "No OP_OPEN in server response\n");
exit(10);
}
/* Store the open handle in the client structure */
client->fh.nfs_fh4_len = res->resarray.resarray_val[idx+1].nfs_resop4_u.opgetfh.GETFH4res_u.resok4.object.nfs_fh4_len;
client->fh.nfs_fh4_val = malloc(client->fh.nfs_fh4_len);
if (client->fh.nfs_fh4_val == NULL) {
fprintf(stderr, "Failed to allocate data for nfs_fh4\n");
exit(10);
}
memcpy(client->fh.nfs_fh4_val, res->resarray.resarray_val[idx+1].nfs_resop4_u.opgetfh.GETFH4res_u.resok4.object.nfs_fh4_val, client->fh.nfs_fh4_len);
/* Store stateid for the open handle in the client structure */
client->stateid.seqid = res->resarray.resarray_val[idx].nfs_resop4_u.opopen.OPEN4res_u.resok4.stateid.seqid;
memcpy(client->stateid.other, res->resarray.resarray_val[idx].nfs_resop4_u.opopen.OPEN4res_u.resok4.stateid.other, 12);
/* Check if server wants us to confirm the open */
if (res->resarray.resarray_val[idx].nfs_resop4_u.opopen.OPEN4res_u.resok4.rflags & OPEN4_RESULT_CONFIRM) {
send_open_confirm(rpc, client->fh, open_confirm_cb, client);
return;
}
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
}
void getrootfh_cb(struct rpc_context *rpc, int status, void *data,
void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to get root filehandle of server %s\n",
client->server);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to get root filehandle of server %s\n",
client->server);
exit(10);
}
send_open(rpc, res->resarray.resarray_val[1].nfs_resop4_u.opgetfh.GETFH4res_u.resok4.object, client->path, open_cb, client);
}
void setclientid_confirm_cb(struct rpc_context *rpc, int status, void *data,
void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
char *path;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to set client id of server %s\n",
client->server);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to set client id of server %s\n",
client->server);
exit(10);
}
send_getrootfh(rpc, getrootfh_cb, client);
}
void setclientid_cb(struct rpc_context *rpc, int status, void *data,
void *private_data)
{
struct client *client = private_data;
COMPOUND4res *res = data;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "Failed to set client id on server %s\n",
client->server);
exit(10);
}
if (res->status != NFS4_OK) {
fprintf(stderr, "Failed to set client id on server %s\n",
client->server);
exit(10);
}
client->clientid = res->resarray.resarray_val[0].nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.resok4.clientid;
memcpy(client->setclientid_confirm, res->resarray.resarray_val[0].nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.resok4.setclientid_confirm, NFS4_VERIFIER_SIZE);
send_setclientid_confirm(rpc, setclientid_confirm_cb, client);
}
/*
* NULL procedure for the callback protocol.
*/
static int cb_null_proc(struct rpc_context *rpc, struct rpc_msg *call)
{
rpc_send_reply(rpc, call, NULL, (zdrproc_t)zdr_void, 0);
return 0;
}
/*
* CB_COMPOUND procedure for the callback protocol.
* This is where the server will inform us about lease breaks and similar.
*/
static int cb_compound_proc(struct rpc_context *rpc, struct rpc_msg *call)
{
CB_COMPOUND4args *args = call->body.cbody.args;
fprintf(stderr, "cb_compund_cb. Do something here.\n");
return 0;
}
struct service_proc pt[] = {
{CB_NULL, cb_null_proc,
(zdrproc_t)zdr_void, 0},
{CB_COMPOUND, cb_compound_proc,
(zdrproc_t)zdr_CB_COMPOUND4args, sizeof(CB_COMPOUND4args)},
};
/*
* This callback is invoked when others (the nfsv4 server) initiates a
* NFSv4 CALLBACK sessions to us.
* We accept() the connection and create a local rpc server context
* for the callback protocol.
*/
static void client_accept(evutil_socket_t s, short events, void *private_data)
{
struct client *client = private_data;
struct server *server;
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
int fd;
server = malloc(sizeof(struct server));
if (server == NULL) {
fprintf(stderr, "failed to malloc server structure\n");
exit(10);
}
memset(server, 0, sizeof(*server));
server->next = server_list;
server_list = server;
if ((fd = accept(s, (struct sockaddr *)&ss, &len)) < 0) {
free_server(server);
fprintf(stderr, "accept failed\n");
exit(10);
}
evutil_make_socket_nonblocking(fd);
server->rpc = rpc_init_server_context(fd);
if (server->rpc == NULL) {
free_server(server);
fprintf(stderr, "Failed to create server rpc context\n");
exit(10);
}
rpc_register_service(server->rpc, NFS4_CALLBACK, NFS_CB,
pt, sizeof(pt) / sizeof(pt[0]));
server->read_event = event_new(base, fd, EV_READ|EV_PERSIST,
server_io, server);
server->write_event = event_new(base, fd, EV_WRITE|EV_PERSIST,
server_io, server);
update_events(server->rpc, server->read_event, server->write_event);
}
/*
* This callback is invoked when our async connect() to the server has
* completed. At this point we know which IP address was used locally for
* the connection and can bind our nfsv4 callback server instance to it.
*/
void connect_cb(struct rpc_context *rpc, int status, void *data _U_,
void *private_data)
{
struct client *client = private_data;
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
struct sockaddr_in *in;
struct sockaddr_in6 *in6;
if (status != RPC_STATUS_SUCCESS) {
fprintf(stderr, "connection to NFSv4 server %s failed\n",
client->server);
exit(10);
}
/*
* NFSv4 CALLBACK
* Now that we have a client connection we can register a callback
* server port on the same IP address as was used to the outgoing
* client connection. That way we know that the address used by the
* server is routable, and uses the same version of ip, that the client
* supports and can route to.
*/
if (getsockname(rpc_get_fd(rpc), (struct sockaddr *)&ss, &len) < 0) {
fprintf(stderr, "getsockaddr failed\n");
exit(10);
}
switch (ss.ss_family) {
case AF_INET:
in = (struct sockaddr_in *)&ss;
in->sin_port=0;
break;
case AF_INET6:
in6 = (struct sockaddr_in6 *)&ss;
in6->sin6_port=0;
break;
default:
fprintf(stderr, "Can not handle AF_FAMILY:%d", ss.ss_family);
exit(10);
}
client->callback_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client->callback_fd == -1) {
fprintf(stderr, "Failed to create callback socket\n");
exit(10);
}
evutil_make_socket_nonblocking(client->callback_fd);
if (bind(client->callback_fd, (struct sockaddr *)&ss, sizeof(ss)) < 0) {
fprintf(stderr, "Failed to bind callback socket\n");
exit(10);
}
if (listen(client->callback_fd, 16) < 0) {
fprintf(stderr, "failed to listen to callback socket\n");
exit(10);
}
client->listen_event = event_new(base,
client->callback_fd,
EV_READ|EV_PERSIST,
client_accept, private_data);
event_add(client->listen_event, NULL);
/*
* Now that we are finished setting up the callback server port
* we can proceed and negotiate the nfsv4 client id.
*/
send_setclientid(rpc, setclientid_cb, client);
}
int main(int argc, char *argv[])
{
struct nfs_context *nfs;
struct nfs_url *url;
struct client client;
int i, fd;
#ifdef WIN32
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
fprintf(stderr, "Failed to start Winsock2\n");
exit(10);
}
#endif
#ifdef AROS
aros_init_socket();
#endif
if (argc < 2) {
usage();
}
base = event_base_new();
if (base == NULL) {
fprintf(stderr, "Failed create event context\n");
exit(10);
}
nfs = nfs_init_context();
if (nfs == NULL) {
fprintf(stderr, "failed to init context\n");
exit(10);
}
url = nfs_parse_url_dir(nfs, argv[1]);
if (url == NULL) {
fprintf(stderr, "failed to parse url\n");
exit(10);
}
memset(&client, 0, sizeof(client));
client.rpc = nfs_get_rpc_context(nfs);
client.is_finished = 0;
client.server = url->server;
client.path = &url->path[1]; // skip leading '/'
srandom(time(NULL));
for (i = 0; i < NFS4_VERIFIER_SIZE; i++) {
client.verifier[i] = random() & 0xff;
}
asprintf(&client.id, "Libnfs %s tcp pid:%d", argv[1], getpid());
asprintf(&client.owner, "open id:libnfs pid:%d", getpid());
client.callback_fd = -1;
if (rpc_connect_program_async(client.rpc, url->server,
NFS4_PROGRAM, NFS_V4,
connect_cb, &client) != 0) {
fprintf(stderr, "Failed to start connection\n");
exit(10);
}
/*
* Set up the events we need for the outgoing client RPC channel.
*/
fd = rpc_get_fd(client.rpc);
client.read_event = event_new(base, fd, EV_READ|EV_PERSIST,
client_io, &client);
client.write_event = event_new(base, fd, EV_WRITE|EV_PERSIST,
client_io, &client);
update_events(client.rpc, client.read_event, client.write_event);
/*
* Main event loop.
*/
event_base_dispatch(base);
/*
* Finished cleanly, lets deallocate all resrouces we were using.
*/
/*
* Close the listening socket.
*/
close(client.callback_fd);
/*
* Destroy the client context.
*/
free(client.id);
free(client.owner);
free(client.fh.nfs_fh4_val);
/*
* Destroy all server contexts
*/
while (server_list) {
struct server *server = server_list;
server_list = server->next;
free_server(server);
}
nfs_destroy_url(url);
/*
* This will implicitly close the rpc context and also destroy it.
*/
nfs_destroy_context(nfs);
event_base_free(base);
return 0;
}

View File

@ -128,6 +128,46 @@ void pmap3_getaddr_cb(struct rpc_context *rpc, int status, void *data, void *pri
client->is_finished = 1;
}
void pmap2_set_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
{
struct client *client = private_data;
uint32_t res = *(uint32_t *)data;
if (status == RPC_STATUS_ERROR) {
printf("PORTMAP2/SET call failed with \"%s\"\n", (char *)data);
exit(10);
}
if (status != RPC_STATUS_SUCCESS) {
printf("PORTMAP2/SET call failed, status:%d\n", status);
exit(10);
}
printf("PORTMAP2/SET:\n");
printf(" Res:%d\n", res);
client->is_finished = 1;
}
void pmap2_unset_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
{
struct client *client = private_data;
uint32_t res = *(uint32_t *)data;
if (status == RPC_STATUS_ERROR) {
printf("PORTMAP2/UNSET call failed with \"%s\"\n", (char *)data);
exit(10);
}
if (status != RPC_STATUS_SUCCESS) {
printf("PORTMAP2/UNSET call failed, status:%d\n", status);
exit(10);
}
printf("PORTMAP2/UNSET:\n");
printf(" Res:%d\n", res);
client->is_finished = 1;
}
void pmap3_set_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
{
struct client *client = private_data;
@ -329,6 +369,8 @@ int main(int argc _U_, char *argv[] _U_)
int null2 = 0;
int dump2 = 0;
int null3 = 0;
int set2 = 0;
int unset2 = 0;
int set3 = 0;
int unset3 = 0;
int getaddr3 = 0;
@ -337,6 +379,8 @@ int main(int argc _U_, char *argv[] _U_)
int u2t3 = 0;
int command_found = 0;
int set2prog, set2vers, set2prot, set2port;
int unset2prog, unset2vers, unset2prot, unset2port;
int set3prog, set3vers;
char *set3netid, *set3addr, *set3owner;
int unset3prog, unset3vers;
@ -365,6 +409,20 @@ int main(int argc _U_, char *argv[] _U_)
} else if (!strcmp(argv[i], "null2")) {
null2 = 1;
command_found++;
} else if (!strcmp(argv[i], "set2")) {
set2 = 1;
set2prog = atoi(argv[++i]);
set2vers = atoi(argv[++i]);
set2prot = atoi(argv[++i]);
set2port = atoi(argv[++i]);
command_found++;
} else if (!strcmp(argv[i], "unset2")) {
unset2 = 1;
unset2prog = atoi(argv[++i]);
unset2vers = atoi(argv[++i]);
unset2prot = atoi(argv[++i]);
unset2port = atoi(argv[++i]);
command_found++;
} else if (!strcmp(argv[i], "dump3")) {
dump3 = 1;
command_found++;
@ -465,6 +523,20 @@ int main(int argc _U_, char *argv[] _U_)
}
wait_until_finished(rpc, &client);
}
if (set2) {
if (rpc_pmap2_set_async(rpc, set2prog, set2vers, set2prot, set2port, pmap2_set_cb, &client) != 0) {
printf("Failed to send SET2 request\n");
exit(10);
}
wait_until_finished(rpc, &client);
}
if (unset2) {
if (rpc_pmap2_unset_async(rpc, unset2prog, unset2vers, unset2prot, unset2port, pmap2_unset_cb, &client) != 0) {
printf("Failed to send UNSET2 request\n");
exit(10);
}
wait_until_finished(rpc, &client);
}
if (set3) {
struct pmap3_mapping map;

703
examples/portmap-server.c Normal file
View File

@ -0,0 +1,703 @@
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
/*
Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2015
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/>.
*/
/* This is a very incomplete portmapper that only implements
* a subset of version 2 and threee of the protocol.
* A proper portmapper needs to implement these two versions fully
* as well as version 4.
*
* See this as an example of how to build a simple RPC service
* that supports both UDP and TCP using libnfs.
*/
#define _FILE_OFFSET_BITS 64
#define _GNU_SOURCE
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef AROS
#include "aros_compat.h"
#endif
#ifdef WIN32
#include "win32_compat.h"
#pragma comment(lib, "ws2_32.lib")
WSADATA wsaData;
#else
#include <sys/stat.h>
#include <string.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include "libnfs.h"
#include "libnfs-raw.h"
#include "libnfs-raw-portmap.h"
#include <event2/event.h>
struct event_base *base;
struct server {
struct rpc_context *rpc;
struct event *read_event;
struct event *write_event;
};
/* Socket where we listen for incomming rpc connections */
struct event *listen_event;
int listen_socket = -1;
/* Socket used for UDP server */
struct server udp_server;
int udp_socket = -1;
struct mapping {
struct mapping *next;
u_int prog;
u_int vers;
int port;
char *netid;
char *addr;
char *owner;
};
struct mapping *map;
void free_map_item(struct mapping *item)
{
free(item->netid);
free(item->addr);
free(item->owner);
free(item);
}
static void free_server(struct server *server)
{
if (server->rpc) {
rpc_disconnect(server->rpc, NULL);
rpc_destroy_context(server->rpc);
}
if (server->read_event) {
event_free(server->read_event);
}
if (server->write_event) {
event_free(server->write_event);
}
free(server);
}
/*
* Based on the state of libnfs and its context, update libevent
* accordingly regarding which events we are interested in.
*/
static void update_events(struct rpc_context *rpc, struct event *read_event,
struct event *write_event)
{
int events = rpc_which_events(rpc);
if (read_event) {
if (events & POLLIN) {
event_add(read_event, NULL);
} else {
event_del(read_event);
}
}
if (write_event) {
if (events & POLLOUT) {
event_add(write_event, NULL);
} else {
event_del(write_event);
}
}
}
/*
* Add a registration for program,version,netid.
*/
int pmap_register(int prog, int vers, char *netid, char *addr,
char *owner)
{
struct mapping *item;
char *str;
int count = 0;
item = malloc(sizeof(struct mapping));
item->prog = prog;
item->vers = vers;
item->netid = netid;
item->addr = addr;
item->owner = owner;
/* The port are the last two dotted decimal fields in the address */
for (str = item->addr + strlen(item->addr) - 1; str >= item->addr; str--) {
if (*str != '.') {
if (*str < '0' || *str > '9') {
break;
}
continue;
}
count++;
if (count == 2) {
int high, low;
sscanf(str, ".%d.%d", &high, &low);
item->port = high * 256 + low;
break;
}
}
item->next = map;
map = item;
}
/*
* Find and return a registration matching program,version,netid.
*/
struct mapping *map_lookup(int prog, int vers, char *netid)
{
struct mapping *tmp;
for (tmp = map; tmp; tmp = tmp->next) {
if (tmp->prog != prog) {
continue;
}
if (tmp->vers != vers) {
continue;
}
if (strcmp(tmp->netid, netid)) {
continue;
}
return tmp;
}
return NULL;
}
/*
* Remove a registration from our map or registrations.
*/
void map_remove(int prog, int vers, char *netid)
{
struct mapping *prev = NULL;
struct mapping *tmp;
for (tmp = map; tmp; prev = tmp, tmp = tmp->next) {
if (tmp->prog != prog) {
continue;
}
if (tmp->vers != vers) {
continue;
}
if (strcmp(tmp->netid, netid)) {
continue;
}
break;
}
if (tmp == NULL) {
return;
}
if (prev) {
prev->next = tmp->next;
} else {
map = tmp->next;
}
free_map_item(tmp);
return;
}
/*
* The NULL procedure. All protocols/versions must provide a NULL procedure
* as index 0.
* It is used by clients, and rpcinfo, to "ping" a service and verify that
* the service is available and that it does support the indicated version.
*/
static int pmap2_null_proc(struct rpc_context *rpc, struct rpc_msg *call)
{
rpc_send_reply(rpc, call, NULL, (zdrproc_t)zdr_void, 0);
return 0;
}
/*
* v2 GETPORT.
* This is the lookup function for portmapper version 2.
* A client provides program, version and protocol (tcp or udp)
* and portmapper returns which port that service is available on,
* (or 0 if no such program is registered.)
*/
static int pmap2_getport_proc(struct rpc_context *rpc, struct rpc_msg *call)
{
PMAP2GETPORTargs *args = call->body.cbody.args;
struct mapping *tmp;
char *netid;
uint32_t port = 0;
if (args->prot == IPPROTO_TCP) {
netid = "tcp";
} else {
netid = "udp";
}
tmp = map_lookup(args->prog, args->vers, netid);
if (tmp) {
port = tmp->port;
}
rpc_send_reply(rpc, call, &port, (zdrproc_t)zdr_uint32_t, sizeof(uint32_t));
return 0;
}
/*
* v2 DUMP.
* This RPC returns a list of all endpoints that are registered with
* portmapper.
*/
static int pmap2_dump_proc(struct rpc_context *rpc, struct rpc_msg *call)
{
PMAP2DUMPres reply;
struct mapping *tmp;
reply.list = NULL;
for (tmp = map; tmp; tmp = tmp->next) {
struct pmap2_mapping_list *tmp_list;
int proto;
/* pmap2 only support ipv4 */
if (!strcmp(tmp->netid, "tcp")) {
proto = IPPROTO_TCP;
} else if (!strcmp(tmp->netid, "udp")) {
proto = IPPROTO_UDP;
} else {
continue;
}
tmp_list = malloc(sizeof(struct pmap2_mapping_list));
tmp_list->map.prog = tmp->prog;
tmp_list->map.vers = tmp->vers;
tmp_list->map.prot = proto;
tmp_list->map.port = tmp->port;
tmp_list->next = reply.list;
reply.list = tmp_list;
}
rpc_send_reply(rpc, call, &reply,
(zdrproc_t)zdr_PMAP2DUMPres, sizeof(PMAP2DUMPres));
while (reply.list) {
struct pmap2_mapping_list *tmp_list = reply.list->next;
free(reply.list);
reply.list = tmp_list;
}
return 0;
}
/*
* v2 SET
* This procedure is used to register and endpoint with portmapper.
*/
static int pmap2_set_proc(struct rpc_context *rpc, struct rpc_msg *call)
{
PMAP2GETPORTargs *args = call->body.cbody.args;
char *prot;
char *addr;
uint32_t response = 1;
if (args->prot == IPPROTO_TCP) {
prot = "tcp";
} else {
prot = "udp";
}
/* Don't update if we already have a mapping */
if (map_lookup(args->prog, args->vers, prot)) {
response = 0;
rpc_send_reply(rpc, call, &response, (zdrproc_t)zdr_uint32_t, sizeof(uint32_t));
return 0;
}
asprintf(&addr, "0.0.0.0.%d.%d", args->port >> 8, args->port & 0xff);
pmap_register(args->prog, args->vers, strdup(prot), addr,
strdup("<unknown>"));
rpc_send_reply(rpc, call, &response, (zdrproc_t)zdr_uint32_t, sizeof(uint32_t));
return 0;
}
/*
* v2 UNSET
* This procedure is used to remove a registration from portmappers
* list of endpoints.
*/
static int pmap2_unset_proc(struct rpc_context *rpc, struct rpc_msg *call)
{
PMAP2GETPORTargs *args = call->body.cbody.args;
char *prot;
char *addr;
uint32_t response = 1;
if (args->prot == IPPROTO_TCP) {
prot = "tcp";
} else {
prot = "udp";
}
map_remove(args->prog, args->vers, prot);
rpc_send_reply(rpc, call, &response, (zdrproc_t)zdr_uint32_t, sizeof(uint32_t));
return 0;
}
/*
* Service table for portmapper v2.
*
* Service management is table driven in libnfsand this is the table
* that defines which procedures we implement for portmapper v2.
* If clients try to connect to the not-yet-implemented procedures here
* libnfs will automatically respond with an RPC layer error that flags
* PROCEDURE UNAVAILABLE.
*
* This table contains the procedure number, the callback function to implement
* this procedure, the unmarshalling function that libnfs should use to unppack
* the client payload as well as its size.
*
* Version 2 does not support ipv6 so this version of portmapper is
* not too commonly used any more.
*/
struct service_proc pmap2_pt[] = {
{PMAP2_NULL, pmap2_null_proc,
(zdrproc_t)zdr_void, 0},
{PMAP2_SET, pmap2_set_proc,
(zdrproc_t)zdr_PMAP2SETargs, sizeof(PMAP2SETargs)},
{PMAP2_UNSET, pmap2_unset_proc,
(zdrproc_t)zdr_PMAP2UNSETargs, sizeof(PMAP2UNSETargs)},
{PMAP2_GETPORT, pmap2_getport_proc,
(zdrproc_t)zdr_PMAP2GETPORTargs, sizeof(PMAP2GETPORTargs)},
{PMAP2_DUMP, pmap2_dump_proc,
(zdrproc_t)zdr_void, 0},
//{PMAP2_CALLIT, pmap2_...},
};
/*
* The NULL procedure. All protocols/versions must provide a NULL procedure
* as index 0.
* It is used by clients, and rpcinfo, to "ping" a service and verify that
* the service is available and that it does support the indicated version.
*/
static int pmap3_null_proc(struct rpc_context *rpc, struct rpc_msg *call)
{
rpc_send_reply(rpc, call, NULL, (zdrproc_t)zdr_void, 0);
return 0;
}
/*
* v3 DUMP.
* This RPC returns a list of all endpoints that are registered with
* portmapper.
*/
static int pmap3_dump_proc(struct rpc_context *rpc, struct rpc_msg *call)
{
PMAP3DUMPres reply;
struct mapping *tmp;
reply.list = NULL;
for (tmp = map; tmp; tmp = tmp->next) {
struct pmap3_mapping_list *tmp_list;
tmp_list = malloc(sizeof(struct pmap3_mapping_list));
tmp_list->map.prog = tmp->prog;
tmp_list->map.vers = tmp->vers;
tmp_list->map.netid = tmp->netid;
tmp_list->map.addr = tmp->addr;
tmp_list->map.owner = tmp->owner;
tmp_list->next = reply.list;
reply.list = tmp_list;
}
rpc_send_reply(rpc, call, &reply,
(zdrproc_t)zdr_PMAP3DUMPres, sizeof(PMAP3DUMPres));
while (reply.list) {
struct pmap3_mapping_list *tmp_list = reply.list->next;
free(reply.list);
reply.list = tmp_list;
}
return 0;
}
/*
* Service table for portmapper v3.
*
* Service management is table driven in libnfsand this is the table
* that defines which procedures we implement for portmapper v3.
* If clients try to connect to the not-yet-implemented procedures here
* libnfs will automatically respond with an RPC layer error that flags
* PROCEDURE UNAVAILABLE.
*
* This table contains the procedure number, the callback function to implement
* this procedure, the unmarshalling function that libnfs should use to unppack
* the client payload as well as its size.
*/
struct service_proc pmap3_pt[] = {
{PMAP3_NULL, pmap3_null_proc,
(zdrproc_t)zdr_void, 0},
//{PMAP3_SET, pmap3_...},
//{PMAP3_UNSET, pmap3_...},
//{PMAP3_GETADDR, pmap3_...},
{PMAP3_DUMP, pmap3_dump_proc,
(zdrproc_t)zdr_void, 0},
//{PMAP3_CALLIT, pmap3_...},
//{PMAP3_GETTIME, pmap3_...},
//{PMAP3_UADDR2TADDR, pmap3_...},
//{PMAP3_TADDR2UADDR, pmap3_...},
};
/*
* This callback is invoked from the event system when an event we are waiting
* for has become active.
*/
static void server_io(evutil_socket_t fd, short events, void *private_data)
{
struct server *server = private_data;
int revents = 0;
/*
* Translate the libevent read/write flags to the corresponding
* flags that libnfs uses.
*/
if (events & EV_READ) {
revents |= POLLIN;
}
if (events & EV_WRITE) {
revents |= POLLOUT;
}
/*
* Let libnfs process the event.
*/
if (rpc_service(server->rpc, revents) < 0) {
free_server(server);
return;
}
/*
* Update which events we are interested in. It might have changed
* for example if we no longer have any data pending to send
* we no longer need to wait for the socket to become writeable.
*/
update_events(server->rpc, server->read_event, server->write_event);
}
/*
* This callback is invoked when we have a client connecting to our TCP
* port.
*/
static void do_accept(evutil_socket_t s, short events, void *private_data)
{
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
struct server *server;
int fd;
server = malloc(sizeof(struct server));
if (server == NULL) {
return;
}
memset(server, 0, sizeof(*server));
if ((fd = accept(s, (struct sockaddr *)&ss, &len)) < 0) {
free_server(server);
return;
}
evutil_make_socket_nonblocking(fd);
server->rpc = rpc_init_server_context(fd);
if (server->rpc == NULL) {
close(fd);
free_server(server);
return;
}
/*
* Register both v2 and v3 of the protocol to the new
* server context.
*/
rpc_register_service(server->rpc, PMAP_PROGRAM, PMAP_V2,
pmap2_pt, sizeof(pmap2_pt) / sizeof(pmap2_pt[0]));
rpc_register_service(server->rpc, PMAP_PROGRAM, PMAP_V3,
pmap3_pt, sizeof(pmap3_pt) / sizeof(pmap3_pt[0]));
/*
* Create events for read and write for this new server instance.
*/
server->read_event = event_new(base, fd, EV_READ|EV_PERSIST,
server_io, server);
server->write_event = event_new(base, fd, EV_WRITE|EV_PERSIST,
server_io, server);
update_events(server->rpc, server->read_event, server->write_event);
}
int main(int argc, char *argv[])
{
struct sockaddr_in in;
int one = 1;
#ifdef WIN32
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
printf("Failed to start Winsock2\n");
return 10;
}
#endif
#ifdef AROS
aros_init_socket();
#endif
base = event_base_new();
if (base == NULL) {
printf("Failed create event context\n");
exit(10);
}
/*
* Portmapper listens on port 111, any address.
* Just initialize it for now as we will need it several times below.
*/
in.sin_family = AF_INET;
in.sin_port = htons(111);
in.sin_addr.s_addr = htonl (INADDR_ANY);
/* This is the portmapper protocol itself which we obviously
* support.
*/
pmap_register(100000, 2, strdup("tcp"), strdup("0.0.0.0.0.111"),
strdup("portmapper-service"));
pmap_register(100000, 2, strdup("udp"), strdup("0.0.0.0.0.111"),
strdup("portmapper-service"));
pmap_register(100000, 3, strdup("tcp"), strdup("0.0.0.0.0.111"),
strdup("portmapper-service"));
pmap_register(100000, 3, strdup("udp"), strdup("0.0.0.0.0.111"),
strdup("portmapper-service"));
/*
* TCP: Set up a listening socket for incoming TCP connections.
* Once clients connect, inside do_accept() we will create a proper
* libnfs server context for each connection.
*/
listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listen_socket == -1) {
printf("Failed to create listening socket\n");
exit(10);
}
evutil_make_socket_nonblocking(listen_socket);
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
if (bind(listen_socket, (struct sockaddr *)&in, sizeof(in)) < 0) {
printf("Failed to bind listening socket\n");
exit(10);
}
if (listen(listen_socket, 16) < 0) {
printf("failed to listen to socket\n");
exit(10);
}
listen_event = event_new(base,
listen_socket,
EV_READ|EV_PERSIST,
do_accept, NULL);
event_add(listen_event, NULL);
/*
* UDP: Create and bind to the socket we want to use for the UDP server.
*/
udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (udp_socket == -1) {
printf("Failed to create udp socket\n");
exit(10);
}
evutil_make_socket_nonblocking(udp_socket);
setsockopt(udp_socket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
if (bind(udp_socket, (struct sockaddr *)&in, sizeof(in)) < 0) {
printf("Failed to bind udp socket\n");
exit(10);
}
/*
* UDP: Create a libnfs server context for this socket.
*/
memset(&udp_server, 0, sizeof(udp_server));
udp_server.rpc = rpc_init_server_context(udp_socket);
/*
* UDP: Register both v2 and v3 of the protocol to the
* UDP server context.
*/
rpc_register_service(udp_server.rpc, PMAP_PROGRAM, PMAP_V2,
pmap2_pt, sizeof(pmap2_pt) / sizeof(pmap2_pt[0]));
rpc_register_service(udp_server.rpc, PMAP_PROGRAM, PMAP_V3,
pmap3_pt, sizeof(pmap3_pt) / sizeof(pmap3_pt[0]));
udp_server.read_event = event_new(base,
udp_socket,
EV_READ|EV_PERSIST,
server_io, &udp_server);
event_add(udp_server.read_event, NULL);
/*
* Everything is now set up. Start the event loop.
*/
event_base_dispatch(base);
return 0;
}

View File

@ -6,6 +6,7 @@ dist_nfsc_HEADERS = \
../mount/libnfs-raw-mount.h \
../portmap/libnfs-raw-portmap.h \
../nfs/libnfs-raw-nfs.h \
../nfs4/libnfs-raw-nfs4.h \
../nlm/libnfs-raw-nlm.h \
../nsm/libnfs-raw-nsm.h \
../rquota/libnfs-raw-rquota.h

View File

@ -93,11 +93,20 @@ struct rpc_queue {
#define ZDR_ENCODE_OVERHEAD 1024
#define ZDR_ENCODEBUF_MINSIZE 4096
struct rpc_endpoint {
struct rpc_endpoint *next;
int program;
int version;
struct service_proc *procs;
int num_procs;
};
struct rpc_context {
uint32_t magic;
int fd;
int old_fd;
int is_connected;
int is_nonblocking;
char *error_string;
@ -110,19 +119,21 @@ struct rpc_context {
struct rpc_queue outqueue;
struct sockaddr_storage udp_src;
struct rpc_queue waitpdu[HASHES];
uint32_t waitpdu_len;
uint32_t inpos;
uint32_t insize;
char rm_buf[4];
char *inbuf;
/* special fields for UDP, which can sometimes be BROADCASTed */
int is_udp;
struct sockaddr *udp_dest;
struct sockaddr_storage udp_dest;
int is_broadcast;
/* track the address we connect to so we can auto-reconnect on session failure */
struct sockaddr_storage s;
int auto_reconnect;
int auto_reconnect_retries;
/* fragment reassembly */
struct rpc_fragment *fragments;
@ -137,6 +148,10 @@ struct rpc_context {
int debug;
int timeout;
char ifname[IFNAMSIZ];
/* Is a server context ? */
int is_server_context;
struct rpc_endpoint *endpoints;
};
struct rpc_pdu {
@ -155,6 +170,11 @@ struct rpc_pdu {
zdrproc_t zdr_decode_fn;
caddr_t zdr_decode_buf;
uint32_t zdr_decode_bufsize;
#define PDU_DISCARD_AFTER_SENDING 0x00000001
uint32_t flags;
time_t timeout;
};
void rpc_reset_queue(struct rpc_queue *q);
@ -204,8 +224,6 @@ void rpc_unset_autoreconnect(struct rpc_context *rpc);
void rpc_set_interface(struct rpc_context *rpc, const char *ifname);
void rpc_set_tcp_syncnt(struct rpc_context *rpc, int v);
void rpc_set_uid(struct rpc_context *rpc, int uid);
void rpc_set_gid(struct rpc_context *rpc, int gid);
void rpc_set_pagecache(struct rpc_context *rpc, uint32_t v);
void rpc_set_pagecache_ttl(struct rpc_context *rpc, uint32_t v);
void rpc_set_readahead(struct rpc_context *rpc, uint32_t v);
@ -214,9 +232,12 @@ void rpc_set_timeout(struct rpc_context *rpc, int timeout);
int rpc_get_timeout(struct rpc_context *rpc);
int rpc_add_fragment(struct rpc_context *rpc, char *data, uint32_t size);
void rpc_free_all_fragments(struct rpc_context *rpc);
int rpc_is_udp_socket(struct rpc_context *rpc);
const struct nfs_fh3 *nfs_get_rootfh(struct nfs_context *nfs);
void *zdr_malloc(ZDR *zdrs, uint32_t size);
#ifdef __cplusplus
}
#endif

View File

@ -1,3 +1,4 @@
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
/*
Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
@ -70,6 +71,63 @@ int rpc_service(struct rpc_context *rpc, int revents);
*/
int rpc_queue_length(struct rpc_context *rpc);
/*
* Set which UID/GID to use in the authenticator.
* By default libnfs will use getuid()/getgid() where available
* and 65534/65534 where not.
*/
void rpc_set_uid(struct rpc_context *rpc, int uid);
void rpc_set_gid(struct rpc_context *rpc, int gid);
/*
* Create a server context.
*/
struct rpc_context *rpc_init_server_context(int s);
/* This is the callback functions for server contexts.
* These are invoked from the library when a CALL has been received and a
* service procedure has been found that matches the rpc
* program/version/procedure.
*
* The rpc arguments are stored in call->body.cbody.args;
* Example:
* static int pmap2_getport_proc(struct rpc_context *rpc, struct rpc_msg *call)
* {
* pmap2_mapping *args = call->body.cbody.args;
* ...
*
* struct service_proc pmap2_pt[] = {
* {PMAP2_GETPORT, pmap2_getport_proc,
* (zdrproc_t)zdr_pmap2_mapping, sizeof(pmap2_mapping)},
* ...
*
*
* The return value is:
* 0: Procedure was completed normally.
* !0: An abnormal error has occured. It is unrecoverable and the only
* meaningful cause of action is to tear down the connection from
* the client.
*/
typedef int (*service_fn)(struct rpc_context *rpc, struct rpc_msg *call);
struct service_proc {
int proc;
service_fn func;
zdrproc_t decode_fn;
int decode_buf_size;
};
/*
* Register a service callback table for program/version.
* Can only be used with contexts created with rpc_init_server_context()
*/
int rpc_register_service(struct rpc_context *rpc, int program, int version,
struct service_proc *procs, int num_procs);
int rpc_send_reply(struct rpc_context *rpc, struct rpc_msg *call,
void *reply, zdrproc_t encode_fn,
int alloc_hint);
/*
* When an operation failed, this function can extract a detailed error string.
*/
@ -109,6 +167,7 @@ void rpc_set_fd(struct rpc_context *rpc, int fd);
#define RPC_STATUS_SUCCESS 0
#define RPC_STATUS_ERROR 1
#define RPC_STATUS_CANCEL 2
#define RPC_STATUS_TIMEOUT 3
/*
* Async connection to the tcp port at server:port.
@ -1699,6 +1758,56 @@ EXTERN int rpc_nsm1_simucrash_async(struct rpc_context *rpc, rpc_cb cb, void *pr
struct NSM1_NOTIFYargs;
EXTERN int rpc_nsm1_notify_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_NOTIFYargs *args, void *private_data);
/*
* Call NFS4/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.
*/
EXTERN int rpc_nfs4_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
/*
* Call NFS4/COMPOUND
* 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 COMPOUND4res
* 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 COMPOUND4args;
EXTERN int rpc_nfs4_compound_async(struct rpc_context *rpc, rpc_cb cb, struct COMPOUND4args *args, void *private_data);
/*
* Call <generic>/NULL
* Function returns
* 0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
* <0 : An error occured when trying to set up the connection. The callback will not be invoked.
*
* When the callback is invoked, status indicates the result:
* RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
* data is NULL.
* RPC_STATUS_ERROR : An error occured when trying to contact the portmapper.
* data is the error string.
* RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
* data is NULL.
*/
EXTERN int
rpc_null_async(struct rpc_context *rpc, int program, int version, rpc_cb cb, void *private_data);
#ifdef __cplusplus
}
#endif

View File

@ -96,7 +96,7 @@ typedef uint32_t u_int;
typedef uint32_t enum_t;
typedef uint32_t bool_t;
typedef int (*zdrproc_t) (ZDR *, void *,...);
typedef uint32_t (*zdrproc_t) (ZDR *, void *,...);
#define AUTH_NONE 0
#define AUTH_NULL 0
@ -165,6 +165,7 @@ struct call_body {
uint32_t proc;
struct opaque_auth cred;
struct opaque_auth verf;
void *args;
};
struct accepted_reply {
@ -221,9 +222,11 @@ void libnfs_zdr_destroy(ZDR *zdrs);
bool_t libnfs_zdr_bytes(ZDR *zdrs, char **bufp, uint32_t *size, uint32_t maxsize);
#define zdr_u_int libnfs_zdr_u_int
#define zdr_uint32_t libnfs_zdr_u_int
bool_t libnfs_zdr_u_int(ZDR *zdrs, uint32_t *u);
#define zdr_int libnfs_zdr_int
#define zdr_int32_t libnfs_zdr_int
bool_t libnfs_zdr_int(ZDR *zdrs, int32_t *i);
#define zdr_uint64_t libnfs_zdr_uint64_t
@ -239,7 +242,7 @@ bool_t libnfs_zdr_enum(ZDR *zdrs, enum_t *e);
bool_t libnfs_zdr_bool(ZDR *zdrs, bool_t *b);
#define zdr_void libnfs_zdr_void
bool_t libnfs_zdr_void(void);
bool_t libnfs_zdr_void(ZDR *zdrs, void *);
#define zdr_pointer libnfs_zdr_pointer
bool_t libnfs_zdr_pointer(ZDR *zdrs, char **objp, uint32_t size, zdrproc_t proc);

82
include/nfsc/libnfs.h Normal file → Executable file
View File

@ -22,14 +22,11 @@
#define _LIBNFS_H_
#include <stdint.h>
#if defined(__ANDROID__)
#include <sys/time.h>
#endif
#if defined(AROS)
#include <sys/time.h>
#endif
#if defined(__APPLE__) && defined(__MACH__)
#if defined(__ANDROID__) || defined(AROS) \
|| ( defined(__APPLE__) && defined(__MACH__) )
#include <sys/time.h>
#else
#include <time.h>
#endif
#ifdef __cplusplus
@ -57,7 +54,10 @@ struct nfs_url {
#define EXTERN
#endif
#if defined(WIN32)
#ifdef WIN32
#ifdef HAVE_FUSE_H
#include <fuse.h>
#else
struct statvfs {
uint32_t f_bsize;
uint32_t f_frsize;
@ -71,6 +71,7 @@ struct statvfs {
uint32_t f_flag;
uint32_t f_namemax;
};
#endif
#if !defined(__MINGW32__)
struct utimbuf {
time_t actime;
@ -238,12 +239,6 @@ EXTERN void nfs_set_dircache(struct nfs_context *nfs, int enabled);
*/
EXTERN void nfs_pagecache_invalidate(struct nfs_context *nfs, struct nfsfh *nfsfh);
/*
* Sets timeout in milliseconds. A negative value means infinite timeout.
*/
EXTERN void nfs_set_timeout(struct nfs_context *nfs, int timeout);
EXTERN int nfs_get_timeout(struct nfs_context *nfs);
/*
* MOUNT THE EXPORT
*/
@ -455,13 +450,14 @@ EXTERN uint16_t nfs_umask(struct nfs_context *nfs, uint16_t mask);
* Async open(<filename>)
*
* mode is a combination of the flags :
* O_RDONLY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND, O_TRUNC
* O_RDONLY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND, O_TRUNC, O_NOFOLLOW
*
* Function returns
* 0 : The operation was initiated. Once the operation finishes, the callback will be invoked.
* <0 : An error occured when trying to set up the operation. The callback will not be invoked.
*
* Supported flags are
* O_NOFOLLOW
* O_APPEND
* O_RDONLY
* O_WRONLY
@ -538,7 +534,7 @@ EXTERN int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_
* >=0 : numer of bytes read.
* -errno : An error occured.
*/
EXTERN int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf);
EXTERN int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, void *buf);
@ -566,7 +562,7 @@ EXTERN int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t
* >=0 : numer of bytes read.
* -errno : An error occured.
*/
EXTERN int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf);
EXTERN int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, void *buf);
@ -587,14 +583,14 @@ EXTERN int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count
* -errno : An error occured.
* data is the error string.
*/
EXTERN int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data);
EXTERN int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, const void *buf, nfs_cb cb, void *private_data);
/*
* Sync pwrite()
* Function returns
* >=0 : numer of bytes written.
* -errno : An error occured.
*/
EXTERN int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf);
EXTERN int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, const void *buf);
/*
@ -613,14 +609,14 @@ EXTERN int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t off
* -errno : An error occured.
* data is the error string.
*/
EXTERN int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf, nfs_cb cb, void *private_data);
EXTERN int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, const void *buf, nfs_cb cb, void *private_data);
/*
* Sync write()
* Function returns
* >=0 : numer of bytes written.
* -errno : An error occured.
*/
EXTERN int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf);
EXTERN int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, const void *buf);
/*
@ -754,6 +750,27 @@ EXTERN int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
*/
EXTERN int nfs_mkdir(struct nfs_context *nfs, const char *path);
/*
* Async mkdir2()
*
* 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.
*/
EXTERN int nfs_mkdir2_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data);
/*
* Sync mkdir2()
* Function returns
* 0 : Success
* -errno : An error occured.
*/
EXTERN int nfs_mkdir2(struct nfs_context *nfs, const char *path, int mode);
/*
@ -812,6 +829,7 @@ EXTERN int nfs_creat(struct nfs_context *nfs, const char *path, int mode, struct
* Async create()
*
* Same as nfs_creat_async but allows passing flags:
* O_NOFOLLOW
* O_APPEND
* O_SYNC
* O_EXCL
@ -1523,6 +1541,28 @@ struct nfs_server_list {
struct nfs_server_list *nfs_find_local_servers(void);
void free_nfs_srvr_list(struct nfs_server_list *srv);
/*
* sync nfs_set_timeout()
* This function sets the timeout used for nfs rpc calls.
*
* Function returns nothing.
*
* int milliseconds : timeout to be applied in milliseconds (-1 no timeout)
* timeouts must currently be set in whole seconds,
* i.e. units of 1000
*/
EXTERN void nfs_set_timeout(struct nfs_context *nfs, int milliseconds);
/*
* sync nfs_get_timeout()
* This function gets the timeout used for nfs rpc calls.
*
* Function returns
* -1 : No timeout applied
* > 0 : Timeout in milliseconds
*/
EXTERN int nfs_get_timeout(struct nfs_context *nfs);
#ifdef __cplusplus
}
#endif

View File

@ -6,6 +6,7 @@ libnfs_la_CPPFLAGS = -I$(abs_top_srcdir)/include \
-I$(abs_top_srcdir)/include/nfsc \
-I$(abs_top_srcdir)/mount \
-I$(abs_top_srcdir)/nfs \
-I$(abs_top_srcdir)/nfs4 \
-I$(abs_top_srcdir)/nlm \
-I$(abs_top_srcdir)/nsm \
-I$(abs_top_srcdir)/portmap \
@ -29,6 +30,7 @@ libnfs_la_LDFLAGS = -version-info $(SOCURRENT):$(SOREVISION):$(SOAGE)
libnfs_la_LIBADD = \
../mount/libmount.la \
../nfs/libnfs.la \
../nfs4/libnfs4.la \
../nlm/libnlm.la \
../nsm/libnsm.la \
../portmap/libportmap.la \

View File

@ -91,7 +91,28 @@ struct rpc_context *rpc_init_context(void)
return rpc;
}
uint32_t static round_to_power_of_two(uint32_t x) {
struct rpc_context *rpc_init_server_context(int s)
{
struct rpc_context *rpc;
rpc = malloc(sizeof(struct rpc_context));
if (rpc == NULL) {
return NULL;
}
memset(rpc, 0, sizeof(struct rpc_context));
rpc->magic = RPC_CONTEXT_MAGIC;
rpc->is_server_context = 1;
rpc->fd = s;
rpc->is_connected = 1;
rpc->is_udp = rpc_is_udp_socket(rpc);
rpc_reset_queue(&rpc->outqueue);
return rpc;
}
static uint32_t round_to_power_of_two(uint32_t x) {
uint32_t power = 1;
while (power < x) {
power <<= 1;
@ -237,8 +258,8 @@ void rpc_error_all_pdus(struct rpc_context *rpc, const char *error)
assert(rpc->magic == RPC_CONTEXT_MAGIC);
while ((pdu = rpc->outqueue.head) != NULL) {
pdu->cb(rpc, RPC_STATUS_ERROR, (void *)error, pdu->private_data);
rpc->outqueue.head = pdu->next;
pdu->cb(rpc, RPC_STATUS_ERROR, (void *)error, pdu->private_data);
rpc_free_pdu(rpc, pdu);
}
rpc->outqueue.tail = NULL;
@ -247,13 +268,14 @@ void rpc_error_all_pdus(struct rpc_context *rpc, const char *error)
struct rpc_queue *q = &rpc->waitpdu[i];
while((pdu = q->head) != NULL) {
q->head = pdu->next;
pdu->cb(rpc, RPC_STATUS_ERROR, (void *)error,
pdu->private_data);
q->head = pdu->next;
rpc_free_pdu(rpc, pdu);
}
q->tail = NULL;
}
rpc->waitpdu_len = 0;
}
static void rpc_free_fragment(struct rpc_fragment *fragment)
@ -306,9 +328,17 @@ void rpc_destroy_context(struct rpc_context *rpc)
assert(rpc->magic == RPC_CONTEXT_MAGIC);
/* If we are a server context, free all registered endpoints. */
while (rpc->endpoints != NULL) {
struct rpc_endpoint *next = rpc->endpoints->next;
free(rpc->endpoints);
rpc->endpoints = next;
}
while((pdu = rpc->outqueue.head) != NULL) {
pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
LIBNFS_LIST_REMOVE(&rpc->outqueue.head, pdu);
pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
rpc_free_pdu(rpc, pdu);
}
@ -316,16 +346,18 @@ void rpc_destroy_context(struct rpc_context *rpc)
struct rpc_queue *q = &rpc->waitpdu[i];
while((pdu = q->head) != NULL) {
pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
LIBNFS_LIST_REMOVE(&q->head, pdu);
pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
rpc_free_pdu(rpc, pdu);
}
}
rpc_free_all_fragments(rpc);
auth_destroy(rpc->auth);
rpc->auth =NULL;
if (rpc->auth) {
auth_destroy(rpc->auth);
rpc->auth =NULL;
}
if (rpc->fd != -1) {
close(rpc->fd);
@ -336,11 +368,6 @@ void rpc_destroy_context(struct rpc_context *rpc)
rpc->error_string = NULL;
}
if (rpc->udp_dest != NULL) {
free(rpc->udp_dest);
rpc->udp_dest = NULL;
}
free(rpc->inbuf);
rpc->inbuf = NULL;
@ -361,3 +388,32 @@ int rpc_get_timeout(struct rpc_context *rpc)
return rpc->timeout;
}
int rpc_register_service(struct rpc_context *rpc, int program, int version,
struct service_proc *procs, int num_procs)
{
struct rpc_endpoint *endpoint;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (!rpc->is_server_context) {
rpc_set_error(rpc, "Not a server context.");
return -1;
}
endpoint = malloc(sizeof(*endpoint));
if (endpoint == NULL) {
rpc_set_error(rpc, "Out of memory: Failed to allocate endpoint "
"structure");
return -1;
}
endpoint->program = program;
endpoint->version = version;
endpoint->procs = procs;
endpoint->num_procs = num_procs;
endpoint->next = rpc->endpoints;
rpc->endpoints = endpoint;
return 0;
}

View File

@ -395,7 +395,7 @@ static void pread_cb(int status, struct nfs_context *nfs, void *data, void *priv
memcpy(buffer, (char *)data, status);
}
int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buffer)
int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, void *buffer)
{
struct sync_cb_data cb_data;
@ -416,7 +416,7 @@ int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uin
/*
* read()
*/
int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buffer)
int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, void *buffer)
{
struct sync_cb_data cb_data;
@ -526,7 +526,7 @@ static void pwrite_cb(int status, struct nfs_context *nfs, void *data, void *pri
nfs_set_error(nfs, "%s call failed with \"%s\"", cb_data->call, (char *)data);
}
int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf)
int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, const void *buf)
{
struct sync_cb_data cb_data;
@ -546,7 +546,7 @@ int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, ui
/*
* write()
*/
int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf)
int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, const void *buf)
{
struct sync_cb_data cb_data;
@ -697,6 +697,21 @@ int nfs_mkdir(struct nfs_context *nfs, const char *path)
return cb_data.status;
}
int nfs_mkdir2(struct nfs_context *nfs, const char *path, int mode)
{
struct sync_cb_data cb_data;
cb_data.is_finished = 0;
if (nfs_mkdir2_async(nfs, path, mode, mkdir_cb, &cb_data) != 0) {
nfs_set_error(nfs, "nfs_mkdir2_async failed");
return -1;
}
wait_for_nfs_reply(nfs, &cb_data);
return cb_data.status;
}
@ -1420,7 +1435,8 @@ int nfs_link(struct nfs_context *nfs, const char *oldpath, const char *newpath)
cb_data.is_finished = 0;
if (nfs_link_async(nfs, oldpath, newpath, link_cb, &cb_data) != 0) {
nfs_set_error(nfs, "nfs_link_async failed");
nfs_set_error(nfs, "nfs_link_async failed: %s",
nfs_get_error(nfs));
return -1;
}

View File

@ -41,6 +41,8 @@ nfs_lseek
nfs_lseek_async
nfs_mkdir
nfs_mkdir_async
nfs_mkdir2
nfs_mkdir2_async
nfs_mknod
nfs_mknod_async
nfs_mount
@ -104,6 +106,7 @@ rpc_disconnect
rpc_get_error
rpc_get_fd
rpc_init_context
rpc_init_server_context
rpc_pmap2_null_async
rpc_pmap2_getport_async
rpc_pmap2_set_async
@ -200,6 +203,8 @@ rpc_nfs3_readlink_async
rpc_nfs3_symlink_async
rpc_nfs3_rename_async
rpc_nfs3_link_async
rpc_nfs4_compound_async
rpc_nfs4_null_async
rpc_nlm4_null_async
rpc_nlm4_test_async
rpc_nlm4_lock_async
@ -212,9 +217,14 @@ rpc_nsm1_unmon_async
rpc_nsm1_unmonall_async
rpc_nsm1_simucrash_async
rpc_nsm1_notify_async
rpc_null_async
rpc_register_service
rpc_rquota1_null_async
rpc_rquota1_getquota_async
rpc_rquota1_getactivequota_async
rpc_send_reply
rpc_service
rpc_set_fd
rpc_set_gid
rpc_set_uid
rpc_which_events

View File

@ -78,7 +78,7 @@ void libnfs_zdrmem_create(ZDR *zdrs, const caddr_t addr, uint32_t size, enum zdr
zdrs->mem = NULL;
}
static void *zdr_malloc(ZDR *zdrs, uint32_t size)
void *zdr_malloc(ZDR *zdrs, uint32_t size)
{
struct zdr_mem *mem;
int mem_size;
@ -205,7 +205,7 @@ bool_t libnfs_zdr_bool(ZDR *zdrs, bool_t *b)
return libnfs_zdr_u_int(zdrs, (uint32_t *)b);
}
bool_t libnfs_zdr_void(void)
bool_t libnfs_zdr_void(ZDR *zdrs, void *v)
{
return TRUE;
}
@ -312,10 +312,6 @@ bool_t libnfs_zdr_array(ZDR *zdrs, char **arrp, uint32_t *size, uint32_t maxsize
return FALSE;
}
if (zdrs->pos + (int)(*size * elsize) > zdrs->size) {
return FALSE;
}
if (zdrs->x_op == ZDR_DECODE) {
*arrp = zdr_malloc(zdrs, *size * elsize);
if (*arrp == NULL) {

172
lib/libnfs.c Normal file → Executable file
View File

@ -27,9 +27,12 @@
#ifdef WIN32
#include "win32_compat.h"
#define PRIu64 "llu"
#else
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#else
#define PRIu64 "llu"
#endif
#ifdef HAVE_UTIME_H
@ -68,7 +71,7 @@
#include <sys/mkdev.h>
#endif
#ifdef MAJOR_IN_SYSMACROS
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
@ -216,7 +219,7 @@ void nfs_pagecache_invalidate(struct nfs_context *nfs, struct nfsfh *nfsfh) {
}
}
static void nfs_pagecache_put(struct nfs_pagecache *pagecache, uint64_t offset, char *buf, size_t len) {
static void nfs_pagecache_put(struct nfs_pagecache *pagecache, uint64_t offset, const char *buf, size_t len) {
time_t ts = pagecache->ttl ? time(NULL) : 1;
if (!pagecache->num_entries) return;
while (len > 0) {
@ -286,7 +289,7 @@ struct nfs_cb_data {
uint64_t offset, max_offset, org_offset;
char *buffer;
int not_my_buffer;
char *usrbuf;
const char *usrbuf;
int update_pos;
};
@ -534,6 +537,7 @@ void nfs_destroy_context(struct nfs_context *nfs)
LIBNFS_LIST_REMOVE(&nfs->nested_mounts, mnt);
free(mnt->path);
free(mnt->fh.data.data_val);
free(mnt);
}
rpc_destroy_context(nfs->rpc);
@ -628,27 +632,12 @@ static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *
return;
}
switch (data->program) {
case MOUNT_PROGRAM:
if (rpc_mount3_null_async(rpc, rpc_connect_program_5_cb,
data) != 0) {
data->cb(rpc, status, command_data, data->private_data);
free_rpc_cb_data(data);
return;
}
return;
case NFS_PROGRAM:
if (rpc_nfs3_null_async(rpc, rpc_connect_program_5_cb,
data) != 0) {
data->cb(rpc, status, command_data, data->private_data);
free_rpc_cb_data(data);
return;
}
return;
}
data->cb(rpc, status, NULL, data->private_data);
free_rpc_cb_data(data);
if (rpc_null_async(rpc, data->program, data->version,
rpc_connect_program_5_cb, data) != 0) {
data->cb(rpc, status, command_data, data->private_data);
free_rpc_cb_data(data);
return;
}
}
static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
@ -969,19 +958,11 @@ static void nfs_mount_10_cb(struct rpc_context *rpc, int status, void *command_d
nfs->writemax = res->FSINFO3res_u.resok.wtmax;
if (nfs->readmax > NFS_MAX_XFER_SIZE) {
rpc_set_error(rpc, "server max rsize of %" PRIu64 " is greater than libnfs supported %d bytes",
nfs->readmax, NFS_MAX_XFER_SIZE);
data->cb(-EINVAL, nfs, command_data, data->private_data);
free_nfs_cb_data(data);
return;
nfs->readmax = NFS_MAX_XFER_SIZE;
}
if (nfs->writemax > NFS_MAX_XFER_SIZE) {
rpc_set_error(rpc, "server max wsize of %" PRIu64 " is greater than libnfs supported %d bytes",
nfs->writemax, NFS_MAX_XFER_SIZE);
data->cb(-EINVAL, nfs, command_data, data->private_data);
free_nfs_cb_data(data);
return;
nfs->writemax = NFS_MAX_XFER_SIZE;
}
memset(&args, 0, sizeof(GETATTR3args));
@ -1086,6 +1067,17 @@ finished:
rpc_disconnect(rpc, "normal disconnect");
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_connect_program_async(nfs->rpc, nfs->server, NFS_PROGRAM, NFS_V3, nfs_mount_9_cb, data) != 0) {
data->cb(-ENOMEM, nfs, command_data, data->private_data);
free_nfs_cb_data(data);
@ -1461,28 +1453,35 @@ static int nfs_lookup_path_async_internal(struct nfs_context *nfs, fattr3 *attr,
path = data->path;
slash = strchr(path, '/');
if (attr && attr->type == NF3LNK && (!data->no_follow || *path != '\0')) {
READLINK3args rl_args;
if (data->link_count++ >= MAX_LINK_COUNT) {
data->cb(-ELOOP, nfs, "Too many levels of symbolic links", data->private_data);
if (attr && attr->type == NF3LNK) {
if (data->continue_int & O_NOFOLLOW) {
data->cb(-ELOOP, nfs, "Symbolic link encountered", data->private_data);
free_nfs_cb_data(data);
return -1;
}
if (!data->no_follow || *path != '\0') {
READLINK3args rl_args;
rl_args.symlink = *fh;
if (data->link_count++ >= MAX_LINK_COUNT) {
data->cb(-ELOOP, nfs, "Too many levels of symbolic links", data->private_data);
free_nfs_cb_data(data);
return -1;
}
if (rpc_nfs3_readlink_async(nfs->rpc, nfs_lookup_path_2_cb, &rl_args, 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;
rl_args.symlink = *fh;
if (rpc_nfs3_readlink_async(nfs->rpc, nfs_lookup_path_2_cb, &rl_args, 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;
}
if (slash != NULL) {
*slash = '/';
}
return 0;
}
if (slash != NULL) {
*slash = '/';
}
return 0;
}
if (slash != NULL) {
@ -2514,7 +2513,7 @@ int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count,
* Async pwrite()
*/
static void nfs_fill_WRITE3args (WRITE3args *args, struct nfsfh *fh, uint64_t offset, uint64_t count,
void *buf)
const void *buf)
{
memset(args, 0, sizeof(WRITE3args));
args->file = fh->fh;
@ -2522,7 +2521,7 @@ static void nfs_fill_WRITE3args (WRITE3args *args, struct nfsfh *fh, uint64_t of
args->count = (count3)count;
args->stable = fh->is_sync ? FILE_SYNC : UNSTABLE;
args->data.data_len = (count3)count;
args->data.data_val = buf;
args->data.data_val = (char *)buf;
}
static void nfs_pwrite_mcb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
@ -2616,7 +2615,7 @@ static void nfs_pwrite_mcb(struct rpc_context *rpc, int status, void *command_da
}
static int nfs_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, size_t count, char *buf, nfs_cb cb, void *private_data, int update_pos)
static int nfs_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, size_t count, const char *buf, nfs_cb cb, void *private_data, int update_pos)
{
struct nfs_cb_data *data;
@ -2688,7 +2687,7 @@ static int nfs_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsf
return 0;
}
int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data)
int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, const void *buf, nfs_cb cb, void *private_data)
{
return nfs_pwrite_async_internal(nfs, nfsfh, offset, (size_t)count, buf, cb, private_data, 0);
}
@ -2731,7 +2730,7 @@ static void nfs_write_append_cb(struct rpc_context *rpc, int status, void *comma
free_nfs_cb_data(data);
}
int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf, nfs_cb cb, void *private_data)
int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, const void *buf, nfs_cb cb, void *private_data)
{
if (nfsfh->is_append) {
struct GETATTR3args args;
@ -2770,12 +2769,30 @@ int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count
* close
*/
static void nfs_close_cb(int err, struct nfs_context *nfs, void *ret_data, void *private_data) {
struct nfs_cb_data *data = private_data;
free_nfsfh(data->nfsfh);
data->cb(err, nfs, ret_data, data->private_data);
free_nfs_cb_data(data);
}
int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
{
free_nfsfh(nfsfh);
cb(0, nfs, NULL, private_data);
return 0;
};
struct nfs_cb_data *data;
data = malloc(sizeof(struct nfs_cb_data));
if (data == NULL) {
rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
return -1;
}
memset(data, 0, sizeof(struct nfs_cb_data));
data->nfsfh = nfsfh;
data->cb = cb;
data->private_data = private_data;
return nfs_fsync_async(nfs, nfsfh, nfs_close_cb, data);
}
@ -3052,6 +3069,7 @@ static void nfs_mkdir_cb(struct rpc_context *rpc, int status, void *command_data
static int nfs_mkdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
{
char *str = data->continue_data;
int mode = data->continue_int;
MKDIR3args args;
str = &str[strlen(str) + 1];
@ -3060,7 +3078,7 @@ static int nfs_mkdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_
args.where.dir = data->fh;
args.where.name = str;
args.attributes.mode.set_it = 1;
args.attributes.mode.set_mode3_u.mode = 0755;
args.attributes.mode.set_mode3_u.mode = mode;
if (rpc_nfs3_mkdir_async(nfs->rpc, nfs_mkdir_cb, &args, data) != 0) {
rpc_set_error(nfs->rpc, "RPC error: Failed to send MKDIR call for %s", data->path);
@ -3071,7 +3089,7 @@ static int nfs_mkdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_
return 0;
}
int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
int nfs_mkdir2_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
{
char *new_path;
char *ptr;
@ -3091,7 +3109,7 @@ int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *
*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, 0, cb, private_data, nfs_mkdir_continue_internal, new_path, free, 0) != 0) {
if (nfs_lookuppath_async(nfs, new_path, 0, cb, private_data, nfs_mkdir_continue_internal, new_path, free, mode) != 0) {
rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path component");
return -1;
}
@ -3099,6 +3117,10 @@ int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *
return 0;
}
int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
{
return nfs_mkdir2_async(nfs, path, 0755, cb, private_data);
}
@ -3270,7 +3292,7 @@ static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_d
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);
free_nfs_cb_data(data);
return;
}
@ -5393,7 +5415,7 @@ static void nfs_link_cb(struct rpc_context *rpc, int status, void *command_data,
return;
}
nfs_dircache_drop(nfs, &data->fh);
nfs_dircache_drop(nfs, &link_data->newdir);
data->cb(0, nfs, NULL, data->private_data);
free_nfs_cb_data(data);
}
@ -5690,3 +5712,21 @@ int nfs_get_timeout(struct nfs_context *nfs)
{
return rpc_get_timeout(nfs->rpc);
}
int rpc_null_async(struct rpc_context *rpc, int program, int version, rpc_cb cb, void *private_data)
{
struct rpc_pdu *pdu;
pdu = rpc_allocate_pdu(rpc, program, version, 0, cb, private_data, (zdrproc_t)zdr_void, 0);
if (pdu == NULL) {
rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for NULL call");
return -1;
}
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NULL call");
return -1;
}
return 0;
}

208
lib/pdu.c
View File

@ -86,6 +86,51 @@ unsigned int rpc_hash_xid(uint32_t xid)
#define PAD_TO_8_BYTES(x) ((x + 0x07) & ~0x07)
static struct rpc_pdu *rpc_allocate_reply_pdu(struct rpc_context *rpc,
struct rpc_msg *res,
size_t alloc_hint)
{
struct rpc_pdu *pdu;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
pdu = malloc(sizeof(struct rpc_pdu));
if (pdu == NULL) {
rpc_set_error(rpc, "Out of memory: Failed to allocate pdu structure");
return NULL;
}
memset(pdu, 0, sizeof(struct rpc_pdu));
pdu->flags = PDU_DISCARD_AFTER_SENDING;
pdu->xid = 0;
pdu->cb = NULL;
pdu->private_data = NULL;
pdu->zdr_decode_fn = NULL;
pdu->zdr_decode_bufsize = 0;
pdu->outdata.data = malloc(ZDR_ENCODEBUF_MINSIZE + alloc_hint);
if (pdu->outdata.data == NULL) {
rpc_set_error(rpc, "Out of memory: Failed to allocate encode buffer");
free(pdu);
return NULL;
}
zdrmem_create(&pdu->zdr, pdu->outdata.data, ZDR_ENCODEBUF_MINSIZE + alloc_hint, ZDR_ENCODE);
if (rpc->is_udp == 0) {
zdr_setpos(&pdu->zdr, 4); /* skip past the record marker */
}
if (zdr_replymsg(rpc, &pdu->zdr, res) == 0) {
rpc_set_error(rpc, "zdr_replymsg failed with %s",
rpc_get_error(rpc));
zdr_destroy(&pdu->zdr);
free(pdu->outdata.data);
free(pdu);
return NULL;
}
return pdu;
}
struct rpc_pdu *rpc_allocate_pdu2(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_decode_bufsize, size_t alloc_hint)
{
struct rpc_pdu *pdu;
@ -115,6 +160,7 @@ struct rpc_pdu *rpc_allocate_pdu2(struct rpc_context *rpc, int program, int vers
pdu->outdata.data = malloc(ZDR_ENCODEBUF_MINSIZE + alloc_hint);
if (pdu->outdata.data == NULL) {
rpc_set_error(rpc, "Out of memory: Failed to allocate encode buffer");
free(pdu);
return NULL;
}
@ -137,6 +183,7 @@ struct rpc_pdu *rpc_allocate_pdu2(struct rpc_context *rpc, int program, int vers
rpc_set_error(rpc, "zdr_callmsg failed with %s",
rpc_get_error(rpc));
zdr_destroy(&pdu->zdr);
free(pdu->outdata.data);
free(pdu);
return NULL;
}
@ -153,14 +200,10 @@ void rpc_free_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
{
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (pdu->outdata.data != NULL) {
free(pdu->outdata.data);
pdu->outdata.data = NULL;
}
free(pdu->outdata.data);
if (pdu->zdr_decode_buf != NULL) {
zdr_free(pdu->zdr_decode_fn, pdu->zdr_decode_buf);
pdu->zdr_decode_buf = NULL;
}
zdr_destroy(&pdu->zdr);
@ -179,6 +222,12 @@ int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (rpc->timeout > 0) {
pdu->timeout = time(NULL) + rpc->timeout / 1000;
} else {
pdu->timeout = 0;
}
size = zdr_getpos(&pdu->zdr);
/* for udp we dont queue, we just send it straight away */
@ -186,7 +235,9 @@ int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
unsigned int hash;
// XXX add a rpc->udp_dest_sock_size and get rid of sys/socket.h and netinet/in.h
if (sendto(rpc->fd, pdu->zdr.buf, size, MSG_DONTWAIT, rpc->udp_dest, sizeof(struct sockaddr_in)) < 0) {
if (sendto(rpc->fd, pdu->zdr.buf, size, MSG_DONTWAIT,
(struct sockaddr *)&rpc->udp_dest,
sizeof(rpc->udp_dest)) < 0) {
rpc_set_error(rpc, "Sendto failed with errno %s", strerror(errno));
rpc_free_pdu(rpc, pdu);
return -1;
@ -194,6 +245,7 @@ int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
hash = rpc_hash_xid(pdu->xid);
rpc_enqueue(&rpc->waitpdu[hash], pdu);
rpc->waitpdu_len++;
return 0;
}
@ -230,7 +282,6 @@ static int rpc_process_reply(struct rpc_context *rpc, struct rpc_pdu *pdu, ZDR *
}
msg.body.rbody.reply.areply.reply_data.results.where = pdu->zdr_decode_buf;
msg.body.rbody.reply.areply.reply_data.results.proc = pdu->zdr_decode_fn;
if (zdr_replymsg(rpc, zdr, &msg) == 0) {
rpc_set_error(rpc, "zdr_replymsg failed in rpc_process_reply: "
"%s", rpc_get_error(rpc));
@ -272,6 +323,137 @@ static int rpc_process_reply(struct rpc_context *rpc, struct rpc_pdu *pdu, ZDR *
return 0;
}
static int rpc_send_error_reply(struct rpc_context *rpc,
struct rpc_msg *call,
enum accept_stat err,
int min_vers, int max_vers)
{
struct rpc_pdu *pdu;
struct rpc_msg res;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
memset(&res, 0, sizeof(struct rpc_msg));
res.xid = call->xid;
res.direction = REPLY;
res.body.rbody.stat = MSG_ACCEPTED;
res.body.rbody.reply.areply.reply_data.mismatch_info.low = min_vers;
res.body.rbody.reply.areply.reply_data.mismatch_info.high = max_vers;
res.body.rbody.reply.areply.verf = _null_auth;
res.body.rbody.reply.areply.stat = err;
if (rpc->is_udp) {
/* send the reply back to the client */
memcpy(&rpc->udp_dest, &rpc->udp_src, sizeof(rpc->udp_dest));
}
pdu = rpc_allocate_reply_pdu(rpc, &res, 0);
if (pdu == NULL) {
rpc_set_error(rpc, "Failed to send error_reply: %s",
rpc_get_error(rpc));
return -1;
}
rpc_queue_pdu(rpc, pdu);
return 0;
}
int rpc_send_reply(struct rpc_context *rpc,
struct rpc_msg *call,
void *reply,
zdrproc_t encode_fn,
int alloc_hint)
{
struct rpc_pdu *pdu;
struct rpc_msg res;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
memset(&res, 0, sizeof(struct rpc_msg));
res.xid = call->xid;
res.direction = REPLY;
res.body.rbody.stat = MSG_ACCEPTED;
res.body.rbody.reply.areply.verf = _null_auth;
res.body.rbody.reply.areply.stat = SUCCESS;
res.body.rbody.reply.areply.reply_data.results.where = reply;
res.body.rbody.reply.areply.reply_data.results.proc = encode_fn;
if (rpc->is_udp) {
/* send the reply back to the client */
memcpy(&rpc->udp_dest, &rpc->udp_src, sizeof(rpc->udp_dest));
}
pdu = rpc_allocate_reply_pdu(rpc, &res, alloc_hint);
if (pdu == NULL) {
rpc_set_error(rpc, "Failed to send error_reply: %s",
rpc_get_error(rpc));
return -1;
}
rpc_queue_pdu(rpc, pdu);
return 0;
}
static int rpc_process_call(struct rpc_context *rpc, ZDR *zdr)
{
struct rpc_msg call;
struct rpc_endpoint *endpoint;
int i, min_version = 0, max_version = 0, found_program = 0;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
memset(&call, 0, sizeof(struct rpc_msg));
if (zdr_callmsg(rpc, zdr, &call) == 0) {
rpc_set_error(rpc, "Failed to decode CALL message. %s",
rpc_get_error(rpc));
return rpc_send_error_reply(rpc, &call, GARBAGE_ARGS, 0, 0);
}
for (endpoint = rpc->endpoints; endpoint; endpoint = endpoint->next) {
if (call.body.cbody.prog == endpoint->program) {
if (!found_program) {
min_version = max_version = endpoint->version;
}
if (endpoint->version < min_version) {
min_version = endpoint->version;
}
if (endpoint->version > max_version) {
max_version = endpoint->version;
}
found_program = 1;
if (call.body.cbody.vers == endpoint->version) {
break;
}
}
}
if (endpoint == NULL) {
rpc_set_error(rpc, "No endpoint found for CALL "
"program:0x%08x version:%d\n",
call.body.cbody.prog, call.body.cbody.vers);
if (!found_program) {
return rpc_send_error_reply(rpc, &call, PROG_UNAVAIL,
0, 0);
}
return rpc_send_error_reply(rpc, &call, PROG_MISMATCH,
min_version, max_version);
}
for (i = 0; i < endpoint->num_procs; i++) {
if (endpoint->procs[i].proc == call.body.cbody.proc) {
if (endpoint->procs[i].decode_buf_size) {
call.body.cbody.args = zdr_malloc(zdr, endpoint->procs[i].decode_buf_size);
}
if (!endpoint->procs[i].decode_fn(zdr, call.body.cbody.args)) {
rpc_set_error(rpc, "Failed to unmarshall "
"call payload");
return rpc_send_error_reply(rpc, &call, GARBAGE_ARGS, 0 ,0);
}
return endpoint->procs[i].func(rpc, &call);
}
}
return rpc_send_error_reply(rpc, &call, PROC_UNAVAIL, 0 ,0);
}
int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size)
{
struct rpc_pdu *pdu, *prev_pdu;
@ -330,6 +512,17 @@ int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size)
rpc_free_all_fragments(rpc);
}
if (rpc->is_server_context) {
int ret;
ret = rpc_process_call(rpc, &zdr);
zdr_destroy(&zdr);
if (reasbuf != NULL) {
free(reasbuf);
}
return ret;
}
pos = zdr_getpos(&zdr);
if (zdr_int(&zdr, (int *)&xid) == 0) {
rpc_set_error(rpc, "zdr_int reading xid failed");
@ -361,6 +554,7 @@ int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size)
q->tail = prev_pdu;
if (prev_pdu != NULL)
prev_pdu->next = pdu->next;
rpc->waitpdu_len--;
}
if (rpc_process_reply(rpc, pdu, &zdr) != 0) {
rpc_set_error(rpc, "rpc_procdess_reply failed");

View File

@ -85,19 +85,35 @@
#include "win32_errnowrapper.h"
#endif
static int rpc_reconnect_requeue(struct rpc_context *rpc);
static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s);
#define NR_RECONNECT_RETRIES 10
static void set_nonblocking(int fd)
static int rpc_reconnect_requeue(struct rpc_context *rpc);
static int create_socket(int domain, int type, int protocol)
{
#ifdef SOCK_CLOEXEC
/* Linux-specific extension (since 2.6.27): set the
close-on-exec flag on all sockets to avoid leaking file
descriptors to child processes */
int fd = socket(domain, type|SOCK_CLOEXEC, protocol);
if (fd >= 0 || errno != EINVAL)
return fd;
#endif
return socket(domain, type, protocol);
}
static int set_nonblocking(int fd)
{
int v = 0;
#if defined(WIN32)
long nonblocking=1;
u_long nonblocking=1;
v = ioctl(fd, FIONBIO, &nonblocking);
#else
v = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, v | O_NONBLOCK);
v = fcntl(fd, F_SETFL, v | O_NONBLOCK);
#endif //FIXME
return v;
}
static void set_nolinger(int fd)
@ -210,8 +226,14 @@ static int rpc_write_to_socket(struct rpc_context *rpc)
if (pdu->next == NULL)
rpc->outqueue.tail = NULL;
if (pdu->flags & PDU_DISCARD_AFTER_SENDING) {
rpc_free_pdu(rpc, pdu);
return 0;
}
hash = rpc_hash_xid(pdu->xid);
rpc_enqueue(&rpc->waitpdu[hash], pdu);
rpc->waitpdu_len++;
}
}
return 0;
@ -222,11 +244,11 @@ static int rpc_read_from_socket(struct rpc_context *rpc)
{
uint32_t pdu_size;
ssize_t count;
char *buf;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (rpc->is_udp) {
char *buf;
socklen_t socklen = sizeof(rpc->udp_src);
buf = malloc(MAX_UDP_SIZE);
@ -252,61 +274,63 @@ static int rpc_read_from_socket(struct rpc_context *rpc)
return 0;
}
again:
/* read record marker, 4 bytes at the beginning of every pdu first */
pdu_size = rpc->inpos < 4 ? 4 : rpc_get_pdu_size(rpc->inbuf);
do {
/* read record marker, 4 bytes at the beginning of every pdu first */
if (rpc->inpos < 4) {
buf = (void *)rpc->rm_buf;
pdu_size = 4;
} else {
pdu_size = rpc_get_pdu_size((void *)&rpc->rm_buf);
if (rpc->inbuf == NULL) {
if (pdu_size > NFS_MAX_XFER_SIZE + 4096) {
rpc_set_error(rpc, "Incoming PDU exceeds limit of %d bytes.", NFS_MAX_XFER_SIZE + 4096);
return -1;
}
rpc->inbuf = malloc(pdu_size);
if (rpc->inbuf == NULL) {
rpc_set_error(rpc, "Failed to allocate buffer of %d bytes for pdu, errno:%d. Closing socket.", pdu_size, errno);
return -1;
}
memcpy(rpc->inbuf, &rpc->rm_buf, 4);
}
buf = rpc->inbuf;
}
if (pdu_size > NFS_MAX_XFER_SIZE + 4096) {
rpc_set_error(rpc, "Incoming PDU exceeds limit of %d bytes.", NFS_MAX_XFER_SIZE + 4096);
return -1;
}
if (rpc->insize < pdu_size) {
rpc->inbuf = realloc(rpc->inbuf, pdu_size);
if (rpc->inbuf == NULL) {
rpc_set_error(rpc, "Failed to allocate buffer of %d bytes for pdu, errno:%d. Closing socket.", pdu_size, errno);
count = recv(rpc->fd, buf + rpc->inpos, pdu_size - rpc->inpos, MSG_DONTWAIT);
if (count < 0) {
if (errno == EINTR || errno == EAGAIN) {
break;
}
rpc_set_error(rpc, "Read from socket failed, errno:%d. Closing socket.", errno);
return -1;
}
rpc->insize = pdu_size;
}
count = recv(rpc->fd, rpc->inbuf + rpc->inpos, rpc->insize - rpc->inpos, MSG_DONTWAIT);
if (count < 0) {
if (errno == EINTR || errno == EAGAIN) {
return 0;
}
rpc_set_error(rpc, "Read from socket failed, errno:%d. Closing socket.", errno);
return -1;
}
if (count == 0) {
/* remote side has closed the socket. Reconnect. */
return -1;
}
rpc->inpos += count;
if (rpc->inpos == 4) {
/* we have just read the header there is likely more data available */
goto again;
}
if (rpc->inpos == rpc->insize) {
char *buf = rpc->inbuf;
rpc->inbuf = NULL;
rpc->insize = 0;
rpc->inpos = 0;
if (rpc_process_pdu(rpc, buf, pdu_size) != 0) {
rpc_set_error(rpc, "Invalid/garbage pdu received from server. Closing socket");
if (count == 0) {
/* remote side has closed the socket. Reconnect. */
return -1;
}
free(buf);
}
rpc->inpos += count;
if (rpc->inpos == 4) {
/* we have just read the header there is likely more data available */
continue;
}
if (rpc->inpos == pdu_size) {
rpc->inbuf = NULL;
rpc->inpos = 0;
if (rpc_process_pdu(rpc, buf, pdu_size) != 0) {
rpc_set_error(rpc, "Invalid/garbage pdu received from server. Closing socket");
free(buf);
return -1;
}
free(buf);
}
} while (rpc->is_nonblocking && rpc->waitpdu_len > 0);
return 0;
}
static void
maybe_call_connect_cb(struct rpc_context *rpc, int status)
{
@ -320,10 +344,59 @@ maybe_call_connect_cb(struct rpc_context *rpc, int status)
tmp_cb(rpc, status, rpc->error_string, rpc->connect_data);
}
static void
rpc_timeout_scan(struct rpc_context *rpc)
{
struct rpc_pdu *pdu;
struct rpc_pdu *next_pdu;
time_t t = time(NULL);
unsigned int i;
for (pdu = rpc->outqueue.head; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
if (pdu->timeout == 0) {
/* no timeout for this pdu */
continue;
}
if (t < pdu->timeout) {
/* not expired yet */
continue;
}
LIBNFS_LIST_REMOVE(&rpc->outqueue.head, pdu);
rpc_set_error(rpc, "command timed out");
pdu->cb(rpc, RPC_STATUS_TIMEOUT,
NULL, pdu->private_data);
rpc_free_pdu(rpc, pdu);
}
for (i = 0; i < HASHES; i++) {
struct rpc_queue *q = &rpc->waitpdu[i];
for (pdu = q->head; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
if (pdu->timeout == 0) {
/* no timeout for this pdu */
continue;
}
if (t < pdu->timeout) {
/* not expired yet */
continue;
}
LIBNFS_LIST_REMOVE(&q->head, pdu);
rpc_set_error(rpc, "command timed out");
pdu->cb(rpc, RPC_STATUS_TIMEOUT,
NULL, pdu->private_data);
rpc_free_pdu(rpc, pdu);
}
}
}
int rpc_service(struct rpc_context *rpc, int revents)
{
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (revents & (POLLERR|POLLHUP)) {
if (revents & (POLLERR | POLLHUP)) {
if (revents & POLLERR) {
#ifdef WIN32
char err = 0;
@ -356,7 +429,7 @@ int rpc_service(struct rpc_context *rpc, int revents)
}
if (rpc->is_connected == 0 && rpc->fd != -1 && revents&POLLOUT) {
if (rpc->is_connected == 0 && rpc->fd != -1 && (revents & POLLOUT)) {
int err = 0;
socklen_t err_size = sizeof(err);
@ -380,16 +453,25 @@ int rpc_service(struct rpc_context *rpc, int revents)
if (revents & POLLIN) {
if (rpc_read_from_socket(rpc) != 0) {
return rpc_reconnect_requeue(rpc);
if (rpc->is_server_context) {
return -1;
} else {
return rpc_reconnect_requeue(rpc);
}
}
}
if (revents & POLLOUT && rpc_has_queue(&rpc->outqueue)) {
if (rpc_write_to_socket(rpc) != 0) {
return rpc_reconnect_requeue(rpc);
if (rpc->is_server_context) {
return -1;
} else {
return rpc_reconnect_requeue(rpc);
}
}
}
rpc_timeout_scan(rpc);
return 0;
}
@ -397,6 +479,11 @@ void rpc_set_autoreconnect(struct rpc_context *rpc)
{
assert(rpc->magic == RPC_CONTEXT_MAGIC);
/* we can not connect and not reconnect on a server context. */
if (rpc->is_server_context) {
return;
}
rpc->auto_reconnect = 1;
}
@ -404,6 +491,10 @@ void rpc_unset_autoreconnect(struct rpc_context *rpc)
{
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (rpc->is_server_context) {
return;
}
rpc->auto_reconnect = 0;
}
@ -418,16 +509,17 @@ void rpc_set_tcp_syncnt(struct rpc_context *rpc, int v)
#define TCP_SYNCNT 7
#endif
static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s)
static int rpc_connect_sockaddr_async(struct rpc_context *rpc)
{
int socksize;
struct sockaddr_storage *s = &rpc->s;
socklen_t socksize;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
switch (s->ss_family) {
case AF_INET:
socksize = sizeof(struct sockaddr_in);
rpc->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
rpc->fd = create_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (set_bind_device(rpc->fd, rpc->ifname) != 0) {
rpc_set_error (rpc, "Failed to bind to interface");
return -1;
@ -441,7 +533,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
break;
case AF_INET6:
socksize = sizeof(struct sockaddr_in6);
rpc->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
rpc->fd = create_socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (set_bind_device(rpc->fd, rpc->ifname) != 0) {
rpc_set_error (rpc, "Failed to bind to interface");
return -1;
@ -536,7 +628,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
} while (rc != 0 && portOfs != startOfs);
}
set_nonblocking(rpc->fd);
rpc->is_nonblocking = !set_nonblocking(rpc->fd);
set_nolinger(rpc->fd);
if (connect(rpc->fd, (struct sockaddr *)s, socksize) != 0 && errno != EINPROGRESS) {
@ -547,24 +639,11 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
return 0;
}
int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data)
static int rpc_set_sockaddr(struct rpc_context *rpc, const char *server,
int port)
{
struct addrinfo *ai = NULL;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (rpc->fd != -1) {
rpc_set_error(rpc, "Trying to connect while already connected");
return -1;
}
if (rpc->is_udp != 0) {
rpc_set_error(rpc, "Trying to connect on UDP socket");
return -1;
}
rpc->auto_reconnect = 0;
if (getaddrinfo(server, NULL, NULL, &ai) != 0) {
rpc_set_error(rpc, "Invalid address:%s. "
"Can not resolv into IPv4/v6 structure.", server);
@ -589,13 +668,40 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
#endif
break;
}
freeaddrinfo(ai);
return 0;
}
int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data)
{
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (rpc->is_server_context) {
rpc_set_error(rpc, "Can not connect on a server context");
return -1;
}
if (rpc->fd != -1) {
rpc_set_error(rpc, "Trying to connect while already connected");
return -1;
}
if (rpc->is_udp != 0) {
rpc_set_error(rpc, "Trying to connect on UDP socket");
return -1;
}
rpc->auto_reconnect = 0;
if (rpc_set_sockaddr(rpc, server, port) != 0) {
return -1;
}
rpc->connect_cb = cb;
rpc->connect_data = private_data;
freeaddrinfo(ai);
if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) {
if (rpc_connect_sockaddr_async(rpc) != 0) {
return -1;
}
@ -619,7 +725,9 @@ int rpc_disconnect(struct rpc_context *rpc, const char *error)
rpc->is_connected = 0;
rpc_error_all_pdus(rpc, error);
if (!rpc->is_server_context) {
rpc_error_all_pdus(rpc, error);
}
return 0;
}
@ -647,6 +755,9 @@ static int rpc_reconnect_requeue(struct rpc_context *rpc)
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (rpc->is_connected)
rpc->auto_reconnect_retries = NR_RECONNECT_RETRIES;
if (rpc->fd != -1) {
rpc->old_fd = rpc->fd;
}
@ -670,11 +781,13 @@ static int rpc_reconnect_requeue(struct rpc_context *rpc)
}
rpc_reset_queue(q);
}
rpc->waitpdu_len = 0;
if (rpc->auto_reconnect != 0) {
if (rpc->auto_reconnect != 0 && rpc->auto_reconnect_retries > 0) {
rpc->auto_reconnect_retries--;
rpc->connect_cb = reconnect_cb;
RPC_LOG(rpc, 1, "reconnect initiated");
if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) {
if (rpc_connect_sockaddr_async(rpc) != 0) {
rpc_error_all_pdus(rpc, "RPC ERROR: Failed to reconnect async");
return -1;
}
@ -708,7 +821,7 @@ int rpc_bind_udp(struct rpc_context *rpc, char *addr, int port)
switch(ai->ai_family) {
case AF_INET:
rpc->fd = socket(ai->ai_family, SOCK_DGRAM, 0);
rpc->fd = create_socket(ai->ai_family, SOCK_DGRAM, 0);
if (rpc->fd == -1) {
rpc_set_error(rpc, "Failed to create UDP socket: %s", strerror(errno));
freeaddrinfo(ai);
@ -751,17 +864,7 @@ int rpc_set_udp_destination(struct rpc_context *rpc, char *addr, int port, int i
return -1;
}
if (rpc->udp_dest) {
free(rpc->udp_dest);
rpc->udp_dest = NULL;
}
rpc->udp_dest = malloc(ai->ai_addrlen);
if (rpc->udp_dest == NULL) {
rpc_set_error(rpc, "Out of memory. Failed to allocate sockaddr structure");
freeaddrinfo(ai);
return -1;
}
memcpy(rpc->udp_dest, ai->ai_addr, ai->ai_addrlen);
memcpy(&rpc->udp_dest, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
rpc->is_broadcast = is_broadcast;
@ -779,9 +882,8 @@ struct sockaddr *rpc_get_recv_sockaddr(struct rpc_context *rpc)
int rpc_queue_length(struct rpc_context *rpc)
{
int i=0;
int i = 0;
struct rpc_pdu *pdu;
unsigned int n;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
@ -789,12 +891,8 @@ int rpc_queue_length(struct rpc_context *rpc)
i++;
}
for (n = 0; n < HASHES; n++) {
struct rpc_queue *q = &rpc->waitpdu[n];
i += rpc->waitpdu_len;
for(pdu = q->head; pdu; pdu = pdu->next)
i++;
}
return i;
}
@ -804,3 +902,16 @@ void rpc_set_fd(struct rpc_context *rpc, int fd)
rpc->fd = fd;
}
int rpc_is_udp_socket(struct rpc_context *rpc)
{
#ifdef WIN32
char type = 0;
#else
int type = 0;
#endif
socklen_t len = sizeof(type);
getsockopt(rpc->fd, SOL_SOCKET, SO_TYPE, &type, &len);
return type == SOCK_DGRAM;
}

View File

@ -39,7 +39,6 @@ int rpc_mount3_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data
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 -1;
}
@ -69,7 +68,6 @@ int rpc_mount3_mnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void
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 -1;
}
@ -93,7 +91,6 @@ int rpc_mount3_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue mount/dump pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -123,7 +120,6 @@ int rpc_mount3_umnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue mount/umnt pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -147,7 +143,6 @@ int rpc_mount3_umntall_async(struct rpc_context *rpc, rpc_cb cb, void *private_d
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue mount/umntall pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -171,7 +166,6 @@ int rpc_mount3_export_async(struct rpc_context *rpc, rpc_cb cb, void *private_da
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue mount/export pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -235,7 +229,6 @@ int rpc_mount1_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for MOUNT1/NULL call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -260,7 +253,6 @@ int rpc_mount1_mnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for MOUNT1/MNT call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -279,7 +271,6 @@ int rpc_mount1_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue MOUNT1/DUMP pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -304,7 +295,6 @@ int rpc_mount1_umnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue MOUNT1/UMNT pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -323,7 +313,6 @@ int rpc_mount1_umntall_async(struct rpc_context *rpc, rpc_cb cb, void *private_d
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue MOUNT1/UMNTALL pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -342,7 +331,6 @@ int rpc_mount1_export_async(struct rpc_context *rpc, rpc_cb cb, void *private_da
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue MOUNT1/EXPORT pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}

View File

@ -88,7 +88,7 @@ int nfsstat3_to_errno(int error)
case NFS3ERR_NAMETOOLONG: return -ENAMETOOLONG; break;
case NFS3ERR_NOTEMPTY: return -ENOTEMPTY; break;
case NFS3ERR_DQUOT: return -ERANGE; break;
case NFS3ERR_STALE: return -EIO; break;
case NFS3ERR_STALE: return -ESTALE; break;
case NFS3ERR_REMOTE: return -EIO; break;
case NFS3ERR_BADHANDLE: return -EIO; break;
case NFS3ERR_NOT_SYNC: return -EIO; break;
@ -118,7 +118,6 @@ int rpc_nfs3_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/NULL call");
rpc_free_pdu(rpc, pdu);
return -2;
}
@ -148,7 +147,6 @@ int rpc_nfs3_getattr_async(struct rpc_context *rpc, rpc_cb cb, struct GETATTR3ar
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/GETATTR call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -184,7 +182,6 @@ int rpc_nfs3_pathconf_async(struct rpc_context *rpc, rpc_cb cb, struct PATHCONF3
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/PATHCONF call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -220,7 +217,6 @@ int rpc_nfs3_lookup_async(struct rpc_context *rpc, rpc_cb cb, struct LOOKUP3args
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/LOOKUP call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -257,7 +253,6 @@ int rpc_nfs3_access_async(struct rpc_context *rpc, rpc_cb cb, struct ACCESS3args
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/ACCESS call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -294,7 +289,6 @@ int rpc_nfs3_read_async(struct rpc_context *rpc, rpc_cb cb, struct READ3args *ar
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/READ call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -332,7 +326,6 @@ int rpc_nfs3_write_async(struct rpc_context *rpc, rpc_cb cb, struct WRITE3args *
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/WRITE call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -373,7 +366,6 @@ int rpc_nfs3_commit_async(struct rpc_context *rpc, rpc_cb cb, struct COMMIT3args
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/COMMIT call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -411,7 +403,6 @@ int rpc_nfs3_setattr_async(struct rpc_context *rpc, rpc_cb cb, SETATTR3args *arg
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/SETATTR call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -441,7 +432,6 @@ int rpc_nfs3_mkdir_async(struct rpc_context *rpc, rpc_cb cb, MKDIR3args *args, v
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/MKDIR call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -471,7 +461,6 @@ int rpc_nfs3_rmdir_async(struct rpc_context *rpc, rpc_cb cb, struct RMDIR3args *
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/RMDIR call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -508,7 +497,6 @@ int rpc_nfs3_create_async(struct rpc_context *rpc, rpc_cb cb, CREATE3args *args,
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/CREATE call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -538,7 +526,6 @@ int rpc_nfs3_mknod_async(struct rpc_context *rpc, rpc_cb cb, struct MKNOD3args *
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/MKNOD call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -604,7 +591,6 @@ int rpc_nfs3_remove_async(struct rpc_context *rpc, rpc_cb cb, struct REMOVE3args
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/REMOVE call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -641,7 +627,6 @@ int rpc_nfs3_readdir_async(struct rpc_context *rpc, rpc_cb cb, struct READDIR3ar
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/READDIR call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -680,7 +665,6 @@ int rpc_nfs3_readdirplus_async(struct rpc_context *rpc, rpc_cb cb, struct READDI
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/READDIRPLUS call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -720,7 +704,6 @@ int rpc_nfs3_fsstat_async(struct rpc_context *rpc, rpc_cb cb, struct FSSTAT3args
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/FSSTAT call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -756,7 +739,6 @@ int rpc_nfs3_fsinfo_async(struct rpc_context *rpc, rpc_cb cb, struct FSINFO3args
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/FSINFO call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -792,7 +774,6 @@ int rpc_nfs3_readlink_async(struct rpc_context *rpc, rpc_cb cb, READLINK3args *a
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/READLINK call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -822,7 +803,6 @@ int rpc_nfs3_symlink_async(struct rpc_context *rpc, rpc_cb cb, SYMLINK3args *arg
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/SYMLINK call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -852,7 +832,6 @@ int rpc_nfs3_rename_async(struct rpc_context *rpc, rpc_cb cb, struct RENAME3args
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/RENAME call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -892,7 +871,6 @@ int rpc_nfs3_link_async(struct rpc_context *rpc, rpc_cb cb, struct LINK3args *ar
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/LINK call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -928,7 +906,6 @@ int rpc_nfs2_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/NULL call");
rpc_free_pdu(rpc, pdu);
return -2;
}
@ -953,7 +930,6 @@ int rpc_nfs2_getattr_async(struct rpc_context *rpc, rpc_cb cb, struct GETATTR2ar
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/GETATTR call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -978,7 +954,6 @@ int rpc_nfs2_setattr_async(struct rpc_context *rpc, rpc_cb cb, SETATTR2args *arg
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/SETATTR call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1003,7 +978,6 @@ int rpc_nfs2_lookup_async(struct rpc_context *rpc, rpc_cb cb, struct LOOKUP2args
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/LOOKUP call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1028,7 +1002,6 @@ int rpc_nfs2_readlink_async(struct rpc_context *rpc, rpc_cb cb, READLINK2args *a
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/READLINK call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1053,7 +1026,6 @@ int rpc_nfs2_read_async(struct rpc_context *rpc, rpc_cb cb, struct READ2args *ar
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/READ call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1078,7 +1050,6 @@ int rpc_nfs2_write_async(struct rpc_context *rpc, rpc_cb cb, struct WRITE2args *
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/WRITE call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1103,7 +1074,6 @@ int rpc_nfs2_create_async(struct rpc_context *rpc, rpc_cb cb, CREATE2args *args,
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/CREATE call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1128,7 +1098,6 @@ int rpc_nfs2_remove_async(struct rpc_context *rpc, rpc_cb cb, struct REMOVE2args
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/REMOVE call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1153,7 +1122,6 @@ int rpc_nfs2_rename_async(struct rpc_context *rpc, rpc_cb cb, struct RENAME2args
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/RENAME call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1178,7 +1146,6 @@ int rpc_nfs2_link_async(struct rpc_context *rpc, rpc_cb cb, LINK2args *args, voi
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/LINK call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1203,7 +1170,6 @@ int rpc_nfs2_symlink_async(struct rpc_context *rpc, rpc_cb cb, SYMLINK2args *arg
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/SYMLINK call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1228,7 +1194,6 @@ int rpc_nfs2_mkdir_async(struct rpc_context *rpc, rpc_cb cb, MKDIR2args *args, v
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/MKDIR call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1253,7 +1218,6 @@ int rpc_nfs2_rmdir_async(struct rpc_context *rpc, rpc_cb cb, struct RMDIR2args *
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/RMDIR call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1278,7 +1242,6 @@ int rpc_nfs2_readdir_async(struct rpc_context *rpc, rpc_cb cb, struct READDIR2ar
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/READDIR call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -1303,7 +1266,6 @@ int rpc_nfs2_statfs_async(struct rpc_context *rpc, rpc_cb cb, struct STATFS2args
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/STATFS call");
rpc_free_pdu(rpc, pdu);
return -3;
}

View File

@ -42,7 +42,6 @@ int rpc_nfsacl_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfsacl/null call");
rpc_free_pdu(rpc, pdu);
return -2;
}
@ -68,7 +67,6 @@ int rpc_nfsacl_getacl_async(struct rpc_context *rpc, rpc_cb cb, struct GETACL3ar
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfsacl/getacl call");
rpc_free_pdu(rpc, pdu);
return -2;
}
@ -93,7 +91,6 @@ int rpc_nfsacl_setacl_async(struct rpc_context *rpc, rpc_cb cb, struct SETACL3ar
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfsacl/setacl call");
rpc_free_pdu(rpc, pdu);
return -2;
}

25
nfs4/Makefile.am Normal file
View File

@ -0,0 +1,25 @@
noinst_LTLIBRARIES = libnfs4.la
nfs4_SOURCES_GENERATED =
nfs4_HEADERS_GENERATED =
nfs4_GENERATED = $(nfs4_SOURCES_GENERATED) $(nfs4_HEADERS_GENERATED)
CLEANFILES = $(nfs_GENERATED) nfs4-stamp
libnfs4_la_CPPFLAGS = -I$(abs_top_srcdir)/include \
-I$(abs_top_srcdir)/include/nfsc \
-I$(abs_top_srcdir)/win32
libnfs4_la_SOURCES = \
$(nfs4_SOURCES_GENERATED) \
nfs4.c libnfs-raw-nfs4.c libnfs-raw-nfs4.h
$(nfs4_GENERATED) : nfs4-stamp
nfs4-stamp : nfs4.x
rm -f $(nfs_GENERATED)
touch nfs4-stamp
compile_rpc:
cat nfs4.x | head -29 >libnfs-raw-nfs4.h
rpcgen -h nfs4.x | sed -e "s/#include <rpc\/rpc.h>/#include <nfsc\/libnfs-zdr.h>/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/#define _NFS_H_RPCGEN/#define _NFS_H_RPCGEN\n#include <nfsc\/libnfs-zdr.h>/g" -e "s/#define NFS3_COOKIEVERFSIZE 8/#define NFS3_COOKIEVERFSIZE 8\n\n/g" -e "s/ CLIENT / void /g" -e "s/SVCXPRT /void /g" -e "s/bool_t/uint32_t/g" >> libnfs-raw-nfs4.h
cat nfs4.x | head -29 >libnfs-raw-nfs4.c
rpcgen -c nfs4.x | sed -e "s/#include \".*nfs4.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-nfs4.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;//" -e "s/bool_t/uint32_t/g" -e "s/int i;//" >> libnfs-raw-nfs4.c

3052
nfs4/libnfs-raw-nfs4.c Normal file

File diff suppressed because it is too large Load Diff

1987
nfs4/libnfs-raw-nfs4.h Normal file

File diff suppressed because it is too large Load Diff

219
nfs4/nfs4.c Normal file
View File

@ -0,0 +1,219 @@
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
/*
Copyright (C) 2016 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/>.
*/
#ifdef WIN32
#include "win32_compat.h"
#else
#include <sys/stat.h>
#endif/*WIN32*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "libnfs-zdr.h"
#include "libnfs.h"
#include "libnfs-raw.h"
#include "libnfs-private.h"
#include "libnfs-raw-nfs4.h"
char *nfsstat4_to_str(int error)
{
switch (error) {
case NFS4_OK: return "NFS4_OK"; break;
case NFS4ERR_PERM: return "NFS4ERR_PERM"; break;
case NFS4ERR_NOENT: return "NFS4ERR_NOENT"; break;
case NFS4ERR_IO: return "NFS4ERR_IO"; break;
case NFS4ERR_NXIO: return "NFS4ERR_NXIO"; break;
case NFS4ERR_ACCESS: return "NFS4ERR_ACCESS"; break;
case NFS4ERR_EXIST: return "NFS4ERR_EXIST"; break;
case NFS4ERR_XDEV: return "NFS4ERR_XDEV"; break;
case NFS4ERR_NOTDIR: return "NFS4ERR_NOTDIR"; break;
case NFS4ERR_ISDIR: return "NFS4ERR_ISDIR"; break;
case NFS4ERR_INVAL: return "NFS4ERR_INVAL"; break;
case NFS4ERR_FBIG: return "NFS4ERR_FBIG"; break;
case NFS4ERR_NOSPC: return "NFS4ERR_NOSPC"; break;
case NFS4ERR_ROFS: return"NFS4ERR_ROFS"; break;
case NFS4ERR_MLINK: return "NFS4ERR_MLINK"; break;
case NFS4ERR_NAMETOOLONG: return "NFS4ERR_NAMETOOLONG"; break;
case NFS4ERR_NOTEMPTY: return "NFS4ERR_NOTEMPTY"; break;
case NFS4ERR_DQUOT: return "NFS4ERR_DQUOT"; break;
case NFS4ERR_STALE: return "NFS4ERR_STALE"; break;
case NFS4ERR_BADHANDLE: return "NFS4ERR_BADHANDLE"; break;
case NFS4ERR_BAD_COOKIE: return "NFS4ERR_BAD_COOKIE"; break;
case NFS4ERR_NOTSUPP: return "NFS4ERR_NOTSUPP"; break;
case NFS4ERR_TOOSMALL: return "NFS4ERR_TOOSMALL"; break;
case NFS4ERR_SERVERFAULT: return "NFS4ERR_SERVERFAULT"; break;
case NFS4ERR_BADTYPE: return "NFS4ERR_BADTYPE"; break;
case NFS4ERR_DELAY: return "NFS4ERR_DELAY"; break;
case NFS4ERR_SAME: return "NFS4ERR_SAME"; break;
case NFS4ERR_DENIED: return "NFS4ERR_DENIED"; break;
case NFS4ERR_EXPIRED: return "NFS4ERR_EXPIRED"; break;
case NFS4ERR_LOCKED: return "NFS4ERR_LOCKED"; break;
case NFS4ERR_GRACE: return "NFS4ERR_GRACE"; break;
case NFS4ERR_FHEXPIRED: return "NFS4ERR_FHEXPIRED"; break;
case NFS4ERR_SHARE_DENIED: return "NFS4ERR_SHARE_DENIED"; break;
case NFS4ERR_WRONGSEC: return "NFS4ERR_WRONGSEC"; break;
case NFS4ERR_CLID_INUSE: return "NFS4ERR_CLID_INUSE"; break;
case NFS4ERR_RESOURCE: return "NFS4ERR_RESOURCE"; break;
case NFS4ERR_MOVED: return "NFS4ERR_MOVED"; break;
case NFS4ERR_NOFILEHANDLE: return "NFS4ERR_NOFILEHANDLE"; break;
case NFS4ERR_MINOR_VERS_MISMATCH: return "NFS4ERR_MINOR_VERS_MISMATCH"; break;
case NFS4ERR_STALE_CLIENTID: return "NFS4ERR_STALE_CLIENTID"; break;
case NFS4ERR_STALE_STATEID: return "NFS4ERR_STALE_STATEID"; break;
case NFS4ERR_OLD_STATEID: return "NFS4ERR_OLD_STATEID"; break;
case NFS4ERR_BAD_STATEID: return "NFS4ERR_BAD_STATEID"; break;
case NFS4ERR_BAD_SEQID: return "NFS4ERR_BAD_SEQID"; break;
case NFS4ERR_NOT_SAME: return "NFS4ERR_NOT_SAME"; break;
case NFS4ERR_LOCK_RANGE: return "NFS4ERR_LOCK_RANGE"; break;
case NFS4ERR_SYMLINK: return "NFS4ERR_SYMLINK"; break;
case NFS4ERR_RESTOREFH: return "NFS4ERR_RESTOREFH"; break;
case NFS4ERR_LEASE_MOVED: return "NFS4ERR_LEASE_MOVED"; break;
case NFS4ERR_ATTRNOTSUPP: return "NFS4ERR_ATTRNOTSUPP"; break;
case NFS4ERR_NO_GRACE: return "NFS4ERR_NO_GRACE"; break;
case NFS4ERR_RECLAIM_BAD: return "NFS4ERR_RECLAIM_BAD"; break;
case NFS4ERR_RECLAIM_CONFLICT: return "NFS4ERR_RECLAIM_CONFLICT"; break;
case NFS4ERR_BADZDR: return "NFS4ERR_BADZDR"; break;
case NFS4ERR_LOCKS_HELD: return "NFS4ERR_LOCKS_HELD"; break;
case NFS4ERR_OPENMODE: return "NFS4ERR_OPENMODE"; break;
case NFS4ERR_BADOWNER: return "NFS4ERR_BADOWNER"; break;
case NFS4ERR_BADCHAR: return "NFS4ERR_BADCHAR"; break;
case NFS4ERR_BADNAME: return "NFS4ERR_BADNAME"; break;
case NFS4ERR_BAD_RANGE: return "NFS4ERR_BAD_RANGE"; break;
case NFS4ERR_LOCK_NOTSUPP: return "NFS4ERR_LOCK_NOTSUPP"; break;
case NFS4ERR_OP_ILLEGAL: return "NFS4ERR_OP_ILLEGAL"; break;
case NFS4ERR_DEADLOCK: return "NFS4ERR_DEADLOCK"; break;
case NFS4ERR_FILE_OPEN: return "NFS4ERR_FILE_OPEN"; break;
case NFS4ERR_ADMIN_REVOKED: return "NFS4ERR_ADMIN_REVOKED"; break;
case NFS4ERR_CB_PATH_DOWN: return "NFS4ERR_CB_PATH_DOWN"; break;
};
return "unknown nfsv4 error";
}
int nfsstat4_to_errno(int error)
{
switch (error) {
case NFS4_OK: return 0;
case NFS4ERR_PERM: return -EPERM;
case NFS4ERR_NOENT: return -ENOENT ;
case NFS4ERR_IO: return -EIO;
case NFS4ERR_NXIO: return -ENXIO;
case NFS4ERR_ACCESS: return -EACCES ;
case NFS4ERR_EXIST: return -EEXIST;
case NFS4ERR_XDEV: return -EXDEV;
case NFS4ERR_NOTDIR: return -ENOTDIR ;
case NFS4ERR_ISDIR: return -EISDIR ;
case NFS4ERR_INVAL: return -EINVAL;
case NFS4ERR_FBIG: return -EFBIG;
case NFS4ERR_NOSPC: return -ENOSPC;
case NFS4ERR_ROFS: return -EROFS;
case NFS4ERR_MLINK: return -EMLINK;
case NFS4ERR_NAMETOOLONG: return -ENAMETOOLONG;
case NFS4ERR_NOTEMPTY: return -ENOTEMPTY;
case NFS4ERR_DQUOT: return -ERANGE;
case NFS4ERR_STALE: return -EIO;
case NFS4ERR_BADHANDLE: return -EINVAL;
case NFS4ERR_BAD_COOKIE: return -EINVAL;
case NFS4ERR_NOTSUPP: return -EINVAL;
case NFS4ERR_TOOSMALL: return -EIO;
case NFS4ERR_SERVERFAULT: return -EIO;
case NFS4ERR_BADTYPE: return -EINVAL;
case NFS4ERR_DELAY: return -EIO;
case NFS4ERR_SAME: return -EIO;
case NFS4ERR_DENIED: return -EIO;
case NFS4ERR_EXPIRED: return -EIO;
case NFS4ERR_LOCKED: return -EIO;
case NFS4ERR_GRACE: return -EIO;
case NFS4ERR_FHEXPIRED: return -EIO;
case NFS4ERR_SHARE_DENIED: return -EIO;
case NFS4ERR_WRONGSEC: return -EIO;
case NFS4ERR_CLID_INUSE: return -EIO;
case NFS4ERR_RESOURCE: return -EIO;
case NFS4ERR_MOVED: return -EIO;
case NFS4ERR_NOFILEHANDLE: return -EIO;
case NFS4ERR_MINOR_VERS_MISMATCH: return -EIO;
case NFS4ERR_STALE_CLIENTID: return -EIO;
case NFS4ERR_STALE_STATEID: return -EIO;
case NFS4ERR_OLD_STATEID: return -EIO;
case NFS4ERR_BAD_STATEID: return -EINVAL;
case NFS4ERR_BAD_SEQID: return -EINVAL;
case NFS4ERR_NOT_SAME: return -EIO;
case NFS4ERR_LOCK_RANGE: return -EIO;
case NFS4ERR_SYMLINK: return -EIO;
case NFS4ERR_RESTOREFH: return -EIO;
case NFS4ERR_ATTRNOTSUPP: return -EINVAL;
case NFS4ERR_NO_GRACE: return -EIO;
case NFS4ERR_RECLAIM_BAD: return -EIO;
case NFS4ERR_RECLAIM_CONFLICT: return -EIO;
case NFS4ERR_BADZDR: return -EINVAL;
case NFS4ERR_LOCKS_HELD: return -EIO;
case NFS4ERR_OPENMODE: return -EIO;
case NFS4ERR_BADOWNER: return -EINVAL;
case NFS4ERR_BADCHAR: return -EINVAL;
case NFS4ERR_BADNAME: return -EINVAL;
case NFS4ERR_BAD_RANGE: return -EINVAL;
case NFS4ERR_LOCK_NOTSUPP: return -EINVAL;
case NFS4ERR_OP_ILLEGAL: return -EIO;
case NFS4ERR_DEADLOCK: return -EIO;
case NFS4ERR_FILE_OPEN: return -EIO;
case NFS4ERR_ADMIN_REVOKED: return -EIO;
case NFS4ERR_CB_PATH_DOWN: return -EIO;
};
return -ERANGE;
}
int rpc_nfs4_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
{
struct rpc_pdu *pdu;
pdu = rpc_allocate_pdu(rpc, NFS4_PROGRAM, NFS_V4, NFSPROC4_NULL, cb, private_data, (zdrproc_t)zdr_void, 0);
if (pdu == NULL) {
rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for NFS4/NULL call");
return -1;
}
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS4/NULL call");
return -2;
}
return 0;
}
int rpc_nfs4_compound_async(struct rpc_context *rpc, rpc_cb cb, struct COMPOUND4args *args, void *private_data)
{
struct rpc_pdu *pdu;
pdu = rpc_allocate_pdu(rpc, NFS4_PROGRAM, NFS_V4, NFSPROC4_COMPOUND, cb, private_data, (zdrproc_t)zdr_COMPOUND4res, sizeof(COMPOUND4res));
if (pdu == NULL) {
rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for NFS4/COMPOUND call");
return -1;
}
if (zdr_COMPOUND4args(&pdu->zdr, args) == 0) {
rpc_set_error(rpc, "ZDR error: Failed to encode COMPOUND4args");
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 NFS4/COMPOUND4 call");
return -3;
}
return 0;
}

1668
nfs4/nfs4.x Normal file

File diff suppressed because it is too large Load Diff

View File

@ -39,7 +39,6 @@ int rpc_nlm4_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/null call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -64,7 +63,6 @@ int rpc_nlm4_test_async(struct rpc_context *rpc, rpc_cb cb, struct NLM4_TESTargs
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/test call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -89,7 +87,6 @@ int rpc_nlm4_lock_async(struct rpc_context *rpc, rpc_cb cb, struct NLM4_LOCKargs
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/lock call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -114,7 +111,6 @@ int rpc_nlm4_cancel_async(struct rpc_context *rpc, rpc_cb cb, struct NLM4_CANCar
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/cancel call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -139,7 +135,6 @@ int rpc_nlm4_unlock_async(struct rpc_context *rpc, rpc_cb cb, struct NLM4_UNLOCK
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/unlock call");
rpc_free_pdu(rpc, pdu);
return -1;
}

View File

@ -39,7 +39,6 @@ int rpc_nsm1_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/null call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -64,7 +63,6 @@ int rpc_nsm1_stat_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_STATargs
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/stat call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -89,7 +87,6 @@ int rpc_nsm1_mon_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_MONargs *
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/mon call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -114,7 +111,6 @@ int rpc_nsm1_unmon_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_UNMONar
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/unmon call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -139,7 +135,6 @@ int rpc_nsm1_unmonall_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_UNMO
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/unmonall call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -158,7 +153,6 @@ int rpc_nsm1_simucrash_async(struct rpc_context *rpc, rpc_cb cb, void *private_d
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/simucrash call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -183,7 +177,6 @@ int rpc_nsm1_notify_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_NOTIFY
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/notify call");
rpc_free_pdu(rpc, pdu);
return -1;
}

View File

@ -22,4 +22,4 @@ compile_rpc:
cat portmap.x | head -29 >libnfs-raw-portmap.h
rpcgen -h portmap.x | sed -e "s/#include <rpc\/rpc.h>/#include <nfsc\/libnfs-zdr.h>/" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/ CLIENT / void /g" -e "s/SVCXPRT /void /g" -e "s/bool_t/uint32_t/g" >> libnfs-raw-portmap.h
cat portmap.x | head -29 >libnfs-raw-portmap.c
rpcgen -c portmap.x | sed -e "s/#include \".*portmap.h\"/#include \"libnfs-zdr.h\"\n#include \"libnfs-raw-portmap.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n buf = NULL;/" -e "s/bool_t/uint32_t/g" >> libnfs-raw-portmap.c
rpcgen -c portmap.x | sed -e "s/#include \".*portmap.h\"/#include \"libnfs-zdr.h\"\n#include \"libnfs-raw-portmap.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;//" -e "s/bool_t/uint32_t/g" -e "s/[ \t]*buf = / int32_t *buf;\n buf = /" >> libnfs-raw-portmap.c

View File

@ -1,3 +1,4 @@
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
/*
Copyright (c) 2014, Ronnie Sahlberg
All rights reserved.
@ -6,7 +7,7 @@ Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
@ -23,10 +24,9 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
/*
* Please do not edit this file.
* It was generated using rpcgen.
@ -38,10 +38,11 @@ either expressed or implied, of the FreeBSD Project.
uint32_t
zdr_pmap2_mapping (ZDR *zdrs, pmap2_mapping *objp)
{
register int32_t *buf;
buf = NULL;
if (zdrs->x_op == ZDR_ENCODE) {
int32_t *buf;
buf = ZDR_INLINE (zdrs, 4 * BYTES_PER_ZDR_UNIT);
if (buf == NULL) {
if (!zdr_u_int (zdrs, &objp->prog))
@ -60,6 +61,7 @@ zdr_pmap2_mapping (ZDR *zdrs, pmap2_mapping *objp)
}
return TRUE;
} else if (zdrs->x_op == ZDR_DECODE) {
int32_t *buf;
buf = ZDR_INLINE (zdrs, 4 * BYTES_PER_ZDR_UNIT);
if (buf == NULL) {
if (!zdr_u_int (zdrs, &objp->prog))
@ -93,10 +95,11 @@ zdr_pmap2_mapping (ZDR *zdrs, pmap2_mapping *objp)
uint32_t
zdr_pmap2_call_args (ZDR *zdrs, pmap2_call_args *objp)
{
register int32_t *buf;
buf = NULL;
if (zdrs->x_op == ZDR_ENCODE) {
int32_t *buf;
buf = ZDR_INLINE (zdrs, 3 * BYTES_PER_ZDR_UNIT);
if (buf == NULL) {
if (!zdr_u_int (zdrs, &objp->prog))
@ -115,6 +118,7 @@ zdr_pmap2_call_args (ZDR *zdrs, pmap2_call_args *objp)
return FALSE;
return TRUE;
} else if (zdrs->x_op == ZDR_DECODE) {
int32_t *buf;
buf = ZDR_INLINE (zdrs, 3 * BYTES_PER_ZDR_UNIT);
if (buf == NULL) {
if (!zdr_u_int (zdrs, &objp->prog))
@ -148,6 +152,8 @@ zdr_pmap2_call_args (ZDR *zdrs, pmap2_call_args *objp)
uint32_t
zdr_pmap2_call_result (ZDR *zdrs, pmap2_call_result *objp)
{
if (!zdr_u_int (zdrs, &objp->port))
return FALSE;
if (!zdr_bytes (zdrs, (char **)&objp->res.res_val, (u_int *) &objp->res.res_len, ~0))
@ -158,6 +164,8 @@ zdr_pmap2_call_result (ZDR *zdrs, pmap2_call_result *objp)
uint32_t
zdr_pmap2_mapping_list (ZDR *zdrs, pmap2_mapping_list *objp)
{
if (!zdr_pmap2_mapping (zdrs, &objp->map))
return FALSE;
if (!zdr_pointer (zdrs, (char **)&objp->next, sizeof (pmap2_mapping_list), (zdrproc_t) zdr_pmap2_mapping_list))
@ -168,6 +176,8 @@ zdr_pmap2_mapping_list (ZDR *zdrs, pmap2_mapping_list *objp)
uint32_t
zdr_pmap2_dump_result (ZDR *zdrs, pmap2_dump_result *objp)
{
if (!zdr_pointer (zdrs, (char **)&objp->list, sizeof (pmap2_mapping_list), (zdrproc_t) zdr_pmap2_mapping_list))
return FALSE;
return TRUE;
@ -176,6 +186,8 @@ zdr_pmap2_dump_result (ZDR *zdrs, pmap2_dump_result *objp)
uint32_t
zdr_pmap3_string_result (ZDR *zdrs, pmap3_string_result *objp)
{
if (!zdr_string (zdrs, &objp->addr, ~0))
return FALSE;
return TRUE;
@ -184,6 +196,8 @@ zdr_pmap3_string_result (ZDR *zdrs, pmap3_string_result *objp)
uint32_t
zdr_pmap3_mapping (ZDR *zdrs, pmap3_mapping *objp)
{
if (!zdr_u_int (zdrs, &objp->prog))
return FALSE;
if (!zdr_u_int (zdrs, &objp->vers))
@ -200,6 +214,8 @@ zdr_pmap3_mapping (ZDR *zdrs, pmap3_mapping *objp)
uint32_t
zdr_pmap3_mapping_list (ZDR *zdrs, pmap3_mapping_list *objp)
{
if (!zdr_pmap3_mapping (zdrs, &objp->map))
return FALSE;
if (!zdr_pointer (zdrs, (char **)&objp->next, sizeof (pmap3_mapping_list), (zdrproc_t) zdr_pmap3_mapping_list))
@ -210,6 +226,8 @@ zdr_pmap3_mapping_list (ZDR *zdrs, pmap3_mapping_list *objp)
uint32_t
zdr_pmap3_dump_result (ZDR *zdrs, pmap3_dump_result *objp)
{
if (!zdr_pointer (zdrs, (char **)&objp->list, sizeof (pmap3_mapping_list), (zdrproc_t) zdr_pmap3_mapping_list))
return FALSE;
return TRUE;
@ -218,10 +236,11 @@ zdr_pmap3_dump_result (ZDR *zdrs, pmap3_dump_result *objp)
uint32_t
zdr_pmap3_call_args (ZDR *zdrs, pmap3_call_args *objp)
{
register int32_t *buf;
buf = NULL;
if (zdrs->x_op == ZDR_ENCODE) {
int32_t *buf;
buf = ZDR_INLINE (zdrs, 3 * BYTES_PER_ZDR_UNIT);
if (buf == NULL) {
if (!zdr_u_int (zdrs, &objp->prog))
@ -240,6 +259,7 @@ zdr_pmap3_call_args (ZDR *zdrs, pmap3_call_args *objp)
return FALSE;
return TRUE;
} else if (zdrs->x_op == ZDR_DECODE) {
int32_t *buf;
buf = ZDR_INLINE (zdrs, 3 * BYTES_PER_ZDR_UNIT);
if (buf == NULL) {
if (!zdr_u_int (zdrs, &objp->prog))
@ -273,6 +293,8 @@ zdr_pmap3_call_args (ZDR *zdrs, pmap3_call_args *objp)
uint32_t
zdr_pmap3_call_result (ZDR *zdrs, pmap3_call_result *objp)
{
if (!zdr_u_int (zdrs, &objp->port))
return FALSE;
if (!zdr_bytes (zdrs, (char **)&objp->res.res_val, (u_int *) &objp->res.res_len, ~0))
@ -283,9 +305,171 @@ zdr_pmap3_call_result (ZDR *zdrs, pmap3_call_result *objp)
uint32_t
zdr_pmap3_netbuf (ZDR *zdrs, pmap3_netbuf *objp)
{
if (!zdr_u_int (zdrs, &objp->maxlen))
return FALSE;
if (!zdr_bytes (zdrs, (char **)&objp->buf.buf_val, (u_int *) &objp->buf.buf_len, ~0))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP2SETargs (ZDR *zdrs, PMAP2SETargs *objp)
{
if (!zdr_pmap2_mapping (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP2UNSETargs (ZDR *zdrs, PMAP2UNSETargs *objp)
{
if (!zdr_pmap2_mapping (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP2GETPORTargs (ZDR *zdrs, PMAP2GETPORTargs *objp)
{
if (!zdr_pmap2_mapping (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP2CALLITargs (ZDR *zdrs, PMAP2CALLITargs *objp)
{
if (!zdr_pmap2_call_args (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP2CALLITres (ZDR *zdrs, PMAP2CALLITres *objp)
{
if (!zdr_pmap2_call_result (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP2DUMPres (ZDR *zdrs, PMAP2DUMPres *objp)
{
if (!zdr_pmap2_dump_result (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP3SETargs (ZDR *zdrs, PMAP3SETargs *objp)
{
if (!zdr_pmap3_mapping (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP3UNSETargs (ZDR *zdrs, PMAP3UNSETargs *objp)
{
if (!zdr_pmap3_mapping (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP3GETADDRargs (ZDR *zdrs, PMAP3GETADDRargs *objp)
{
if (!zdr_pmap3_mapping (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP3GETADDRres (ZDR *zdrs, PMAP3GETADDRres *objp)
{
if (!zdr_pmap3_string_result (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP3DUMPres (ZDR *zdrs, PMAP3DUMPres *objp)
{
if (!zdr_pmap3_dump_result (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP3CALLITargs (ZDR *zdrs, PMAP3CALLITargs *objp)
{
if (!zdr_pmap3_call_result (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP3CALLITres (ZDR *zdrs, PMAP3CALLITres *objp)
{
if (!zdr_pmap3_call_result (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP3UADDR2TADDRres (ZDR *zdrs, PMAP3UADDR2TADDRres *objp)
{
if (!zdr_pmap3_netbuf (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP3TADDR2UADDRargs (ZDR *zdrs, PMAP3TADDR2UADDRargs *objp)
{
if (!zdr_pmap3_netbuf (zdrs, objp))
return FALSE;
return TRUE;
}
uint32_t
zdr_PMAP3TADDR2UADDRres (ZDR *zdrs, PMAP3TADDR2UADDRres *objp)
{
if (!zdr_pmap3_string_result (zdrs, objp))
return FALSE;
return TRUE;
}

View File

@ -1,3 +1,4 @@
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
/*
Copyright (c) 2014, Ronnie Sahlberg
All rights reserved.
@ -26,7 +27,6 @@ The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
/*
* Please do not edit this file.
* It was generated using rpcgen.
@ -137,6 +137,38 @@ struct pmap3_netbuf {
};
typedef struct pmap3_netbuf pmap3_netbuf;
typedef pmap2_mapping PMAP2SETargs;
typedef pmap2_mapping PMAP2UNSETargs;
typedef pmap2_mapping PMAP2GETPORTargs;
typedef pmap2_call_args PMAP2CALLITargs;
typedef pmap2_call_result PMAP2CALLITres;
typedef pmap2_dump_result PMAP2DUMPres;
typedef pmap3_mapping PMAP3SETargs;
typedef pmap3_mapping PMAP3UNSETargs;
typedef pmap3_mapping PMAP3GETADDRargs;
typedef pmap3_string_result PMAP3GETADDRres;
typedef pmap3_dump_result PMAP3DUMPres;
typedef pmap3_call_result PMAP3CALLITargs;
typedef pmap3_call_result PMAP3CALLITres;
typedef pmap3_netbuf PMAP3UADDR2TADDRres;
typedef pmap3_netbuf PMAP3TADDR2UADDRargs;
typedef pmap3_string_result PMAP3TADDR2UADDRres;
#define PMAP_PROGRAM 100000
#define PMAP_V2 2
@ -145,20 +177,20 @@ typedef struct pmap3_netbuf pmap3_netbuf;
extern void * pmap2_null_2(void *, void *);
extern void * pmap2_null_2_svc(void *, struct svc_req *);
#define PMAP2_SET 1
extern uint32_t * pmap2_set_2(pmap2_mapping *, void *);
extern uint32_t * pmap2_set_2_svc(pmap2_mapping *, struct svc_req *);
extern uint32_t * pmap2_set_2(PMAP2SETargs *, void *);
extern uint32_t * pmap2_set_2_svc(PMAP2SETargs *, struct svc_req *);
#define PMAP2_UNSET 2
extern uint32_t * pmap2_unset_2(pmap2_mapping *, void *);
extern uint32_t * pmap2_unset_2_svc(pmap2_mapping *, struct svc_req *);
extern uint32_t * pmap2_unset_2(PMAP2UNSETargs *, void *);
extern uint32_t * pmap2_unset_2_svc(PMAP2UNSETargs *, struct svc_req *);
#define PMAP2_GETPORT 3
extern u_int * pmap2_getport_2(pmap2_mapping *, void *);
extern u_int * pmap2_getport_2_svc(pmap2_mapping *, struct svc_req *);
extern uint32_t * pmap2_getport_2(PMAP2GETPORTargs *, void *);
extern uint32_t * pmap2_getport_2_svc(PMAP2GETPORTargs *, struct svc_req *);
#define PMAP2_DUMP 4
extern pmap2_dump_result * pmap2_dump_2(void *, void *);
extern pmap2_dump_result * pmap2_dump_2_svc(void *, struct svc_req *);
extern PMAP2DUMPres * pmap2_dump_2(void *, void *);
extern PMAP2DUMPres * pmap2_dump_2_svc(void *, struct svc_req *);
#define PMAP2_CALLIT 5
extern pmap2_call_result * pmap2_callit_2(pmap2_call_args *, void *);
extern pmap2_call_result * pmap2_callit_2_svc(pmap2_call_args *, struct svc_req *);
extern PMAP2CALLITres * pmap2_callit_2(PMAP2CALLITargs *, void *);
extern PMAP2CALLITres * pmap2_callit_2_svc(PMAP2CALLITargs *, struct svc_req *);
extern int pmap_program_2_freeresult (void *, zdrproc_t, caddr_t);
#else /* K&R C */
@ -172,14 +204,14 @@ extern uint32_t * pmap2_set_2_svc();
extern uint32_t * pmap2_unset_2();
extern uint32_t * pmap2_unset_2_svc();
#define PMAP2_GETPORT 3
extern u_int * pmap2_getport_2();
extern u_int * pmap2_getport_2_svc();
extern uint32_t * pmap2_getport_2();
extern uint32_t * pmap2_getport_2_svc();
#define PMAP2_DUMP 4
extern pmap2_dump_result * pmap2_dump_2();
extern pmap2_dump_result * pmap2_dump_2_svc();
extern PMAP2DUMPres * pmap2_dump_2();
extern PMAP2DUMPres * pmap2_dump_2_svc();
#define PMAP2_CALLIT 5
extern pmap2_call_result * pmap2_callit_2();
extern pmap2_call_result * pmap2_callit_2_svc();
extern PMAP2CALLITres * pmap2_callit_2();
extern PMAP2CALLITres * pmap2_callit_2_svc();
extern int pmap_program_2_freeresult ();
#endif /* K&R C */
#define PMAP_V3 3
@ -189,29 +221,29 @@ extern int pmap_program_2_freeresult ();
extern void * pmap3_null_3(void *, void *);
extern void * pmap3_null_3_svc(void *, struct svc_req *);
#define PMAP3_SET 1
extern uint32_t * pmap3_set_3(pmap3_mapping *, void *);
extern uint32_t * pmap3_set_3_svc(pmap3_mapping *, struct svc_req *);
extern uint32_t * pmap3_set_3(PMAP3SETargs *, void *);
extern uint32_t * pmap3_set_3_svc(PMAP3SETargs *, struct svc_req *);
#define PMAP3_UNSET 2
extern uint32_t * pmap3_unset_3(pmap3_mapping *, void *);
extern uint32_t * pmap3_unset_3_svc(pmap3_mapping *, struct svc_req *);
extern uint32_t * pmap3_unset_3(PMAP3UNSETargs *, void *);
extern uint32_t * pmap3_unset_3_svc(PMAP3UNSETargs *, struct svc_req *);
#define PMAP3_GETADDR 3
extern pmap3_string_result * pmap3_getaddr_3(pmap3_mapping *, void *);
extern pmap3_string_result * pmap3_getaddr_3_svc(pmap3_mapping *, struct svc_req *);
extern PMAP3GETADDRres * pmap3_getaddr_3(PMAP3GETADDRargs *, void *);
extern PMAP3GETADDRres * pmap3_getaddr_3_svc(PMAP3GETADDRargs *, struct svc_req *);
#define PMAP3_DUMP 4
extern pmap3_dump_result * pmap3_dump_3(void *, void *);
extern pmap3_dump_result * pmap3_dump_3_svc(void *, struct svc_req *);
extern PMAP3DUMPres * pmap3_dump_3(void *, void *);
extern PMAP3DUMPres * pmap3_dump_3_svc(void *, struct svc_req *);
#define PMAP3_CALLIT 5
extern pmap3_call_result * pmap3_callit_3(pmap3_call_args *, void *);
extern pmap3_call_result * pmap3_callit_3_svc(pmap3_call_args *, struct svc_req *);
extern PMAP3CALLITres * pmap3_callit_3(PMAP3CALLITargs *, void *);
extern PMAP3CALLITres * pmap3_callit_3_svc(PMAP3CALLITargs *, struct svc_req *);
#define PMAP3_GETTIME 6
extern u_int * pmap3_gettime_3(void *, void *);
extern u_int * pmap3_gettime_3_svc(void *, struct svc_req *);
extern uint32_t * pmap3_gettime_3(void *, void *);
extern uint32_t * pmap3_gettime_3_svc(void *, struct svc_req *);
#define PMAP3_UADDR2TADDR 7
extern pmap3_netbuf * pmap3_uaddr2taddr_3(char **, void *);
extern pmap3_netbuf * pmap3_uaddr2taddr_3_svc(char **, struct svc_req *);
extern PMAP3UADDR2TADDRres * pmap3_uaddr2taddr_3(char **, void *);
extern PMAP3UADDR2TADDRres * pmap3_uaddr2taddr_3_svc(char **, struct svc_req *);
#define PMAP3_TADDR2UADDR 8
extern struct pmap3_string_result * pmap3_taddr2uaddr_3(pmap3_netbuf *, void *);
extern struct pmap3_string_result * pmap3_taddr2uaddr_3_svc(pmap3_netbuf *, struct svc_req *);
extern PMAP3TADDR2UADDRres * pmap3_taddr2uaddr_3(PMAP3TADDR2UADDRargs *, void *);
extern PMAP3TADDR2UADDRres * pmap3_taddr2uaddr_3_svc(PMAP3TADDR2UADDRargs *, struct svc_req *);
extern int pmap_program_3_freeresult (void *, zdrproc_t, caddr_t);
#else /* K&R C */
@ -225,23 +257,23 @@ extern uint32_t * pmap3_set_3_svc();
extern uint32_t * pmap3_unset_3();
extern uint32_t * pmap3_unset_3_svc();
#define PMAP3_GETADDR 3
extern pmap3_string_result * pmap3_getaddr_3();
extern pmap3_string_result * pmap3_getaddr_3_svc();
extern PMAP3GETADDRres * pmap3_getaddr_3();
extern PMAP3GETADDRres * pmap3_getaddr_3_svc();
#define PMAP3_DUMP 4
extern pmap3_dump_result * pmap3_dump_3();
extern pmap3_dump_result * pmap3_dump_3_svc();
extern PMAP3DUMPres * pmap3_dump_3();
extern PMAP3DUMPres * pmap3_dump_3_svc();
#define PMAP3_CALLIT 5
extern pmap3_call_result * pmap3_callit_3();
extern pmap3_call_result * pmap3_callit_3_svc();
extern PMAP3CALLITres * pmap3_callit_3();
extern PMAP3CALLITres * pmap3_callit_3_svc();
#define PMAP3_GETTIME 6
extern u_int * pmap3_gettime_3();
extern u_int * pmap3_gettime_3_svc();
extern uint32_t * pmap3_gettime_3();
extern uint32_t * pmap3_gettime_3_svc();
#define PMAP3_UADDR2TADDR 7
extern pmap3_netbuf * pmap3_uaddr2taddr_3();
extern pmap3_netbuf * pmap3_uaddr2taddr_3_svc();
extern PMAP3UADDR2TADDRres * pmap3_uaddr2taddr_3();
extern PMAP3UADDR2TADDRres * pmap3_uaddr2taddr_3_svc();
#define PMAP3_TADDR2UADDR 8
extern struct pmap3_string_result * pmap3_taddr2uaddr_3();
extern struct pmap3_string_result * pmap3_taddr2uaddr_3_svc();
extern PMAP3TADDR2UADDRres * pmap3_taddr2uaddr_3();
extern PMAP3TADDR2UADDRres * pmap3_taddr2uaddr_3_svc();
extern int pmap_program_3_freeresult ();
#endif /* K&R C */
@ -260,6 +292,22 @@ extern uint32_t zdr_pmap3_dump_result (ZDR *, pmap3_dump_result*);
extern uint32_t zdr_pmap3_call_args (ZDR *, pmap3_call_args*);
extern uint32_t zdr_pmap3_call_result (ZDR *, pmap3_call_result*);
extern uint32_t zdr_pmap3_netbuf (ZDR *, pmap3_netbuf*);
extern uint32_t zdr_PMAP2SETargs (ZDR *, PMAP2SETargs*);
extern uint32_t zdr_PMAP2UNSETargs (ZDR *, PMAP2UNSETargs*);
extern uint32_t zdr_PMAP2GETPORTargs (ZDR *, PMAP2GETPORTargs*);
extern uint32_t zdr_PMAP2CALLITargs (ZDR *, PMAP2CALLITargs*);
extern uint32_t zdr_PMAP2CALLITres (ZDR *, PMAP2CALLITres*);
extern uint32_t zdr_PMAP2DUMPres (ZDR *, PMAP2DUMPres*);
extern uint32_t zdr_PMAP3SETargs (ZDR *, PMAP3SETargs*);
extern uint32_t zdr_PMAP3UNSETargs (ZDR *, PMAP3UNSETargs*);
extern uint32_t zdr_PMAP3GETADDRargs (ZDR *, PMAP3GETADDRargs*);
extern uint32_t zdr_PMAP3GETADDRres (ZDR *, PMAP3GETADDRres*);
extern uint32_t zdr_PMAP3DUMPres (ZDR *, PMAP3DUMPres*);
extern uint32_t zdr_PMAP3CALLITargs (ZDR *, PMAP3CALLITargs*);
extern uint32_t zdr_PMAP3CALLITres (ZDR *, PMAP3CALLITres*);
extern uint32_t zdr_PMAP3UADDR2TADDRres (ZDR *, PMAP3UADDR2TADDRres*);
extern uint32_t zdr_PMAP3TADDR2UADDRargs (ZDR *, PMAP3TADDR2UADDRargs*);
extern uint32_t zdr_PMAP3TADDR2UADDRres (ZDR *, PMAP3TADDR2UADDRres*);
#else /* K&R C */
extern uint32_t zdr_pmap2_mapping ();
@ -274,6 +322,22 @@ extern uint32_t zdr_pmap3_dump_result ();
extern uint32_t zdr_pmap3_call_args ();
extern uint32_t zdr_pmap3_call_result ();
extern uint32_t zdr_pmap3_netbuf ();
extern uint32_t zdr_PMAP2SETargs ();
extern uint32_t zdr_PMAP2UNSETargs ();
extern uint32_t zdr_PMAP2GETPORTargs ();
extern uint32_t zdr_PMAP2CALLITargs ();
extern uint32_t zdr_PMAP2CALLITres ();
extern uint32_t zdr_PMAP2DUMPres ();
extern uint32_t zdr_PMAP3SETargs ();
extern uint32_t zdr_PMAP3UNSETargs ();
extern uint32_t zdr_PMAP3GETADDRargs ();
extern uint32_t zdr_PMAP3GETADDRres ();
extern uint32_t zdr_PMAP3DUMPres ();
extern uint32_t zdr_PMAP3CALLITargs ();
extern uint32_t zdr_PMAP3CALLITres ();
extern uint32_t zdr_PMAP3UADDR2TADDRres ();
extern uint32_t zdr_PMAP3TADDR2UADDRargs ();
extern uint32_t zdr_PMAP3TADDR2UADDRres ();
#endif /* K&R C */

View File

@ -40,7 +40,6 @@ int rpc_pmap2_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for PORTMAP2/NULL call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -70,7 +69,6 @@ int rpc_pmap2_getport_async(struct rpc_context *rpc, int program, int version, i
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue PORTMAP2/GETPORT pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -100,7 +98,6 @@ int rpc_pmap2_set_async(struct rpc_context *rpc, int program, int version, int p
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue PORTMAP2/SET pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -130,7 +127,6 @@ int rpc_pmap2_unset_async(struct rpc_context *rpc, int program, int version, int
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue PORTMAP2/UNSET pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -149,7 +145,6 @@ int rpc_pmap2_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue PORTMAP2/DUMP pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -202,7 +197,6 @@ int rpc_pmap3_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for PORTMAP3/NULL call");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -227,7 +221,6 @@ int rpc_pmap3_set_async(struct rpc_context *rpc, struct pmap3_mapping *map, rpc_
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue PORTMAP3/SET pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -252,7 +245,6 @@ int rpc_pmap3_unset_async(struct rpc_context *rpc, struct pmap3_mapping *map, rp
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue PORTMAP3/UNSET pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -277,7 +269,6 @@ int rpc_pmap3_getaddr_async(struct rpc_context *rpc, struct pmap3_mapping *map,
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue PORTMAP3/GETADDR pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -296,7 +287,6 @@ int rpc_pmap3_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue PORTMAP3/DUMP pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}
@ -315,7 +305,6 @@ int rpc_pmap3_gettime_async(struct rpc_context *rpc, rpc_cb cb, void *private_da
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Failed to queue PORTMAP3/GETTIME pdu");
rpc_free_pdu(rpc, pdu);
return -1;
}

View File

@ -1,3 +1,4 @@
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
/*
Copyright (c) 2014, Ronnie Sahlberg
All rights reserved.
@ -99,53 +100,71 @@ struct pmap3_netbuf {
opaque buf<>;
};
typedef pmap2_mapping PMAP2SETargs;
typedef pmap2_mapping PMAP2UNSETargs;
typedef pmap2_mapping PMAP2GETPORTargs;
typedef pmap2_call_args PMAP2CALLITargs;
typedef pmap2_call_result PMAP2CALLITres;
typedef pmap2_dump_result PMAP2DUMPres;
typedef pmap3_mapping PMAP3SETargs;
typedef pmap3_mapping PMAP3UNSETargs;
typedef pmap3_mapping PMAP3GETADDRargs;
typedef pmap3_string_result PMAP3GETADDRres;
typedef pmap3_dump_result PMAP3DUMPres;
typedef pmap3_call_result PMAP3CALLITargs;
typedef pmap3_call_result PMAP3CALLITres;
typedef pmap3_netbuf PMAP3UADDR2TADDRres;
typedef pmap3_netbuf PMAP3TADDR2UADDRargs;
typedef pmap3_string_result PMAP3TADDR2UADDRres;
program PMAP_PROGRAM {
version PMAP_V2 {
void
PMAP2_NULL(void) = 0;
bool
PMAP2_SET(pmap2_mapping) = 1;
uint32_t
PMAP2_SET(PMAP2SETargs) = 1;
bool
PMAP2_UNSET(pmap2_mapping) = 2;
uint32_t
PMAP2_UNSET(PMAP2UNSETargs) = 2;
unsigned int
PMAP2_GETPORT(pmap2_mapping) = 3;
uint32_t
PMAP2_GETPORT(PMAP2GETPORTargs) = 3;
pmap2_dump_result
PMAP2DUMPres
PMAP2_DUMP(void) = 4;
pmap2_call_result
PMAP2_CALLIT(pmap2_call_args) = 5;
PMAP2CALLITres
PMAP2_CALLIT(PMAP2CALLITargs) = 5;
} = 2;
version PMAP_V3 {
void
PMAP3_NULL(void) = 0;
bool
PMAP3_SET(pmap3_mapping) = 1;
uint32_t
PMAP3_SET(PMAP3SETargs) = 1;
bool
PMAP3_UNSET(pmap3_mapping) = 2;
uint32_t
PMAP3_UNSET(PMAP3UNSETargs) = 2;
pmap3_string_result
PMAP3_GETADDR(pmap3_mapping) = 3;
PMAP3GETADDRres
PMAP3_GETADDR(PMAP3GETADDRargs) = 3;
pmap3_dump_result
PMAP3DUMPres
PMAP3_DUMP(void) = 4;
pmap3_call_result
PMAP3_CALLIT(pmap3_call_args) = 5;
PMAP3CALLITres
PMAP3_CALLIT(PMAP3CALLITargs) = 5;
unsigned int
uint32_t
PMAP3_GETTIME(void) = 6;
pmap3_netbuf
PMAP3UADDR2TADDRres
PMAP3_UADDR2TADDR(string) = 7;
struct pmap3_string_result
PMAP3_TADDR2UADDR(pmap3_netbuf) = 8;
PMAP3TADDR2UADDRres
PMAP3_TADDR2UADDR(PMAP3TADDR2UADDRargs) = 8;
} = 3;
} = 100000;

View File

@ -62,7 +62,6 @@ int rpc_rquota1_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_dat
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota1/null call");
rpc_free_pdu(rpc, pdu);
return -2;
}
@ -91,7 +90,6 @@ int rpc_rquota1_getquota_async(struct rpc_context *rpc, rpc_cb cb, char *export,
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota1/getquota call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -120,7 +118,6 @@ int rpc_rquota1_getactivequota_async(struct rpc_context *rpc, rpc_cb cb, char *e
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota1/getactivequota call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -140,7 +137,6 @@ int rpc_rquota2_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_dat
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota2/null call");
rpc_free_pdu(rpc, pdu);
return -2;
}
@ -170,7 +166,6 @@ int rpc_rquota2_getquota_async(struct rpc_context *rpc, rpc_cb cb, char *export,
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota2/getquota call");
rpc_free_pdu(rpc, pdu);
return -3;
}
@ -200,7 +195,6 @@ int rpc_rquota2_getactivequota_async(struct rpc_context *rpc, rpc_cb cb, char *e
if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota2/getactivequota call");
rpc_free_pdu(rpc, pdu);
return -3;
}

View File

@ -89,7 +89,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_U_=;_USE_32BIT_TIME_T;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\nfs4;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
@ -112,7 +112,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_U_=;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\nfs4;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
@ -137,7 +137,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_U_=;_USE_32BIT_TIME_T;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\nfs4;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
@ -162,7 +162,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_U_=;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\nfs4;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
@ -192,6 +192,8 @@
<ClCompile Include="..\..\nfs\libnfs-raw-nfs.c" />
<ClCompile Include="..\..\nfs\nfs.c" />
<ClCompile Include="..\..\nfs\nfsacl.c" />
<ClCompile Include="..\..\nfs4\libnfs-raw-nfs4.c" />
<ClCompile Include="..\..\nfs4\nfs4.c" />
<ClCompile Include="..\..\nlm\libnfs-raw-nlm.c" />
<ClCompile Include="..\..\nlm\nlm.c" />
<ClCompile Include="..\..\nsm\libnfs-raw-nsm.c" />
@ -206,6 +208,7 @@
<ClInclude Include="..\..\include\nfsc\libnfs-zdr.h" />
<ClInclude Include="..\..\mount\libnfs-raw-mount.h" />
<ClInclude Include="..\..\nfs\libnfs-raw-nfs.h" />
<ClInclude Include="..\..\nfs4\libnfs-raw-nfs4.h" />
<ClInclude Include="..\..\nlm\libnfs-raw-nlm.h" />
<ClInclude Include="..\..\nsm\libnfs-raw-nsm.h" />
<ClInclude Include="..\..\portmap\libnfs-raw-portmap.h" />

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
@ -20,6 +20,12 @@
<ClCompile Include="..\..\nfs\nfsacl.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\nfs4\libnfs-raw-nfs4.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\nfs4\nfs4.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\rquota\libnfs-raw-rquota.c">
<Filter>Source Files</Filter>
</ClCompile>
@ -76,6 +82,9 @@
<ClInclude Include="..\..\nfs\libnfs-raw-nfs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\nfs4\libnfs-raw-nfs4.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\rquota\libnfs-raw-rquota.h">
<Filter>Header Files</Filter>
</ClInclude>

View File

@ -64,11 +64,11 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>..\libnfs\Release;..\..\bin;$(LibraryPath)</LibraryPath>
<LibraryPath>..\libnfs\Debug;..\..\bin;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>..\libnfs\Release;..\..\bin;$(LibraryPath)</LibraryPath>
<LibraryPath>..\libnfs\Debug;..\..\bin;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>

View File

@ -64,11 +64,11 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>..\libnfs\Release;..\..\bin;$(LibraryPath)</LibraryPath>
<LibraryPath>..\libnfs\Debug;..\..\bin;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>..\libnfs\Release;..\..\bin;$(LibraryPath)</LibraryPath>
<LibraryPath>..\libnfs\Debug;..\..\bin;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>

22
win32/win32_compat.h Normal file → Executable file
View File

@ -34,13 +34,15 @@ THE SOFTWARE.
#include <sys/stat.h>
#include <time.h>
typedef int uid_t;
typedef int gid_t;
typedef unsigned int uid_t;
typedef unsigned int gid_t;
typedef int socklen_t;
#ifndef S_IRUSR
#define S_IRUSR 0000400
#define S_IWUSR 0000200
#define S_IXUSR 0000100
#endif
#define S_IRWXG 0000070 /* RWX mask for group */
#define S_IRGRP 0000040
#define S_IWGRP 0000020
@ -77,8 +79,17 @@ typedef int socklen_t;
#define minor(a) 0
#endif
#ifndef O_NONBLOCK
#define O_NONBLOCK 0x40000000
#endif
#ifndef O_SYNC
#define O_SYNC 0
#endif
#ifndef O_NOFOLLOW
#define O_NOFOLLOW 00400000
#endif
#define MSG_DONTWAIT 0
#define ssize_t SSIZE_T
@ -102,11 +113,18 @@ struct pollfd {
#define close closesocket
#define ioctl ioctlsocket
#ifndef ESTALE
#define ESTALE 116
#endif
/* Wrapper macros to call misc. functions win32 is missing */
#define poll(x, y, z) win32_poll(x, y, z)
#define snprintf sprintf_s
#define inet_pton(x,y,z) win32_inet_pton(x,y,z)
#define open(x, y, z) _open(x, y, z)
#ifndef lseek
#define lseek(x, y, z) _lseek(x, y, z)
#endif
#define read(x, y, z) _read(x, y, z)
#define write(x, y, z) _write(x, y, z)
int getpid(void);