From: Jérôme Benoit Date: Mon, 1 Dec 2014 18:01:56 +0000 (+0100) Subject: Merge tag 'libnfs-1.9.6' of https://github.com/sahlberg/libnfs into upstream X-Git-Tag: upstream/1.9.6 X-Git-Url: https://git.piment-noir.org/?p=deb_libnfs.git;a=commitdiff_plain;h=00e29b2c0b8b0e7885e724f732c0d259c1f8419f;hp=c76fd7199ffdf118c43357af72a29f56f245db04 Merge tag 'libnfs-1.9.6' of https://github.com/sahlberg/libnfs into upstream Tag for 1.9.6 Signed-off-by: Jérôme Benoit Conflicts: README configure.ac examples/fuse_nfs.c include/nfsc/libnfs-zdr.h include/nfsc/libnfs.h lib/Makefile.am lib/libnfs-sync.c lib/libnfs-zdr.c lib/libnfs.c lib/socket.c nfs/Makefile.am nfs/libnfs-raw-nfs.c nfs/libnfs-raw-nfs.h nfs/nfs.c nfs/nfs.x nlm/libnfs-raw-nlm.c nlm/libnfs-raw-nlm.h nlm/nlm.x packaging/RPM/libnfs.spec.in --- diff --git a/README b/README index b0655ea..701a781 100644 --- a/README +++ b/README @@ -115,7 +115,8 @@ patches to make it better instead. RELEASE TARBALLS ================ -Release tarballs are available at https://sites.google.com/site/libnfstarballs/li +Release tarballs are available at +https://sites.google.com/site/libnfstarballs/li diff --git a/configure.ac b/configure.ac index b84a8c5..2e64295 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.50) -AC_INIT([libnfs], [1.9.5], [ronniesahlberg@gmail.com]) +AC_INIT([libnfs], [1.9.6], [ronniesahlberg@gmail.com]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign]) AC_CANONICAL_HOST @@ -72,10 +72,8 @@ case $host in *solaris*) AC_CHECK_HEADERS([sys/filio.h]) AC_CHECK_HEADERS([sys/sockio.h]) - if test x$ENABLE_EXAMPLES = xyes; then - 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])]) - fi + 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])]) ;; *) ;; @@ -153,6 +151,11 @@ AC_CHECK_MEMBER([struct sockaddr_storage.ss_family], #include ]) +AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec]) + +# check where makedev is defined +AC_HEADER_MAJOR + #output AC_CONFIG_FILES([Makefile] [doc/Makefile] diff --git a/examples/fuse_nfs.c b/examples/fuse_nfs.c index 261a6aa..28449ee 100644 --- a/examples/fuse_nfs.c +++ b/examples/fuse_nfs.c @@ -191,7 +191,7 @@ static struct fuse_operations nfs_oper = { void print_usage(char *name) { - printf("Usage: %s [-?|--help] [-n|--nfs-share=nfs-url] mountpoint\n", + printf("Usage: %s [-?|--help] [-n|--nfs-share=nfs-url] [-m|--mountpoint=mountpoint]\n", name); exit(0); } @@ -248,11 +248,13 @@ int main(int argc, char *argv[]) if (url == NULL) { fprintf(stderr, "-n was not specified.\n"); + print_usage(argv[0]); ret = 10; goto finished; } if (mnt == NULL) { fprintf(stderr, "-m was not specified.\n"); + print_usage(argv[0]); ret = 10; goto finished; } diff --git a/include/nfsc/libnfs-zdr.h b/include/nfsc/libnfs-zdr.h index 6b2ea91..aa9f1d8 100644 --- a/include/nfsc/libnfs-zdr.h +++ b/include/nfsc/libnfs-zdr.h @@ -230,11 +230,11 @@ bool_t libnfs_zdr_u_int(ZDR *zdrs, uint32_t *u); #define zdr_int libnfs_zdr_int bool_t libnfs_zdr_int(ZDR *zdrs, int32_t *i); -#define zdr_u_quad_t libnfs_zdr_u_quad_t -bool_t libnfs_zdr_u_quad_t(ZDR *zdrs, uint64_t *u); +#define zdr_uint64_t libnfs_zdr_uint64_t +bool_t libnfs_zdr_uint64_t(ZDR *zdrs, uint64_t *u); -#define zdr_quad_t libnfs_zdr_quad_t -bool_t libnfs_zdr_quad_t(ZDR *zdrs, int64_t *i); +#define zdr_int64_t libnfs_zdr_int64_t +bool_t libnfs_zdr_int64_t(ZDR *zdrs, int64_t *i); #define zdr_enum libnfs_zdr_enum bool_t libnfs_zdr_enum(ZDR *zdrs, enum_t *e); diff --git a/include/nfsc/libnfs.h b/include/nfsc/libnfs.h index dfa2185..6707232 100644 --- a/include/nfsc/libnfs.h +++ b/include/nfsc/libnfs.h @@ -270,6 +270,10 @@ struct nfs_stat_64 { uint64_t nfs_atime; uint64_t nfs_mtime; uint64_t nfs_ctime; + uint64_t nfs_atime_nsec; + uint64_t nfs_mtime_nsec; + uint64_t nfs_ctime_nsec; + uint64_t nfs_used; }; /* @@ -293,6 +297,35 @@ EXTERN int nfs_stat64_async(struct nfs_context *nfs, const char *path, nfs_cb cb */ EXTERN int nfs_stat64(struct nfs_context *nfs, const char *path, struct nfs_stat_64 *st); +/* + * Async stat() + * + * Like stat except if the destination is a symbolic link, it acts on the + * symbolic link itself. + * + * Function returns + * 0 : The operation was initiated. Once the operation finishes, the callback will be invoked. + * <0 : An error occured when trying to set up the operation. The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * 0 : Success. + * data is struct nfs_stat_64 * + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs_lstat64_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data); +/* + * Sync stat() + * + * Like stat except if the destination is a symbolic link, it acts on the + * symbolic link itself. + * + * Function returns + * 0 : The operation was successfull. + * -errno : The command failed. + */ +EXTERN int nfs_lstat64(struct nfs_context *nfs, const char *path, struct nfs_stat_64 *st); + /* * FSTAT() */ @@ -308,6 +341,7 @@ EXTERN int nfs_stat64(struct nfs_context *nfs, const char *path, struct nfs_stat * -errno : An error occured. * data is the error string. */ +/* This function is deprecated. Use nfs_fstat64_async() instead */ EXTERN int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data); /* * Sync fstat(nfsfh *) @@ -321,6 +355,35 @@ EXTERN int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct __stat EXTERN int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat *st); #endif +/* nfs_fstat64 + * 64 bit version of fstat. All fields are always 64bit. + * Use these functions instead of nfs_fstat[_async](), especially if you + * have weird stat structures. + */ +/* + * FSTAT() + */ +/* + * Async fstat(nfsfh *) + * Function returns + * 0 : The operation was initiated. Once the operation finishes, the callback will be invoked. + * <0 : An error occured when trying to set up the operation. The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * 0 : Success. + * data is struct stat * + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs_fstat64_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data); +/* + * Sync fstat(nfsfh *) + * Function returns + * 0 : The operation was successfull. + * -errno : The command failed. + */ +EXTERN int nfs_fstat64(struct nfs_context *nfs, struct nfsfh *nfsfh, struct nfs_stat_64 *st); + /* @@ -330,7 +393,7 @@ EXTERN int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat * * Async open() * * mode is a combination of the flags : - * O_RDOLNY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND + * O_RDOLNY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND, O_TRUNC * * Function returns * 0 : The operation was initiated. Once the operation finishes, the callback will be invoked. @@ -341,6 +404,7 @@ EXTERN int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat * * O_RDONLY * O_WRONLY * O_RDWR + * O_SYNC * O_TRUNC (Only valid with O_RDWR or O_WRONLY. Ignored otherwise.) * * When the callback is invoked, status indicates the result: @@ -682,6 +746,34 @@ EXTERN int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, */ EXTERN int nfs_creat(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh); +/* + * Async create() + * + * Same as nfs_creat_async but allows passing flags: + * O_APPEND + * O_SYNC + * O_EXCL + * O_TRUNC + * + * Function returns + * 0 : The operation was initiated. Once the operation finishes, the callback will be invoked. + * <0 : An error occured when trying to set up the operation. The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * 0 : Success. + * data is a struct *nfsfh; + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs_create_async(struct nfs_context *nfs, const char *path, int flags, int mode, nfs_cb cb, void *private_data); +/* + * Sync create() + * Function returns + * 0 : Success + * -errno : An error occured. + */ +EXTERN int nfs_create(struct nfs_context *nfs, const char *path, int flags, int mode, struct nfsfh **nfsfh); + /* * MKNOD() @@ -786,6 +878,14 @@ struct nfsdirent { uint32_t uid; uint32_t gid; uint32_t nlink; + uint64_t dev; + uint64_t rdev; + uint64_t blksize; + uint64_t blocks; + uint64_t used; + uint32_t atime_nsec; + uint32_t mtime_nsec; + uint32_t ctime_nsec; }; /* * nfs_readdir() never blocks, so no special sync/async versions are available @@ -924,6 +1024,34 @@ EXTERN int nfs_chmod_async(struct nfs_context *nfs, const char *path, int mode, * -errno : The command failed. */ EXTERN int nfs_chmod(struct nfs_context *nfs, const char *path, int mode); +/* + * Async chmod() + * + * Like chmod except if the destination is a symbolic link, it acts on the + * symbolic link itself. + * + * Function returns + * 0 : The operation was initiated. Once the operation finishes, the callback will be invoked. + * <0 : An error occured when trying to set up the operation. The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * 0 : Success. + * data is NULL + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs_lchmod_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data); +/* + * Sync chmod() + * + * Like chmod except if the destination is a symbolic link, it acts on the + * symbolic link itself. + * + * Function returns + * 0 : The operation was successfull. + * -errno : The command failed. + */ +EXTERN int nfs_lchmod(struct nfs_context *nfs, const char *path, int mode); @@ -976,6 +1104,34 @@ EXTERN int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, i * -errno : The command failed. */ EXTERN int nfs_chown(struct nfs_context *nfs, const char *path, int uid, int gid); +/* + * Async chown() + * + * Like chown except if the destination is a symbolic link, it acts on the + * symbolic link itself. + * + * Function returns + * 0 : The operation was initiated. Once the operation finishes, the callback will be invoked. + * <0 : An error occured when trying to set up the operation. The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * 0 : Success. + * data is NULL + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs_lchown_async(struct nfs_context *nfs, const char *path, int uid, int gid, nfs_cb cb, void *private_data); +/* + * Sync chown() + * + * Like chown except if the destination is a symbolic link, it acts on the + * symbolic link itself. + * + * Function returns + * 0 : The operation was successfull. + * -errno : The command failed. + */ +EXTERN int nfs_lchown(struct nfs_context *nfs, const char *path, int uid, int gid); @@ -1029,6 +1185,34 @@ EXTERN int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct ti * -errno : The command failed. */ EXTERN int nfs_utimes(struct nfs_context *nfs, const char *path, struct timeval *times); +/* + * Async utimes() + * + * Like utimes except if the destination is a symbolic link, it acts on the + * symbolic link itself. + * + * Function returns + * 0 : The operation was initiated. Once the operation finishes, the callback will be invoked. + * <0 : An error occured when trying to set up the operation. The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * 0 : Success. + * data is NULL + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs_lutimes_async(struct nfs_context *nfs, const char *path, struct timeval *times, nfs_cb cb, void *private_data); +/* + * Sync utimes() + * + * Like utimes except if the destination is a symbolic link, it acts on the + * symbolic link itself. + * + * Function returns + * 0 : The operation was successfull. + * -errno : The command failed. + */ +EXTERN int nfs_lutimes(struct nfs_context *nfs, const char *path, struct timeval *times); /* @@ -1086,6 +1270,36 @@ EXTERN int nfs_access(struct nfs_context *nfs, const char *path, int mode); + +/* + * ACCESS2() + */ +/* + * Async access2() + * 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 : A mask of R_OK, W_OK and X_OK indicating which permissions are + * available. + * data is NULL + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs_access2_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data); +/* + * Sync access() + * Function returns + * >= 0 : A mask of R_OK, W_OK and X_OK indicating which permissions are + * available. + * -errno : The command failed. + */ +EXTERN int nfs_access2(struct nfs_context *nfs, const char *path); + + + + /* * SYMLINK() */ diff --git a/lib/Makefile.am b/lib/Makefile.am index 2f12325..bbc29d2 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -18,9 +18,9 @@ libnfs_la_SOURCES = \ pdu.c \ socket.c -SOCURRENT=6 +SOCURRENT=7 SOREVISION=0 -SOAGE=2 +SOAGE=3 libnfs_la_LDFLAGS = -version-info $(SOCURRENT):$(SOREVISION):$(SOAGE) libnfs_la_LIBADD = \ ../mount/libmount.la \ diff --git a/lib/libnfs-sync.c b/lib/libnfs-sync.c index d4a5451..59911fc 100644 --- a/lib/libnfs-sync.c +++ b/lib/libnfs-sync.c @@ -86,6 +86,10 @@ #include #endif +#ifdef HAVE_SYS_TIME_H +#include +#endif + #include "libnfs-zdr.h" #include "libnfs.h" #include "libnfs-raw.h" @@ -268,6 +272,23 @@ int nfs_stat64(struct nfs_context *nfs, const char *path, struct nfs_stat_64 *st return cb_data.status; } +int nfs_lstat64(struct nfs_context *nfs, const char *path, struct nfs_stat_64 *st) +{ + struct sync_cb_data cb_data; + + cb_data.is_finished = 0; + cb_data.return_data = st; + + if (nfs_lstat64_async(nfs, path, stat64_cb, &cb_data) != 0) { + nfs_set_error(nfs, "nfs_lstat64_async failed"); + return -1; + } + + wait_for_nfs_reply(nfs, &cb_data); + + return cb_data.status; +} + /* * open() */ @@ -453,6 +474,26 @@ int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat *st) return cb_data.status; } +/* + * fstat64() + */ +int nfs_fstat64(struct nfs_context *nfs, struct nfsfh *nfsfh, struct nfs_stat_64 *st) +{ + struct sync_cb_data cb_data; + + cb_data.is_finished = 0; + cb_data.return_data = st; + + if (nfs_fstat64_async(nfs, nfsfh, stat64_cb, &cb_data) != 0) { + nfs_set_error(nfs, "nfs_fstat64_async failed"); + return -1; + } + + wait_for_nfs_reply(nfs, &cb_data); + + return cb_data.status; +} + /* * pwrite() @@ -696,15 +737,15 @@ static void creat_cb(int status, struct nfs_context *nfs, void *data, void *priv *nfsfh = fh; } -int nfs_creat(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh) +int nfs_create(struct nfs_context *nfs, const char *path, int flags, int mode, struct nfsfh **nfsfh) { struct sync_cb_data cb_data; cb_data.is_finished = 0; cb_data.return_data = nfsfh; - if (nfs_creat_async(nfs, path, mode, creat_cb, &cb_data) != 0) { - nfs_set_error(nfs, "nfs_creat_async failed"); + if (nfs_create_async(nfs, path, flags, mode, creat_cb, &cb_data) != 0) { + nfs_set_error(nfs, "nfs_create_async failed"); return -1; } @@ -713,6 +754,11 @@ int nfs_creat(struct nfs_context *nfs, const char *path, int mode, struct nfsfh return cb_data.status; } +int nfs_creat(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh) +{ + return nfs_create(nfs, path, 0, mode, nfsfh); +} + /* * mknod() */ @@ -973,6 +1019,22 @@ int nfs_chmod(struct nfs_context *nfs, const char *path, int mode) return cb_data.status; } +int nfs_lchmod(struct nfs_context *nfs, const char *path, int mode) +{ + struct sync_cb_data cb_data; + + cb_data.is_finished = 0; + + if (nfs_lchmod_async(nfs, path, mode, chmod_cb, &cb_data) != 0) { + nfs_set_error(nfs, "nfs_lchmod_async failed"); + return -1; + } + + wait_for_nfs_reply(nfs, &cb_data); + + return cb_data.status; +} + @@ -1043,6 +1105,25 @@ int nfs_chown(struct nfs_context *nfs, const char *path, int uid, int gid) return cb_data.status; } +/* + * lchown() + */ +int nfs_lchown(struct nfs_context *nfs, const char *path, int uid, int gid) +{ + struct sync_cb_data cb_data; + + cb_data.is_finished = 0; + + if (nfs_lchown_async(nfs, path, uid, gid, chown_cb, &cb_data) != 0) { + nfs_set_error(nfs, "nfs_lchown_async failed"); + return -1; + } + + wait_for_nfs_reply(nfs, &cb_data); + + return cb_data.status; +} + /* * fchown() */ @@ -1109,6 +1190,22 @@ int nfs_utimes(struct nfs_context *nfs, const char *path, struct timeval *times) return cb_data.status; } +int nfs_lutimes(struct nfs_context *nfs, const char *path, struct timeval *times) +{ + struct sync_cb_data cb_data; + + cb_data.is_finished = 0; + + if (nfs_lutimes_async(nfs, path, times, utimes_cb, &cb_data) != 0) { + nfs_set_error(nfs, "nfs_lutimes_async failed"); + return -1; + } + + wait_for_nfs_reply(nfs, &cb_data); + + return cb_data.status; +} + /* @@ -1180,6 +1277,40 @@ int nfs_access(struct nfs_context *nfs, const char *path, int mode) +/* + * access2() + */ +static void access2_cb(int status, struct nfs_context *nfs, void *data, void *private_data) +{ + struct sync_cb_data *cb_data = private_data; + + cb_data->is_finished = 1; + cb_data->status = status; + + if (status < 0) { + nfs_set_error(nfs, "access2 call failed with \"%s\"", (char *)data); + return; + } +} + +int nfs_access2(struct nfs_context *nfs, const char *path) +{ + struct sync_cb_data cb_data; + + cb_data.is_finished = 0; + + if (nfs_access2_async(nfs, path, access2_cb, &cb_data) != 0) { + nfs_set_error(nfs, "nfs_access2_async failed"); + return -1; + } + + wait_for_nfs_reply(nfs, &cb_data); + + return cb_data.status; +} + + + /* * symlink() */ diff --git a/lib/libnfs-zdr.c b/lib/libnfs-zdr.c index c32f661..921ec5f 100644 --- a/lib/libnfs-zdr.c +++ b/lib/libnfs-zdr.c @@ -20,6 +20,10 @@ * i.e. zdrmem_create() buffers. * It aims to be compatible with normal rpcgen generated functions. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #ifdef WIN32 #include "win32_compat.h" #endif @@ -28,10 +32,18 @@ #include "aros_compat.h" #endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + #include #include #include +#include #include "libnfs-zdr.h" +#include "libnfs.h" +#include "libnfs-raw.h" +#include "libnfs-private.h" struct opaque_auth _null_auth; @@ -106,7 +118,7 @@ bool_t libnfs_zdr_int(ZDR *zdrs, int32_t *i) return libnfs_zdr_u_int(zdrs, (uint32_t *)i); } -bool_t libnfs_zdr_u_quad_t(ZDR *zdrs, uint64_t *u) +bool_t libnfs_zdr_uint64_t(ZDR *zdrs, uint64_t *u) { if (zdrs->pos + 8 > zdrs->size) { return FALSE; @@ -133,9 +145,9 @@ bool_t libnfs_zdr_u_quad_t(ZDR *zdrs, uint64_t *u) return FALSE; } -bool_t libnfs_zdr_quad_t(ZDR *zdrs, int64_t *i) +bool_t libnfs_zdr_int64_t(ZDR *zdrs, int64_t *i) { - return libnfs_zdr_u_quad_t(zdrs, (uint64_t *)i); + return libnfs_zdr_uint64_t(zdrs, (uint64_t *)i); } bool_t libnfs_zdr_bytes(ZDR *zdrs, char **bufp, uint32_t *size, uint32_t maxsize) diff --git a/lib/libnfs.c b/lib/libnfs.c index 94f03cb..2bacd91 100644 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -59,12 +59,21 @@ #include #endif +#ifdef MAJOR_IN_MKDEV +#include +#endif + +#ifdef MAJOR_IN_SYSMACROS +#include +#endif + #include #include #include #include #include #include +#include #include #include #include @@ -78,6 +87,7 @@ #include "libnfs-private.h" #define MAX_DIR_CACHE 128 +#define MAX_LINK_COUNT 40 struct nfsdir { struct nfs_fh3 fh; @@ -168,6 +178,7 @@ struct nfs_cb_data { struct nfs_context *nfs; struct nfsfh *nfsfh; char *saved_path, *path; + int link_count, no_follow; nfs_cb cb; void *private_data; @@ -197,6 +208,7 @@ struct nfs_mcb_data { }; static int nfs_lookup_path_async_internal(struct nfs_context *nfs, fattr3 *attr, struct nfs_cb_data *data, struct nfs_fh3 *fh); +static int nfs_normalize_path(struct nfs_context *nfs, char *path); void nfs_set_auth(struct nfs_context *nfs, struct AUTH *auth) { @@ -696,6 +708,16 @@ static void free_nfs_cb_data(struct nfs_cb_data *data) free(data); } +static void free_nfsfh(struct nfsfh *nfsfh) +{ + if (nfsfh->fh.data.data_val != NULL) { + free(nfsfh->fh.data.data_val); + nfsfh->fh.data.data_val = NULL; + } + free(nfsfh->ra.buf); + free(nfsfh); +} + static void nfs_mount_10_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { @@ -771,6 +793,9 @@ static void nfs_mount_8_cb(struct rpc_context *rpc, int status, void *command_da return; } + /* NFS TCP connections we want to autoreconnect after sessions are torn down (due to inactivity or error) */ + rpc_set_autoreconnect(rpc); + args.fsroot = nfs->rootfh; if (rpc_nfs3_fsinfo_async(rpc, nfs_mount_9_cb, &args, data) != 0) { data->cb(-ENOMEM, nfs, command_data, data->private_data); @@ -823,9 +848,6 @@ static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_da free_nfs_cb_data(data); return; } - - /* NFS TCP connections we want to autoreconnect after sessions are torn down (due to inactivity or error) */ - rpc_set_autoreconnect(rpc); } @@ -897,6 +919,97 @@ int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *exp * Functions to first look up a path, component by component, and then finally call a specific function once * the filehandle for the final component is found. */ +static void nfs_lookup_path_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) +{ + struct nfs_cb_data *data = private_data; + struct nfs_context *nfs = data->nfs; + READLINK3res *res; + char *path, *newpath; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + if (status == RPC_STATUS_ERROR) { + data->cb(-EFAULT, nfs, command_data, data->private_data); + free_nfs_cb_data(data); + return; + } + if (status == RPC_STATUS_CANCEL) { + data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); + free_nfs_cb_data(data); + return; + } + + res = command_data; + if (res->status != NFS3_OK) { + rpc_set_error(nfs->rpc, "NFS: READLINK of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status)); + data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data); + free_nfs_cb_data(data); + return; + } + + path = res->READLINK3res_u.resok.data; + + /* Handle absolute paths, ensuring that the path lies within the + * export. */ + if (path[0] == '/') { + if (strstr(path, nfs->export) == path) { + char *ptr = path + strlen(nfs->export); + if (*ptr == '/') { + newpath = strdup(ptr); + } else if (*ptr == '\0') { + newpath = strdup("/"); + } else { + data->cb(-ENOENT, nfs, "Symbolic link points outside export", data->private_data); + free_nfs_cb_data(data); + return; + } + } else { + data->cb(-ENOENT, nfs, "Symbolic link points outside export", data->private_data); + free_nfs_cb_data(data); + return; + } + + if (!newpath) + goto nomem; + } else { + /* Handle relative paths, both the case where the current + * component is an intermediate component and when it is the + * final component. */ + if (data->path[0]) { + /* Since path points to a component and saved_path + * always starts with '/', path[-1] is valid. */ + data->path[-1] = '\0'; + newpath = malloc(strlen(data->saved_path) + strlen(path) + strlen(data->path) + 6); + if (!newpath) + goto nomem; + + sprintf(newpath, "%s/../%s/%s", data->saved_path, path, data->path); + } else { + newpath = malloc(strlen(data->saved_path) + strlen(path) + 5); + if (!newpath) + goto nomem; + + sprintf(newpath, "%s/../%s", data->saved_path, path); + } + } + free(data->saved_path); + data->saved_path = newpath; + + if (nfs_normalize_path(nfs, data->saved_path) != 0) { + data->cb(-ENOENT, nfs, "Symbolic link resolves to invalid path", data->private_data); + free_nfs_cb_data(data); + return; + } + + data->path = data->saved_path; + nfs_lookup_path_async_internal(nfs, NULL, data, &nfs->rootfh); + return; + +nomem: + data->cb(-ENOMEM, nfs, "Failed to allocate memory for path", data->private_data); + free_nfs_cb_data(data); +} + static void nfs_lookup_path_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct nfs_cb_data *data = private_data; @@ -935,7 +1048,7 @@ static void nfs_lookup_path_1_cb(struct rpc_context *rpc, int status, void *comm nfs_lookup_path_async_internal(nfs, attr, data, &res->LOOKUP3res_u.resok.object); } -static int nfs_lookup_path_async_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data, struct nfs_fh3 *fh) +static int nfs_lookup_path_async_internal(struct nfs_context *nfs, fattr3 *attr, struct nfs_cb_data *data, struct nfs_fh3 *fh) { char *path, *slash; LOOKUP3args args; @@ -946,6 +1059,31 @@ 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 args; + + 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; + } + + args.symlink = *fh; + + if (rpc_nfs3_readlink_async(nfs->rpc, nfs_lookup_path_2_cb, &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) { /* Clear slash so that path is a zero terminated string for * the current path component. Set it back to '/' again later @@ -1129,7 +1267,7 @@ static void nfs_lookup_path_getattr_cb(struct rpc_context *rpc, int status, void nfs_lookup_path_async_internal(nfs, attr, data, &nfs->rootfh); } -static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data, continue_func continue_cb, void *continue_data, void (*free_continue_data)(void *), int continue_int) +static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, int no_follow, nfs_cb cb, void *private_data, continue_func continue_cb, void *continue_data, void (*free_continue_data)(void *), int continue_int) { struct nfs_cb_data *data; struct GETATTR3args args; @@ -1154,6 +1292,7 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c data->free_continue_data = free_continue_data; data->continue_int = continue_int; data->private_data = private_data; + data->no_follow = no_follow; if (path[0] == '/') { data->saved_path = strdup(path); } else { @@ -1202,6 +1341,15 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c /* * Async stat() */ +static dev_t specdata3_to_rdev(struct specdata3 *rdev) +{ +#ifdef makedev + return makedev(rdev->specdata1, rdev->specdata2); +#else + return 0; +#endif +} + static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { GETATTR3res *res; @@ -1234,27 +1382,49 @@ static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_dat return; } - st.st_dev = -1; + st.st_dev = res->GETATTR3res_u.resok.obj_attributes.fsid; st.st_ino = res->GETATTR3res_u.resok.obj_attributes.fileid; st.st_mode = res->GETATTR3res_u.resok.obj_attributes.mode; - if (res->GETATTR3res_u.resok.obj_attributes.type == NF3DIR) { - st.st_mode |= S_IFDIR ; - } - if (res->GETATTR3res_u.resok.obj_attributes.type == NF3REG) { - st.st_mode |= S_IFREG ; + switch (res->GETATTR3res_u.resok.obj_attributes.type) { + case NF3REG: + st.st_mode |= S_IFREG; + break; + case NF3DIR: + st.st_mode |= S_IFDIR; + break; + case NF3BLK: + st.st_mode |= S_IFBLK; + break; + case NF3CHR: + st.st_mode |= S_IFCHR; + break; + case NF3LNK: + st.st_mode |= S_IFLNK; + break; + case NF3SOCK: + st.st_mode |= S_IFSOCK; + break; + case NF3FIFO: + st.st_mode |= S_IFIFO; + break; } st.st_nlink = res->GETATTR3res_u.resok.obj_attributes.nlink; st.st_uid = res->GETATTR3res_u.resok.obj_attributes.uid; st.st_gid = res->GETATTR3res_u.resok.obj_attributes.gid; - st.st_rdev = 0; + st.st_rdev = specdata3_to_rdev(&res->GETATTR3res_u.resok.obj_attributes.rdev); st.st_size = res->GETATTR3res_u.resok.obj_attributes.size; #ifndef WIN32 st.st_blksize = NFS_BLKSIZE; - st.st_blocks = res->GETATTR3res_u.resok.obj_attributes.size / NFS_BLKSIZE; + st.st_blocks = (res->GETATTR3res_u.resok.obj_attributes.used + 512 - 1) / 512; #endif//WIN32 st.st_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds; st.st_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds; st.st_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds; +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + st.st_atim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.atime.nseconds; + st.st_mtim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.mtime.nseconds; + st.st_ctim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.ctime.nseconds; +#endif data->cb(0, nfs, &st, data->private_data); free_nfs_cb_data(data); @@ -1278,7 +1448,7 @@ static int nfs_stat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, int nfs_stat_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data) { - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_stat_continue_internal, NULL, NULL, 0) != 0) { + if (nfs_lookuppath_async(nfs, path, 0, cb, private_data, nfs_stat_continue_internal, NULL, NULL, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -1318,23 +1488,46 @@ static void nfs_stat64_1_cb(struct rpc_context *rpc, int status, void *command_d return; } - st.nfs_dev = -1; + st.nfs_dev = res->GETATTR3res_u.resok.obj_attributes.fsid; st.nfs_ino = res->GETATTR3res_u.resok.obj_attributes.fileid; st.nfs_mode = res->GETATTR3res_u.resok.obj_attributes.mode; - if (res->GETATTR3res_u.resok.obj_attributes.type == NF3DIR) { - st.nfs_mode |= S_IFDIR ; - } - if (res->GETATTR3res_u.resok.obj_attributes.type == NF3REG) { - st.nfs_mode |= S_IFREG ; + switch (res->GETATTR3res_u.resok.obj_attributes.type) { + case NF3REG: + st.nfs_mode |= S_IFREG; + break; + case NF3DIR: + st.nfs_mode |= S_IFDIR; + break; + case NF3BLK: + st.nfs_mode |= S_IFBLK; + break; + case NF3CHR: + st.nfs_mode |= S_IFCHR; + break; + case NF3LNK: + st.nfs_mode |= S_IFLNK; + break; + case NF3SOCK: + st.nfs_mode |= S_IFSOCK; + break; + case NF3FIFO: + st.nfs_mode |= S_IFIFO; + break; } st.nfs_nlink = res->GETATTR3res_u.resok.obj_attributes.nlink; st.nfs_uid = res->GETATTR3res_u.resok.obj_attributes.uid; st.nfs_gid = res->GETATTR3res_u.resok.obj_attributes.gid; - st.nfs_rdev = 0; + st.nfs_rdev = specdata3_to_rdev(&res->GETATTR3res_u.resok.obj_attributes.rdev); st.nfs_size = res->GETATTR3res_u.resok.obj_attributes.size; + st.nfs_blksize = NFS_BLKSIZE; + st.nfs_blocks = (res->GETATTR3res_u.resok.obj_attributes.used + 512 - 1) / 512; st.nfs_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds; st.nfs_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds; st.nfs_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds; + st.nfs_atime_nsec = res->GETATTR3res_u.resok.obj_attributes.atime.nseconds; + st.nfs_mtime_nsec = res->GETATTR3res_u.resok.obj_attributes.mtime.nseconds; + st.nfs_ctime_nsec = res->GETATTR3res_u.resok.obj_attributes.ctime.nseconds; + st.nfs_used = res->GETATTR3res_u.resok.obj_attributes.used; data->cb(0, nfs, &st, data->private_data); free_nfs_cb_data(data); @@ -1356,9 +1549,9 @@ static int nfs_stat64_continue_internal(struct nfs_context *nfs, fattr3 *attr _U return 0; } -int nfs_stat64_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data) +int nfs_stat64_async_internal(struct nfs_context *nfs, const char *path, int no_follow, nfs_cb cb, void *private_data) { - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_stat64_continue_internal, NULL, NULL, 0) != 0) { + if (nfs_lookuppath_async(nfs, path, no_follow, cb, private_data, nfs_stat64_continue_internal, NULL, NULL, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -1366,6 +1559,16 @@ int nfs_stat64_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void return 0; } +int nfs_stat64_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data) +{ + return nfs_stat64_async_internal(nfs, path, 0, cb, private_data); +} + +int nfs_lstat64_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data) +{ + return nfs_stat64_async_internal(nfs, path, 1, cb, private_data); +} + /* * Async open() */ @@ -1552,7 +1755,7 @@ static int nfs_open_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, int nfs_open_async(struct nfs_context *nfs, const char *path, int flags, nfs_cb cb, void *private_data) { - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_open_continue_internal, NULL, NULL, flags) != 0) { + if (nfs_lookuppath_async(nfs, path, 0, cb, private_data, nfs_open_continue_internal, NULL, NULL, flags) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -1579,7 +1782,7 @@ static int nfs_chdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_ int nfs_chdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data) { - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chdir_continue_internal, NULL, NULL, 0) != 0) { + if (nfs_lookuppath_async(nfs, path, 0, cb, private_data, nfs_chdir_continue_internal, NULL, NULL, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -1605,6 +1808,8 @@ static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_dat struct nfs_cb_data *data = mdata->data; struct nfs_context *nfs = data->nfs; READ3res *res; + int cb_err; + void *cb_data; assert(rpc->magic == RPC_CONTEXT_MAGIC); @@ -1703,9 +1908,11 @@ static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_dat if (data->max_offset > data->org_offset + data->org_count) { data->max_offset = data->org_offset + data->org_count; } - data->cb(data->max_offset - data->org_offset, nfs, data->buffer + (data->org_offset - data->offset), data->private_data); + cb_err = data->max_offset - data->org_offset; + cb_data = data->buffer + (data->org_offset - data->offset); } else { - data->cb(res->READ3res_u.resok.count, nfs, res->READ3res_u.resok.data.data_val, data->private_data); + cb_err = res->READ3res_u.resok.count; + cb_data = res->READ3res_u.resok.data.data_val; } data->nfsfh->ra.fh_offset = data->max_offset; @@ -1717,6 +1924,8 @@ static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_dat data->nfsfh->ra.buf_ts = time(NULL); data->buffer = NULL; } + + data->cb(cb_err, nfs, cb_data, data->private_data); free_nfs_cb_data(data); } @@ -2135,13 +2344,7 @@ int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data) { - if (nfsfh->fh.data.data_val != NULL){ - free(nfsfh->fh.data.data_val); - nfsfh->fh.data.data_val = NULL; - } - free(nfsfh->ra.buf); - free(nfsfh); - + free_nfsfh(nfsfh); cb(0, nfs, NULL, private_data); return 0; }; @@ -2180,6 +2383,36 @@ int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, voi return 0; } +/* + * Async fstat64() + */ +int nfs_fstat64_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data) +{ + struct nfs_cb_data *data; + struct GETATTR3args args; + + data = malloc(sizeof(struct nfs_cb_data)); + if (data == NULL) { + rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure"); + return -1; + } + memset(data, 0, sizeof(struct nfs_cb_data)); + data->nfs = nfs; + data->cb = cb; + data->private_data = private_data; + + memset(&args, 0, sizeof(GETATTR3args)); + args.object = nfsfh->fh; + + if (rpc_nfs3_getattr_async(nfs->rpc, nfs_stat64_1_cb, &args, data) != 0) { + rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path); + data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); + free_nfs_cb_data(data); + return -1; + } + return 0; +} + /* @@ -2336,7 +2569,7 @@ int nfs_truncate_async(struct nfs_context *nfs, const char *path, uint64_t lengt offset = length; - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_truncate_continue_internal, NULL, NULL, offset) != 0) { + if (nfs_lookuppath_async(nfs, path, 0, cb, private_data, nfs_truncate_continue_internal, NULL, NULL, offset) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -2426,7 +2659,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, 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, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path component"); return -1; } @@ -2513,7 +2746,7 @@ int nfs_rmdir_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, cb, private_data, nfs_rmdir_continue_internal, new_path, free, 0) != 0) { + if (nfs_lookuppath_async(nfs, new_path, 0, cb, private_data, nfs_rmdir_continue_internal, new_path, free, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -2527,13 +2760,63 @@ int nfs_rmdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void * /* * Async creat() */ +struct create_cb_data { + char *path; + int flags; + int mode; +}; + +static void free_create_cb_data(void *ptr) +{ + struct create_cb_data *data = ptr; + + free(data->path); + free(data); +} + +static void nfs_create_trunc_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) +{ + struct nfs_cb_data *data = private_data; + struct nfs_context *nfs = data->nfs; + struct nfsfh *nfsfh = data->nfsfh; + SETATTR3res *res; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + if (status == RPC_STATUS_ERROR) { + data->cb(-EFAULT, nfs, command_data, data->private_data); + free_nfs_cb_data(data); + free_nfsfh(nfsfh); + return; + } + if (status == RPC_STATUS_CANCEL) { + data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); + free_nfs_cb_data(data); + free_nfsfh(nfsfh); + return; + } + + res = command_data; + if (res->status != NFS3_OK) { + rpc_set_error(nfs->rpc, "NFS: Setattr failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status)); + data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data); + free_nfs_cb_data(data); + free_nfsfh(nfsfh); + return; + } + + data->cb(0, nfs, nfsfh, data->private_data); + free_nfs_cb_data(data); +} + static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { LOOKUP3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; struct nfsfh *nfsfh; - char *str = data->continue_data; + struct create_cb_data *cb_data = data->continue_data; + char *str = cb_data->path; assert(rpc->magic == RPC_CONTEXT_MAGIC); @@ -2566,23 +2849,62 @@ static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_d } memset(nfsfh, 0, sizeof(struct nfsfh)); + if (cb_data->flags & O_SYNC) { + nfsfh->is_sync = 1; + } + if (cb_data->flags & O_APPEND) { + nfsfh->is_append = 1; + } + /* copy the filehandle */ nfsfh->fh.data.data_len = res->LOOKUP3res_u.resok.object.data.data_len; nfsfh->fh.data.data_val = malloc(nfsfh->fh.data.data_len); + if (nfsfh->fh.data.data_val == NULL) { + rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh structure"); + data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); + free_nfs_cb_data(data); + free(nfsfh); + return; + } memcpy(nfsfh->fh.data.data_val, res->LOOKUP3res_u.resok.object.data.data_val, nfsfh->fh.data.data_len); + /* Try to truncate it if we were requested to */ + if (cb_data->flags & O_TRUNC) { + SETATTR3args args; + + data->nfsfh = nfsfh; + + memset(&args, 0, sizeof(SETATTR3args)); + args.object = nfsfh->fh; + args.new_attributes.size.set_it = 1; + args.new_attributes.size.set_size3_u.size = 0; + + if (rpc_nfs3_setattr_async(nfs->rpc, nfs_create_trunc_cb, + &args, data) != 0) { + rpc_set_error(nfs->rpc, "RPC error: Failed to send " + "SETATTR call for %s", data->path); + data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), + data->private_data); + free_nfs_cb_data(data); + free_nfsfh(nfsfh); + return; + } + return; + } + data->cb(0, nfs, nfsfh, data->private_data); free_nfs_cb_data(data); } -static void nfs_creat_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) +static void nfs_create_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { CREATE3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; - char *str = data->continue_data; + struct create_cb_data *cb_data = data->continue_data; + char *str = cb_data->path; LOOKUP3args args; assert(rpc->magic == RPC_CONTEXT_MAGIC); @@ -2620,9 +2942,10 @@ static void nfs_creat_1_cb(struct rpc_context *rpc, int status, void *command_da return; } -static int nfs_creat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data) +static int nfs_create_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data) { - char *str = data->continue_data; + struct create_cb_data *cb_data = data->continue_data; + char *str = cb_data->path; CREATE3args args; str = &str[strlen(str) + 1]; @@ -2630,11 +2953,11 @@ static int nfs_creat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_ memset(&args, 0, sizeof(CREATE3args)); args.where.dir = data->fh; args.where.name = str; - args.how.mode = UNCHECKED; + args.how.mode = (cb_data->flags & O_EXCL) ? GUARDED : UNCHECKED; args.how.createhow3_u.obj_attributes.mode.set_it = 1; - args.how.createhow3_u.obj_attributes.mode.set_mode3_u.mode = data->continue_int; + args.how.createhow3_u.obj_attributes.mode.set_mode3_u.mode = cb_data->mode; - if (rpc_nfs3_create_async(nfs->rpc, nfs_creat_1_cb, &args, data) != 0) { + if (rpc_nfs3_create_async(nfs->rpc, nfs_create_1_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send CREATE call for %s/%s", data->path, str); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -2643,27 +2966,37 @@ static int nfs_creat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_ return 0; } -int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data) +int nfs_create_async(struct nfs_context *nfs, const char *path, int flags, int mode, nfs_cb cb, void *private_data) { - char *new_path; + struct create_cb_data *cb_data; char *ptr; - new_path = strdup(path); - if (new_path == NULL) { + cb_data = malloc(sizeof(struct create_cb_data)); + if (cb_data == NULL) { + rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for cb data"); + return -1; + } + + cb_data->path = strdup(path); + if (cb_data->path == NULL) { rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path"); + free(cb_data); return -1; } - ptr = strrchr(new_path, '/'); + ptr = strrchr(cb_data->path, '/'); if (ptr == NULL) { rpc_set_error(nfs->rpc, "Invalid path %s", path); - free(new_path); + free_create_cb_data(cb_data); return -1; } *ptr = 0; + cb_data->flags = flags; + cb_data->mode = mode; + /* new_path now points to the parent directory, and beyond the nul terminator is the new directory to create */ - if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_creat_continue_internal, new_path, free, mode) != 0) { + if (nfs_lookuppath_async(nfs, cb_data->path, 0, cb, private_data, nfs_create_continue_internal, cb_data, free_create_cb_data, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -2671,6 +3004,11 @@ int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb return 0; } +int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data) +{ + return nfs_create_async(nfs, path, 0, mode, cb, private_data); +} + @@ -2749,7 +3087,7 @@ int nfs_unlink_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, cb, private_data, nfs_unlink_continue_internal, new_path, free, 0) != 0) { + if (nfs_lookuppath_async(nfs, new_path, 0, cb, private_data, nfs_unlink_continue_internal, new_path, free, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -2890,7 +3228,7 @@ int nfs_mknod_async(struct nfs_context *nfs, const char *path, int mode, int dev cb_data->minor = minor(dev); /* data->path now points to the parent directory, and beyond the nul terminateor is the new directory to create */ - if (nfs_lookuppath_async(nfs, cb_data->path, cb, private_data, nfs_mknod_continue_internal, cb_data, free_mknod_cb_data, 0) != 0) { + if (nfs_lookuppath_async(nfs, cb_data->path, 0, cb, private_data, nfs_mknod_continue_internal, cb_data, free_mknod_cb_data, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -2952,13 +3290,21 @@ static void nfs_opendir3_cb(struct rpc_context *rpc, int status, void *command_d nfsdirent->atime.tv_sec = attributes->atime.seconds; nfsdirent->atime.tv_usec = attributes->atime.nseconds/1000; + nfsdirent->atime_nsec = attributes->atime.nseconds; nfsdirent->mtime.tv_sec = attributes->mtime.seconds; nfsdirent->mtime.tv_usec = attributes->mtime.nseconds/1000; + nfsdirent->mtime_nsec = attributes->mtime.nseconds; nfsdirent->ctime.tv_sec = attributes->ctime.seconds; nfsdirent->ctime.tv_usec = attributes->ctime.nseconds/1000; + nfsdirent->ctime_nsec = attributes->ctime.nseconds; nfsdirent->uid = attributes->uid; nfsdirent->gid = attributes->gid; nfsdirent->nlink = attributes->nlink; + nfsdirent->dev = attributes->fsid; + nfsdirent->rdev = specdata3_to_rdev(&attributes->rdev); + nfsdirent->blksize = NFS_BLKSIZE; + nfsdirent->blocks = (attributes->used + 512 - 1) / 512; + nfsdirent->used = attributes->used; } } @@ -3193,13 +3539,21 @@ static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_da nfsdirent->atime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.atime.seconds; nfsdirent->atime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.atime.nseconds/1000; + nfsdirent->atime_nsec = entry->name_attributes.post_op_attr_u.attributes.atime.nseconds; nfsdirent->mtime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.mtime.seconds; nfsdirent->mtime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.mtime.nseconds/1000; + nfsdirent->mtime_nsec = entry->name_attributes.post_op_attr_u.attributes.mtime.nseconds; nfsdirent->ctime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.ctime.seconds; nfsdirent->ctime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.ctime.nseconds/1000; + nfsdirent->ctime_nsec = entry->name_attributes.post_op_attr_u.attributes.ctime.nseconds; nfsdirent->uid = entry->name_attributes.post_op_attr_u.attributes.uid; nfsdirent->gid = entry->name_attributes.post_op_attr_u.attributes.gid; nfsdirent->nlink = entry->name_attributes.post_op_attr_u.attributes.nlink; + nfsdirent->dev = entry->name_attributes.post_op_attr_u.attributes.fsid; + nfsdirent->rdev = specdata3_to_rdev(&entry->name_attributes.post_op_attr_u.attributes.rdev); + nfsdirent->blksize = NFS_BLKSIZE; + nfsdirent->blocks = (entry->name_attributes.post_op_attr_u.attributes.used + 512 - 1) / 512; + nfsdirent->used = entry->name_attributes.post_op_attr_u.attributes.used; } nfsdirent->next = nfsdir->entries; @@ -3294,7 +3648,7 @@ int nfs_opendir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void } memset(nfsdir, 0, sizeof(struct nfsdir)); - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_opendir_continue_internal, nfsdir, free, 0) != 0) { + if (nfs_lookuppath_async(nfs, path, 0, cb, private_data, nfs_opendir_continue_internal, nfsdir, free, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -3502,7 +3856,7 @@ static int nfs_statvfs_continue_internal(struct nfs_context *nfs, fattr3 *attr _ int nfs_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data) { - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_statvfs_continue_internal, NULL, NULL, 0) != 0) { + if (nfs_lookuppath_async(nfs, path, 0, cb, private_data, nfs_statvfs_continue_internal, NULL, NULL, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -3565,7 +3919,7 @@ static int nfs_readlink_continue_internal(struct nfs_context *nfs, fattr3 *attr int nfs_readlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data) { - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_readlink_continue_internal, NULL, NULL, 0) != 0) { + if (nfs_lookuppath_async(nfs, path, 1, cb, private_data, nfs_readlink_continue_internal, NULL, NULL, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -3629,9 +3983,9 @@ static int nfs_chmod_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_ } -int nfs_chmod_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data) +int nfs_chmod_async_internal(struct nfs_context *nfs, const char *path, int no_follow, int mode, nfs_cb cb, void *private_data) { - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chmod_continue_internal, NULL, NULL, mode) != 0) { + if (nfs_lookuppath_async(nfs, path, no_follow, cb, private_data, nfs_chmod_continue_internal, NULL, NULL, mode) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -3639,6 +3993,16 @@ int nfs_chmod_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb return 0; } +int nfs_chmod_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data) +{ + return nfs_chmod_async_internal(nfs, path, 0, mode, cb, private_data); +} + +int nfs_lchmod_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data) +{ + return nfs_chmod_async_internal(nfs, path, 1, mode, cb, private_data); +} + /* * Async fchmod() */ @@ -3739,7 +4103,7 @@ static int nfs_chown_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_ } -int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, int gid, nfs_cb cb, void *private_data) +int nfs_chown_async_internal(struct nfs_context *nfs, const char *path, int no_follow, int uid, int gid, nfs_cb cb, void *private_data) { struct nfs_chown_data *chown_data; @@ -3752,7 +4116,7 @@ int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, int gid, chown_data->uid = uid; chown_data->gid = gid; - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chown_continue_internal, chown_data, free, 0) != 0) { + if (nfs_lookuppath_async(nfs, path, no_follow, cb, private_data, nfs_chown_continue_internal, chown_data, free, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -3760,6 +4124,15 @@ int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, int gid, return 0; } +int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, int gid, nfs_cb cb, void *private_data) +{ + return nfs_chown_async_internal(nfs, path, 0, uid, gid, cb, private_data); +} + +int nfs_lchown_async(struct nfs_context *nfs, const char *path, int uid, int gid, nfs_cb cb, void *private_data) +{ + return nfs_chown_async_internal(nfs, path, 1, uid, gid, cb, private_data); +} /* * Async fchown() @@ -3872,8 +4245,7 @@ static int nfs_utimes_continue_internal(struct nfs_context *nfs, fattr3 *attr _U return 0; } - -int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct timeval *times, nfs_cb cb, void *private_data) +int nfs_utimes_async_internal(struct nfs_context *nfs, const char *path, int no_follow, struct timeval *times, nfs_cb cb, void *private_data) { struct timeval *new_times = NULL; @@ -3887,7 +4259,7 @@ int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct timeval * memcpy(new_times, times, sizeof(struct timeval)*2); } - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) { + if (nfs_lookuppath_async(nfs, path, no_follow, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -3895,6 +4267,16 @@ int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct timeval * return 0; } +int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct timeval *times, nfs_cb cb, void *private_data) +{ + return nfs_utimes_async_internal(nfs, path, 0, times, cb, private_data); +} + +int nfs_lutimes_async(struct nfs_context *nfs, const char *path, struct timeval *times, nfs_cb cb, void *private_data) +{ + return nfs_utimes_async_internal(nfs, path, 1, times, cb, private_data); +} + /* * Async utime() */ @@ -3915,7 +4297,7 @@ int nfs_utime_async(struct nfs_context *nfs, const char *path, struct utimbuf *t new_times[1].tv_usec = 0; } - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) { + if (nfs_lookuppath_async(nfs, path, 0, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -3932,7 +4314,7 @@ static void nfs_access_cb(struct rpc_context *rpc, int status, void *command_dat ACCESS3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; - unsigned int nfsmode = 0; + unsigned int mode = 0; assert(rpc->magic == RPC_CONTEXT_MAGIC); @@ -3955,24 +4337,24 @@ static void nfs_access_cb(struct rpc_context *rpc, int status, void *command_dat return; } - if (data->continue_int & R_OK) { - nfsmode |= ACCESS3_READ; + if ((data->continue_int & R_OK) && (res->ACCESS3res_u.resok.access & ACCESS3_READ)) { + mode |= R_OK; } - if (data->continue_int & W_OK) { - nfsmode |= ACCESS3_MODIFY; + if ((data->continue_int & W_OK) && (res->ACCESS3res_u.resok.access & (ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE))) { + mode |= W_OK; } - if (data->continue_int & X_OK) { - nfsmode |= ACCESS3_EXECUTE; + if ((data->continue_int & X_OK) && (res->ACCESS3res_u.resok.access & (ACCESS3_LOOKUP | ACCESS3_EXECUTE))) { + mode |= X_OK; } - if (res->ACCESS3res_u.resok.access != nfsmode) { + if (data->continue_int != mode) { rpc_set_error(nfs->rpc, "NFS: ACCESS denied. Required access %c%c%c. Allowed access %c%c%c", - nfsmode&ACCESS3_READ?'r':'-', - nfsmode&ACCESS3_MODIFY?'w':'-', - nfsmode&ACCESS3_EXECUTE?'x':'-', - res->ACCESS3res_u.resok.access&ACCESS3_READ?'r':'-', - res->ACCESS3res_u.resok.access&ACCESS3_MODIFY?'w':'-', - res->ACCESS3res_u.resok.access&ACCESS3_EXECUTE?'x':'-'); + data->continue_int&R_OK?'r':'-', + data->continue_int&W_OK?'w':'-', + data->continue_int&X_OK?'x':'-', + mode&R_OK?'r':'-', + mode&W_OK?'w':'-', + mode&X_OK?'x':'-'); data->cb(-EACCES, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); return; @@ -3991,10 +4373,10 @@ static int nfs_access_continue_internal(struct nfs_context *nfs, fattr3 *attr _U nfsmode |= ACCESS3_READ; } if (data->continue_int & W_OK) { - nfsmode |= ACCESS3_MODIFY; + nfsmode |= ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE; } if (data->continue_int & X_OK) { - nfsmode |= ACCESS3_EXECUTE; + nfsmode |= ACCESS3_LOOKUP | ACCESS3_EXECUTE; } memset(&args, 0, sizeof(ACCESS3args)); @@ -4012,7 +4394,81 @@ static int nfs_access_continue_internal(struct nfs_context *nfs, fattr3 *attr _U int nfs_access_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data) { - if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_access_continue_internal, NULL, NULL, mode) != 0) { + if (nfs_lookuppath_async(nfs, path, 0, cb, private_data, nfs_access_continue_internal, NULL, NULL, mode & (R_OK | W_OK | X_OK)) != 0) { + rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); + return -1; + } + + return 0; +} + + + +/* + * Async access2() + */ +static void nfs_access2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) +{ + ACCESS3res *res; + struct nfs_cb_data *data = private_data; + struct nfs_context *nfs = data->nfs; + unsigned int result = 0; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + if (status == RPC_STATUS_ERROR) { + data->cb(-EFAULT, nfs, command_data, data->private_data); + free_nfs_cb_data(data); + return; + } + if (status == RPC_STATUS_CANCEL) { + data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); + free_nfs_cb_data(data); + return; + } + + res = command_data; + if (res->status != NFS3_OK) { + rpc_set_error(nfs->rpc, "NFS: ACCESS of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status)); + data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data); + free_nfs_cb_data(data); + return; + } + + if (res->ACCESS3res_u.resok.access & ACCESS3_READ) { + result |= R_OK; + } + if (res->ACCESS3res_u.resok.access & (ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE)) { + result |= W_OK; + } + if (res->ACCESS3res_u.resok.access & (ACCESS3_LOOKUP | ACCESS3_EXECUTE)) { + result |= X_OK; + } + + data->cb(result, nfs, NULL, data->private_data); + free_nfs_cb_data(data); +} + +static int nfs_access2_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data) +{ + ACCESS3args args; + + memset(&args, 0, sizeof(ACCESS3args)); + args.object = data->fh; + args.access = ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE | ACCESS3_EXECUTE; + + if (rpc_nfs3_access_async(nfs->rpc, nfs_access2_cb, &args, data) != 0) { + rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS call for %s", data->path); + data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); + free_nfs_cb_data(data); + return -1; + } + return 0; +} + +int nfs_access2_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data) +{ + if (nfs_lookuppath_async(nfs, path, 0, cb, private_data, nfs_access2_continue_internal, NULL, NULL, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -4142,7 +4598,7 @@ int nfs_symlink_async(struct nfs_context *nfs, const char *oldpath, const char * return -1; } - if (nfs_lookuppath_async(nfs, symlink_data->newpathparent, cb, private_data, nfs_symlink_continue_internal, symlink_data, free_nfs_symlink_data, 0) != 0) { + if (nfs_lookuppath_async(nfs, symlink_data->newpathparent, 0, cb, private_data, nfs_symlink_continue_internal, symlink_data, free_nfs_symlink_data, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -4253,7 +4709,7 @@ static int nfs_rename_continue_1_internal(struct nfs_context *nfs, fattr3 *attr rename_data->olddir = data->fh; data->fh.data.data_val = NULL; - if (nfs_lookuppath_async(nfs, rename_data->newpath, data->cb, data->private_data, nfs_rename_continue_2_internal, rename_data, free_nfs_rename_data, 0) != 0) { + if (nfs_lookuppath_async(nfs, rename_data->newpath, 0, data->cb, data->private_data, nfs_rename_continue_2_internal, rename_data, free_nfs_rename_data, 0) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send LOOKUP call for %s", newpath); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -4314,7 +4770,7 @@ int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *n rename_data->newobject = ptr; - if (nfs_lookuppath_async(nfs, rename_data->oldpath, cb, private_data, nfs_rename_continue_1_internal, rename_data, free_nfs_rename_data, 0) != 0) { + if (nfs_lookuppath_async(nfs, rename_data->oldpath, 0, cb, private_data, nfs_rename_continue_1_internal, rename_data, free_nfs_rename_data, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -4416,7 +4872,7 @@ static int nfs_link_continue_1_internal(struct nfs_context *nfs, fattr3 *attr _U link_data->oldfh = data->fh; data->fh.data.data_val = NULL; - if (nfs_lookuppath_async(nfs, link_data->newpath, data->cb, data->private_data, nfs_link_continue_2_internal, link_data, free_nfs_link_data, 0) != 0) { + if (nfs_lookuppath_async(nfs, link_data->newpath, 0, data->cb, data->private_data, nfs_link_continue_2_internal, link_data, free_nfs_link_data, 0) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send LOOKUP call for %s", link_data->newpath); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -4465,7 +4921,7 @@ int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *new link_data->newobject = ptr; - if (nfs_lookuppath_async(nfs, link_data->oldpath, cb, private_data, nfs_link_continue_1_internal, link_data, free_nfs_link_data, 0) != 0) { + if (nfs_lookuppath_async(nfs, link_data->oldpath, 0, cb, private_data, nfs_link_continue_1_internal, link_data, free_nfs_link_data, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } diff --git a/lib/socket.c b/lib/socket.c index f973f01..1c1853c 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -46,6 +46,10 @@ #include #endif +#ifdef HAVE_NETINET_IN_H +#include +#endif + #ifdef HAVE_NETINET_TCP_H #include #endif @@ -68,6 +72,7 @@ #include #include #include +#include #include #include "libnfs-zdr.h" #include "libnfs.h" @@ -506,7 +511,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s ((struct sockaddr_in6 *)&ss)->sin6_port = port; ((struct sockaddr_in6 *)&ss)->sin6_family = AF_INET6; #ifdef HAVE_SOCKADDR_LEN - ((struct sockaddr_in6 *)&ss)->sin6_len = sizeof(struct sockaddr6_in); + ((struct sockaddr_in6 *)&ss)->sin6_len = sizeof(struct sockaddr_in6); #endif break; } diff --git a/nfs/Makefile.am b/nfs/Makefile.am index c155372..de62dce 100644 --- a/nfs/Makefile.am +++ b/nfs/Makefile.am @@ -19,6 +19,6 @@ nfs-stamp : nfs.x compile_rpc: cat nfs.x | head -29 >libnfs-raw-nfs.h - rpcgen -h nfs.x | sed -e "s/#include /#include /" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/#define _NFS_H_RPCGEN/#define _NFS_H_RPCGEN\n#include /g" -e "s/#define NFS3_COOKIEVERFSIZE 8/#define NFS3_COOKIEVERFSIZE 8\n\n#if defined(ANDROID)\ntypedef long long int quad_t;\ntypedef long long unsigned u_quad_t;\n#endif\n#if defined(WIN32)\ntypedef long long int quad_t;\ntypedef long long unsigned u_quad_t;\n#endif/g" -e "s/ CLIENT / void /g" -e "s/SVCXPRT /void /g" -e "s/bool_t/uint32_t/g" >> libnfs-raw-nfs.h + rpcgen -h nfs.x | sed -e "s/#include /#include /" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/#define _NFS_H_RPCGEN/#define _NFS_H_RPCGEN\n#include /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-nfs.h cat nfs.x | head -29 >libnfs-raw-nfs.c rpcgen -c nfs.x | sed -e "s/#include \".*nfs.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-nfs.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n buf = NULL;/" -e "s/bool_t/uint32_t/g" >> libnfs-raw-nfs.c diff --git a/nfs/libnfs-raw-nfs.c b/nfs/libnfs-raw-nfs.c index 925048a..6a02346 100644 --- a/nfs/libnfs-raw-nfs.c +++ b/nfs/libnfs-raw-nfs.c @@ -52,7 +52,7 @@ zdr_cookie3 (ZDR *zdrs, cookie3 *objp) register int32_t *buf; buf = NULL; - if (!zdr_u_quad_t (zdrs, objp)) + if (!zdr_uint64_t (zdrs, objp)) return FALSE; return TRUE; } @@ -142,7 +142,7 @@ zdr_size3 (ZDR *zdrs, size3 *objp) register int32_t *buf; buf = NULL; - if (!zdr_u_quad_t (zdrs, objp)) + if (!zdr_uint64_t (zdrs, objp)) return FALSE; return TRUE; } @@ -153,7 +153,7 @@ zdr_fileid3 (ZDR *zdrs, fileid3 *objp) register int32_t *buf; buf = NULL; - if (!zdr_u_quad_t (zdrs, objp)) + if (!zdr_uint64_t (zdrs, objp)) return FALSE; return TRUE; } @@ -206,7 +206,7 @@ zdr_fattr3 (ZDR *zdrs, fattr3 *objp) return FALSE; if (!zdr_specdata3 (zdrs, &objp->rdev)) return FALSE; - if (!zdr_u_quad_t (zdrs, &objp->fsid)) + if (!zdr_uint64_t (zdrs, &objp->fsid)) return FALSE; if (!zdr_fileid3 (zdrs, &objp->fileid)) return FALSE; @@ -268,7 +268,7 @@ zdr_offset3 (ZDR *zdrs, offset3 *objp) register int32_t *buf; buf = NULL; - if (!zdr_u_quad_t (zdrs, objp)) + if (!zdr_uint64_t (zdrs, objp)) return FALSE; return TRUE; } diff --git a/nfs/libnfs-raw-nfs.h b/nfs/libnfs-raw-nfs.h index 835029e..a3b60f5 100644 --- a/nfs/libnfs-raw-nfs.h +++ b/nfs/libnfs-raw-nfs.h @@ -48,18 +48,11 @@ extern "C" { #define NFS3_CREATEVERFSIZE 8 #define NFS3_COOKIEVERFSIZE 8 -#if defined(ANDROID) -typedef long long int quad_t; -typedef long long unsigned u_quad_t; -#endif -#if defined(WIN32) -typedef long long int quad_t; -typedef long long unsigned u_quad_t; -#endif + typedef char cookieverf3[NFS3_COOKIEVERFSIZE]; -typedef u_quad_t cookie3; +typedef uint64_t cookie3; struct nfs_fh3 { struct { @@ -94,9 +87,9 @@ typedef u_int uid3; typedef u_int gid3; -typedef u_quad_t size3; +typedef uint64_t size3; -typedef u_quad_t fileid3; +typedef uint64_t fileid3; struct specdata3 { u_int specdata1; @@ -119,7 +112,7 @@ struct fattr3 { size3 size; size3 used; specdata3 rdev; - u_quad_t fsid; + uint64_t fsid; fileid3 fileid; nfstime3 atime; nfstime3 mtime; @@ -175,7 +168,7 @@ enum stable_how { }; typedef enum stable_how stable_how; -typedef u_quad_t offset3; +typedef uint64_t offset3; typedef u_int count3; diff --git a/nfs/nfs.c b/nfs/nfs.c index a97d40a..335c67b 100644 --- a/nfs/nfs.c +++ b/nfs/nfs.c @@ -86,7 +86,7 @@ int nfsstat3_to_errno(int error) case NFS3ERR_ROFS: return -EROFS; break; case NFS3ERR_MLINK: return -EMLINK; break; case NFS3ERR_NAMETOOLONG: return -ENAMETOOLONG; break; - case NFS3ERR_NOTEMPTY: return -EEXIST; break; + case NFS3ERR_NOTEMPTY: return -ENOTEMPTY; break; case NFS3ERR_DQUOT: return -ERANGE; break; case NFS3ERR_STALE: return -EIO; break; case NFS3ERR_REMOTE: return -EIO; break; @@ -697,7 +697,7 @@ int rpc_nfs_readdirplus_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 args.cookie = cookie; memcpy(&args.cookieverf, cookieverf, sizeof(cookieverf3)); args.dircount = count; - args.maxcount = count; + args.maxcount = count * 8; return rpc_nfs3_readdirplus_async(rpc, cb, &args, private_data); } diff --git a/nfs/nfs.x b/nfs/nfs.x index ca48c03..ab874a0 100644 --- a/nfs/nfs.x +++ b/nfs/nfs.x @@ -37,7 +37,7 @@ const NFS3_COOKIEVERFSIZE = 8; typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE]; -typedef u_quad_t cookie3; +typedef uint64_t cookie3; struct nfs_fh3 { opaque data; @@ -66,9 +66,9 @@ typedef unsigned int uid3; typedef unsigned int gid3; -typedef u_quad_t size3; +typedef uint64_t size3; -typedef u_quad_t fileid3; +typedef uint64_t fileid3; struct specdata3 { unsigned int specdata1; @@ -89,7 +89,7 @@ struct fattr3 { size3 size; size3 used; specdata3 rdev; - u_quad_t fsid; + uint64_t fsid; fileid3 fileid; nfstime3 atime; nfstime3 mtime; @@ -142,7 +142,7 @@ enum stable_how { FILE_SYNC = 2 }; -typedef u_quad_t offset3; +typedef uint64_t offset3; typedef unsigned int count3; diff --git a/nlm/libnfs-raw-nlm.c b/nlm/libnfs-raw-nlm.c index ccb2c82..40d70f6 100644 --- a/nlm/libnfs-raw-nlm.c +++ b/nlm/libnfs-raw-nlm.c @@ -91,9 +91,9 @@ zdr_nlm4_holder (ZDR *zdrs, nlm4_holder *objp) return FALSE; if (!zdr_nlm4_oh (zdrs, &objp->oh)) return FALSE; - if (!zdr_u_quad_t (zdrs, &objp->l_offset)) + if (!zdr_uint64_t (zdrs, &objp->l_offset)) return FALSE; - if (!zdr_u_quad_t (zdrs, &objp->l_len)) + if (!zdr_uint64_t (zdrs, &objp->l_len)) return FALSE; return TRUE; } @@ -112,9 +112,9 @@ zdr_nlm4_lock (ZDR *zdrs, nlm4_lock *objp) return FALSE; if (!zdr_u_int (zdrs, &objp->svid)) return FALSE; - if (!zdr_u_quad_t (zdrs, &objp->l_offset)) + if (!zdr_uint64_t (zdrs, &objp->l_offset)) return FALSE; - if (!zdr_u_quad_t (zdrs, &objp->l_len)) + if (!zdr_uint64_t (zdrs, &objp->l_len)) return FALSE; return TRUE; } diff --git a/nlm/libnfs-raw-nlm.h b/nlm/libnfs-raw-nlm.h index ce85259..53635f5 100644 --- a/nlm/libnfs-raw-nlm.h +++ b/nlm/libnfs-raw-nlm.h @@ -79,8 +79,8 @@ struct nlm4_holder { uint32_t exclusive; u_int svid; nlm4_oh oh; - u_quad_t l_offset; - u_quad_t l_len; + uint64_t l_offset; + uint64_t l_len; }; typedef struct nlm4_holder nlm4_holder; #define NLM_MAXNAME 256 @@ -90,8 +90,8 @@ struct nlm4_lock { struct nlm_fh4 fh; nlm4_oh oh; u_int svid; - u_quad_t l_offset; - u_quad_t l_len; + uint64_t l_offset; + uint64_t l_len; }; typedef struct nlm4_lock nlm4_lock; diff --git a/nlm/nlm.x b/nlm/nlm.x index 6cd39c2..072aa99 100644 --- a/nlm/nlm.x +++ b/nlm/nlm.x @@ -54,8 +54,8 @@ struct nlm4_holder { bool exclusive; unsigned int svid; nlm4_oh oh; - u_quad_t l_offset; - u_quad_t l_len; + uint64_t l_offset; + uint64_t l_len; }; const NLM_MAXNAME = 256; @@ -64,8 +64,8 @@ struct nlm4_lock { struct nlm_fh4 fh; nlm4_oh oh; unsigned int svid; - u_quad_t l_offset; - u_quad_t l_len; + uint64_t l_offset; + uint64_t l_len; }; struct nlm4_share { diff --git a/packaging/RPM/libnfs.spec.in b/packaging/RPM/libnfs.spec.in index 0535743..35e3825 100644 --- a/packaging/RPM/libnfs.spec.in +++ b/packaging/RPM/libnfs.spec.in @@ -108,6 +108,15 @@ Utility programs for LibNFS %{_mandir}/man1/nfs-ls.1.gz %changelog +* Tue Nov 25 2014 : Version 1.9.6 + - Add O_TRUNC support for nfs_create + - Handle OOM during create + - Return more stats fields as part of readdir since we get these for "free" + when we use READDIRPLUS + - Follow symlinks during path resolution + - Add lchown, lstat and lutimes + - Replace all [u_]quad types with [u]int types in our RPC layer + - Solaris build fixes * Sat Jul 19 2014 : Version 1.9.5 - Remove old ONC-RPC symbols * Wed Mar 19 2014 : Version 1.9.3