diff --git a/examples/nfs-io.c b/examples/nfs-io.c index 6b7008b..bfa11c0 100644 --- a/examples/nfs-io.c +++ b/examples/nfs-io.c @@ -55,6 +55,7 @@ WSADATA wsaData; #include "../include/nfsc/libnfs.h" #include "../include/nfsc/libnfs-raw.h" #include "../mount/libnfs-raw-mount.h" +#include "../nfs4/libnfs-raw-nfs4.h" void print_usage(void) { @@ -67,6 +68,8 @@ int main(int argc, char *argv[]) struct nfs_context *nfs = NULL; struct nfsfh *nfsfh = NULL; struct nfs_url *url = NULL; + fattr4_acl acl4; + int i; #ifdef WIN32 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { @@ -179,6 +182,32 @@ int main(int argc, char *argv[]) printf(" mtime: %lu %lu", st.nfs_mtime, st.nfs_mtime_nsec); printf("\n"); } + } else if (!strncmp(argv[1], "acl", 3)) { + printf("ACL version:%d\n", nfs_get_version(nfs)); + if (nfs_get_version(nfs) != NFS_V4) { + printf("acl support only for nfsv4 for now\n"); + goto finished; + } + + /* NFS_V4 */ + ret = nfs_open(nfs, url->file, 0600, &nfsfh); + if (ret != 0) { + printf("failed to open %s\n", url->file); + goto finished; + } + if (nfs4_getacl(nfs, nfsfh, &acl4)) { + printf("Failed to read ACLs %s\n", nfs_get_error(nfs)); + goto finished; + } + for (i = 0; i < acl4.fattr4_acl_len; i++) { + printf("Type:%d Flag:%d Mask:0x%08x Who:%s\n", + acl4.fattr4_acl_val[i].type, + acl4.fattr4_acl_val[i].flag, + acl4.fattr4_acl_val[i].access_mask, + acl4.fattr4_acl_val[i].who.utf8string_val); + } + nfs4_acl_free(&acl4); + ret = 0; } else { goto finished; } diff --git a/include/nfsc/libnfs.h b/include/nfsc/libnfs.h index 31dcd99..17b2c54 100755 --- a/include/nfsc/libnfs.h +++ b/include/nfsc/libnfs.h @@ -275,6 +275,12 @@ EXTERN void nfs_set_autoreconnect(struct nfs_context *nfs, int num_retries); * NFS_V4 */ EXTERN int nfs_set_version(struct nfs_context *nfs, int version); +/* + * Get NFS version of a connected share. Supported versions are + * NFS_V3 + * NFS_V4 + */ +EXTERN int nfs_get_version(struct nfs_context *nfs); /* * Invalidate the pagecache diff --git a/lib/libnfs-sync.c b/lib/libnfs-sync.c index b1489af..34719d5 100644 --- a/lib/libnfs-sync.c +++ b/lib/libnfs-sync.c @@ -100,6 +100,7 @@ #include "libnfs-raw.h" #include "libnfs-raw-mount.h" #include "libnfs-raw-nfs.h" +#include "libnfs-raw-nfs4.h" #include "libnfs-private.h" struct sync_cb_data { @@ -1850,6 +1851,81 @@ nfs_link(struct nfs_context *nfs, const char *oldpath, const char *newpath) return cb_data.status; } + +/* + * nfs4_getacl() + */ +void nfs4_acl_free(fattr4_acl *acl) +{ + int i; + + for (i = 0; i < acl->fattr4_acl_len; i++) { + free(acl->fattr4_acl_val[i].who.utf8string_val); + } + free(acl->fattr4_acl_val); +} + +static void +nfs4_getacl_cb(int status, struct nfs_context *nfs, void *data, void *private_data) +{ + struct sync_cb_data *cb_data = private_data; + fattr4_acl *src = data; + fattr4_acl *dst = cb_data->return_data; + int i; + + cb_data->is_finished = 1; + cb_data->status = status; + + if (status < 0) { + nfs_set_error(nfs, "getacl call failed with \"%s\"", + (char *)data); + return; + } + dst->fattr4_acl_len = src->fattr4_acl_len; + dst->fattr4_acl_val = calloc(dst->fattr4_acl_len, sizeof(nfsace4)); + if (dst->fattr4_acl_val == NULL) { + cb_data->status = -ENOMEM; + nfs_set_error(nfs, "Failed to allocate fattr4_acl_val"); + return; + } + for (i = 0; i < dst->fattr4_acl_len; i++) { + dst->fattr4_acl_val[i].type = src->fattr4_acl_val[i].type; + dst->fattr4_acl_val[i].flag = src->fattr4_acl_val[i].flag; + dst->fattr4_acl_val[i].access_mask = src->fattr4_acl_val[i].access_mask; + dst->fattr4_acl_val[i].who.utf8string_len = src->fattr4_acl_val[i].who.utf8string_len; + dst->fattr4_acl_val[i].who.utf8string_val = calloc(dst->fattr4_acl_val[i].who.utf8string_len + 1, 1); + if (dst->fattr4_acl_val[i].who.utf8string_val == NULL) { + cb_data->status = -ENOMEM; + nfs4_acl_free(dst); + nfs_set_error(nfs, "Failed to allocate acl name"); + return; + } + memcpy(dst->fattr4_acl_val[i].who.utf8string_val, + src->fattr4_acl_val[i].who.utf8string_val, + dst->fattr4_acl_val[i].who.utf8string_len); + } +} + +int +nfs4_getacl(struct nfs_context *nfs, struct nfsfh *nfsfh, + fattr4_acl *acl) +{ + struct sync_cb_data cb_data; + + cb_data.is_finished = 0; + cb_data.return_data = acl; + + if (nfs4_getacl_async(nfs, nfsfh, nfs4_getacl_cb, &cb_data) != 0) { + nfs_set_error(nfs, "nfs_getacl_async failed. %s", + nfs_get_error(nfs)); + return -1; + } + + wait_for_nfs_reply(nfs, &cb_data); + + return cb_data.status; +} + void mount_getexports_cb(struct rpc_context *mount_context, int status, void *data, void *private_data) diff --git a/lib/libnfs-win32.def b/lib/libnfs-win32.def index f38ebe6..245d1f8 100644 --- a/lib/libnfs-win32.def +++ b/lib/libnfs-win32.def @@ -35,6 +35,7 @@ nfs_get_fd nfs_get_readmax nfs_get_writemax nfs_getcwd +nfs_get_version nfs_get_timeout nfs_init_context nfs_link @@ -118,6 +119,9 @@ nfsstat4_to_errno nfsstat4_to_str nfs4_set_client_name nfs4_set_verifier +nfs4_acl_free +nfs4_getacl +nfs4_getacl_async win32_poll rpc_connect_async rpc_connect_port_async diff --git a/lib/libnfs.c b/lib/libnfs.c index 9ea499a..9c8045b 100755 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -1848,6 +1848,11 @@ nfs_set_version(struct nfs_context *nfs, int version) { return 0; } +int +nfs_get_version(struct nfs_context *nfs) { + return nfs->version; +} + void nfs_set_error(struct nfs_context *nfs, char *error_string, ...) { diff --git a/lib/nfs_v4.c b/lib/nfs_v4.c index 7c21e2b..449223e 100644 --- a/lib/nfs_v4.c +++ b/lib/nfs_v4.c @@ -99,6 +99,7 @@ #include "slist.h" #include "libnfs.h" #include "libnfs-raw.h" +#include "libnfs-raw-nfs4.h" #include "libnfs-private.h" #ifndef discard_const @@ -193,6 +194,10 @@ static uint32_t statvfs_attributes[2] = { 1 << (FATTR4_SPACE_TOTAL - 32)) }; +static uint32_t getacl_attributes[1] = { + (1 << FATTR4_ACL ) +}; + static int nfs4_open_async_internal(struct nfs_context *nfs, struct nfs4_cb_data *data, int flags, int mode); @@ -2530,6 +2535,86 @@ nfs4_fstat64_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, return 0; } +static void +nfs4_getacl_cb(struct rpc_context *rpc, int status, void *command_data, + void *private_data) +{ + struct nfs4_cb_data *data = private_data; + struct nfs_context *nfs = data->nfs; + COMPOUND4res *res = command_data; + GETATTR4resok *garesok; + fattr4_acl acl; + ZDR zdr; + int i; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + if (check_nfs4_error(nfs, status, data, res, "GETACL")) { + data->cb(-EIO, nfs, "GETACL failed", data->private_data); + free_nfs4_cb_data(data); + return; + } + + if ((i = nfs4_find_op(nfs, data, res, OP_GETATTR, "GETATTR")) < 0) { + data->cb(-EIO, nfs, "GETACL failed", data->private_data); + free_nfs4_cb_data(data); + return; + } + garesok = &res->resarray.resarray_val[i].nfs_resop4_u.opgetattr.GETATTR4res_u.resok4; + + memset(&acl, 0, sizeof(acl)); + zdrmem_create(&zdr, + garesok->obj_attributes.attr_vals.attrlist4_val, + garesok->obj_attributes.attr_vals.attrlist4_len, + ZDR_DECODE); + if (zdr_fattr4_acl(&zdr, &acl)) { + data->cb(0, nfs, &acl, data->private_data); + } else { + data->cb(-EIO, nfs, "Failed to unmarshall fattr4_acl", data->private_data); + } + + zdr_destroy(&zdr); + free_nfs4_cb_data(data); +} + +int +nfs4_getacl_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, + void *private_data) +{ + COMPOUND4args args; + nfs_argop4 op[2]; + struct nfs4_cb_data *data; + int i; + + data = malloc(sizeof(*data)); + if (data == NULL) { + nfs_set_error(nfs, "Out of memory. Failed to allocate " + "cb data"); + return -1; + } + memset(data, 0, sizeof(*data)); + + data->nfs = nfs; + data->cb = cb; + data->private_data = private_data; + + i = nfs4_op_putfh(nfs, &op[0], nfsfh); + i += nfs4_op_getattr(nfs, &op[i], getacl_attributes, 1); + + memset(&args, 0, sizeof(args)); + args.argarray.argarray_len = i; + args.argarray.argarray_val = op; + + if (rpc_nfs4_compound_async(nfs->rpc, nfs4_getacl_cb, &args, + data) != 0) { + free_nfs4_cb_data(data); + return -1; + } + + return 0; +} + + static void nfs4_close_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) diff --git a/nfs4/libnfs-raw-nfs4.h b/nfs4/libnfs-raw-nfs4.h index fdb85e1..74d0cb7 100644 --- a/nfs4/libnfs-raw-nfs4.h +++ b/nfs4/libnfs-raw-nfs4.h @@ -2754,3 +2754,46 @@ extern uint32_t zdr_CB_COMPOUND4res (); #endif #endif /* !_NFS4_H_RPCGEN */ +#include + +#if defined(WIN32) && defined(libnfs_EXPORTS) +#define EXTERN __declspec( dllexport ) +#else +#ifndef EXTERN +#define EXTERN +#endif +#endif + +/* + * NFSv4 ACL + */ +/* + * Async nfs4 get acl + * Function returns + * 0 : The command was queued successfully. The callback will be invoked once + * the command completes. + * <0 : An error occured when trying to queue the command. + * The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * 0 : Success. + * data is fattr4_acl * + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs4_getacl_async(struct nfs_context *nfs, struct nfsfh *nfsfh, + nfs_cb cb, void *private_data); + +/* + * Sync nfs4 get acl + * Function returns + * 0 : The operation was successful. + * -errno : The command failed. + * + * If the command was successful, the returned data in nfs4acl must be freed + * by calling nfs4_acl_free() + */ +EXTERN int nfs4_getacl(struct nfs_context *nfs, struct nfsfh *nfsfh, + fattr4_acl *nfs4acl); + +EXTERN void nfs4_acl_free(fattr4_acl *nfs4acl); diff --git a/nfs4/libnfs-raw-nfs4.h.extra b/nfs4/libnfs-raw-nfs4.h.extra new file mode 100644 index 0000000..ca605dd --- /dev/null +++ b/nfs4/libnfs-raw-nfs4.h.extra @@ -0,0 +1,43 @@ +#include + +#if defined(WIN32) && defined(libnfs_EXPORTS) +#define EXTERN __declspec( dllexport ) +#else +#ifndef EXTERN +#define EXTERN +#endif +#endif + +/* + * NFSv4 ACL + */ +/* + * Async nfs4 get acl + * Function returns + * 0 : The command was queued successfully. The callback will be invoked once + * the command completes. + * <0 : An error occured when trying to queue the command. + * The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * 0 : Success. + * data is fattr4_acl * + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs4_getacl_async(struct nfs_context *nfs, struct nfsfh *nfsfh, + nfs_cb cb, void *private_data); + +/* + * Sync nfs4 get acl + * Function returns + * 0 : The operation was successful. + * -errno : The command failed. + * + * If the command was successful, the returned data in nfs4acl must be freed + * by calling nfs4_acl_free() + */ +EXTERN int nfs4_getacl(struct nfs_context *nfs, struct nfsfh *nfsfh, + fattr4_acl *nfs4acl); + +EXTERN void nfs4_acl_free(fattr4_acl *nfs4acl); diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 95f4c38..7e84f2f 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -1,7 +1,7 @@ -set(UTILITIES nfs-cat nfs-ls nfs-stat) +set(UTILITIES nfs-cat nfs-ls) if(NOT CMAKE_SYSTEM_NAME STREQUAL Windows) - list(APPEND UTILITIES nfs-cp) + list(APPEND UTILITIES nfs-cp nfs-stat) endif() foreach(TARGET ${UTILITIES}) diff --git a/utils/Makefile.am b/utils/Makefile.am index 11d8d27..be472e1 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -1,7 +1,7 @@ -bin_PROGRAMS = nfs-cat nfs-ls nfs-stat +bin_PROGRAMS = nfs-cat nfs-ls if !HAVE_WIN32 -bin_PROGRAMS += nfs-cp +bin_PROGRAMS += nfs-cp nfs-stat endif AM_CPPFLAGS = \