diff mbox series

[v2,111/118] NFSD: Add an xdr_stream-based decoder for NFSv2/3 ACLs

Message ID 160590501674.1340.17812051346945067469.stgit@klimt.1015granger.net (mailing list archive)
State New, archived
Headers show
Series Update NFSD XDR functions | expand

Commit Message

Chuck Lever Nov. 20, 2020, 8:43 p.m. UTC
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfs_common/nfsacl.c |   53 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/nfsacl.h |    3 +++
 2 files changed, 56 insertions(+)
diff mbox series

Patch

diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c
index d056ad2fdefd..e2ec0f241a4f 100644
--- a/fs/nfs_common/nfsacl.c
+++ b/fs/nfs_common/nfsacl.c
@@ -295,3 +295,56 @@  int nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
 		   nfsacl_desc.desc.array_len;
 }
 EXPORT_SYMBOL_GPL(nfsacl_decode);
+
+/**
+ * nfs_stream_decode_acl - Decode an NFSv3 ACL
+ *
+ * @xdr: an xdr_stream positioned at an encoded ACL
+ * @aclcnt: OUT: count of ACEs in decoded posix_acl
+ * @pacl: OUT: a dynamically-allocated buffer containing the decoded posix_acl
+ *
+ * Return values:
+ *   %XDR_DECODE_FAILED: The encoded ACL is not valid
+ *   %XDR_DECODE_DONE: @pacl contains a decoded ACL, and @xdr is advanced
+ *
+ * On a successful return, caller must release *pacl using posix_acl_release().
+ */
+enum xdr_decode_result
+nfs_stream_decode_acl(struct xdr_stream *xdr, unsigned int *aclcnt,
+		      struct posix_acl **pacl)
+{
+	const size_t elem_size = sizeof(__be32) * 3;
+	struct nfsacl_decode_desc nfsacl_desc = {
+		.desc = {
+			.elem_size = elem_size,
+			.xcode = pacl ? xdr_nfsace_decode : NULL,
+		},
+	};
+	unsigned int base;
+	u32 entries;
+
+	if (xdr_stream_decode_u32(xdr, &entries) < 0)
+		return XDR_DECODE_FAILED;
+	if (entries > NFS_ACL_MAX_ENTRIES)
+		return XDR_DECODE_FAILED;
+
+	base = xdr_stream_pos(xdr);
+	if (!xdr_inline_decode(xdr, sizeof(__be32) + elem_size * entries))
+		return XDR_DECODE_FAILED;
+	nfsacl_desc.desc.array_maxlen = entries;
+	if (xdr_decode_array2(xdr->buf, base, &nfsacl_desc.desc))
+		return XDR_DECODE_FAILED;
+
+	if (pacl) {
+		if (entries != nfsacl_desc.desc.array_len ||
+		    posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) {
+			posix_acl_release(nfsacl_desc.acl);
+			return XDR_DECODE_FAILED;
+		}
+		*pacl = nfsacl_desc.acl;
+	}
+	if (aclcnt)
+		*aclcnt = entries;
+	return XDR_DECODE_DONE;
+}
+EXPORT_SYMBOL_GPL(nfs_stream_decode_acl);
diff --git a/include/linux/nfsacl.h b/include/linux/nfsacl.h
index 103d44695323..434471cc4b62 100644
--- a/include/linux/nfsacl.h
+++ b/include/linux/nfsacl.h
@@ -38,5 +38,8 @@  nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
 extern int
 nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
 	      struct posix_acl **pacl);
+extern enum xdr_decode_result
+nfs_stream_decode_acl(struct xdr_stream *xdr, unsigned int *aclcnt,
+		      struct posix_acl **pacl);
 
 #endif  /* __LINUX_NFSACL_H */