Merge tag 'nfs-for-5.18-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[linux-block.git] / fs / xfs / xfs_xattr.c
CommitLineData
0b61f8a4 1// SPDX-License-Identifier: GPL-2.0
f9e09f09
LM
2/*
3 * Copyright (C) 2008 Christoph Hellwig.
4 * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
f9e09f09
LM
5 */
6
7#include "xfs.h"
5467b34b 8#include "xfs_shared.h"
a4fbe6ab 9#include "xfs_format.h"
69432832 10#include "xfs_log_format.h"
57062787 11#include "xfs_da_format.h"
383e32b0
DW
12#include "xfs_trans_resv.h"
13#include "xfs_mount.h"
f9e09f09
LM
14#include "xfs_inode.h"
15#include "xfs_attr.h"
5f213ddb 16#include "xfs_acl.h"
a2544622 17#include "xfs_da_btree.h"
f9e09f09
LM
18
19#include <linux/posix_acl_xattr.h>
f9e09f09
LM
20
21
f9e09f09 22static int
b296821a
AV
23xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
24 struct inode *inode, const char *name, void *value, size_t size)
f9e09f09 25{
e5171d7e
CH
26 struct xfs_da_args args = {
27 .dp = XFS_I(inode),
d5f0f49a 28 .attr_filter = handler->flags,
e5171d7e
CH
29 .name = name,
30 .namelen = strlen(name),
31 .value = value,
32 .valuelen = size,
33 };
34 int error;
f9e09f09 35
e5171d7e 36 error = xfs_attr_get(&args);
f9e09f09
LM
37 if (error)
38 return error;
e5171d7e 39 return args.valuelen;
f9e09f09
LM
40}
41
42static int
e65ce2a5
CB
43xfs_xattr_set(const struct xattr_handler *handler,
44 struct user_namespace *mnt_userns, struct dentry *unused,
45 struct inode *inode, const char *name, const void *value,
46 size_t size, int flags)
f9e09f09 47{
a2544622
CH
48 struct xfs_da_args args = {
49 .dp = XFS_I(inode),
d5f0f49a
CH
50 .attr_filter = handler->flags,
51 .attr_flags = flags,
a2544622
CH
52 .name = name,
53 .namelen = strlen(name),
54 .value = (void *)value,
55 .valuelen = size,
56 };
67d8e04e 57 int error;
f9e09f09 58
a2544622 59 error = xfs_attr_set(&args);
d5f0f49a 60 if (!error && (handler->flags & XFS_ATTR_ROOT))
5a3930e2 61 xfs_forget_acl(inode, name);
67d8e04e 62 return error;
f9e09f09
LM
63}
64
46e58764 65static const struct xattr_handler xfs_xattr_user_handler = {
f9e09f09 66 .prefix = XATTR_USER_PREFIX,
431547b3
CH
67 .flags = 0, /* no flags implies user namespace */
68 .get = xfs_xattr_get,
69 .set = xfs_xattr_set,
f9e09f09
LM
70};
71
46e58764 72static const struct xattr_handler xfs_xattr_trusted_handler = {
f9e09f09 73 .prefix = XATTR_TRUSTED_PREFIX,
d5f0f49a 74 .flags = XFS_ATTR_ROOT,
431547b3
CH
75 .get = xfs_xattr_get,
76 .set = xfs_xattr_set,
f9e09f09
LM
77};
78
46e58764 79static const struct xattr_handler xfs_xattr_security_handler = {
f9e09f09 80 .prefix = XATTR_SECURITY_PREFIX,
d5f0f49a 81 .flags = XFS_ATTR_SECURE,
431547b3
CH
82 .get = xfs_xattr_get,
83 .set = xfs_xattr_set,
f9e09f09
LM
84};
85
46e58764 86const struct xattr_handler *xfs_xattr_handlers[] = {
f9e09f09
LM
87 &xfs_xattr_user_handler,
88 &xfs_xattr_trusted_handler,
89 &xfs_xattr_security_handler,
ef14f0c1 90#ifdef CONFIG_XFS_POSIX_ACL
2401dc29
CH
91 &posix_acl_access_xattr_handler,
92 &posix_acl_default_xattr_handler,
ef14f0c1 93#endif
f9e09f09
LM
94 NULL
95};
96
f7a136ae 97static void
5d92b75c 98__xfs_xattr_put_listent(
a9273ca5 99 struct xfs_attr_list_context *context,
5d92b75c
AG
100 char *prefix,
101 int prefix_len,
102 unsigned char *name,
103 int namelen)
f9e09f09 104{
f9e09f09
LM
105 char *offset;
106 int arraytop;
107
3b50086f
DW
108 if (context->count < 0 || context->seen_enough)
109 return;
110
a9c8c69b 111 if (!context->buffer)
5d92b75c 112 goto compute_size;
f9e09f09
LM
113
114 arraytop = context->count + prefix_len + namelen + 1;
115 if (arraytop > context->firstu) {
116 context->count = -1; /* insufficient space */
791cc43b 117 context->seen_enough = 1;
f7a136ae 118 return;
f9e09f09 119 }
a9c8c69b 120 offset = context->buffer + context->count;
5d92b75c 121 strncpy(offset, prefix, prefix_len);
f9e09f09 122 offset += prefix_len;
a9273ca5 123 strncpy(offset, (char *)name, namelen); /* real name */
f9e09f09
LM
124 offset += namelen;
125 *offset = '\0';
5d92b75c
AG
126
127compute_size:
f9e09f09 128 context->count += prefix_len + namelen + 1;
f7a136ae 129 return;
f9e09f09
LM
130}
131
f7a136ae 132static void
5d92b75c 133xfs_xattr_put_listent(
a9273ca5
DC
134 struct xfs_attr_list_context *context,
135 int flags,
136 unsigned char *name,
137 int namelen,
e5bd12bf 138 int valuelen)
f9e09f09 139{
5d92b75c
AG
140 char *prefix;
141 int prefix_len;
f9e09f09 142
5d92b75c 143 ASSERT(context->count >= 0);
f9e09f09 144
5d92b75c
AG
145 if (flags & XFS_ATTR_ROOT) {
146#ifdef CONFIG_XFS_POSIX_ACL
147 if (namelen == SGI_ACL_FILE_SIZE &&
148 strncmp(name, SGI_ACL_FILE,
149 SGI_ACL_FILE_SIZE) == 0) {
f7a136ae 150 __xfs_xattr_put_listent(
5d92b75c
AG
151 context, XATTR_SYSTEM_PREFIX,
152 XATTR_SYSTEM_PREFIX_LEN,
153 XATTR_POSIX_ACL_ACCESS,
154 strlen(XATTR_POSIX_ACL_ACCESS));
5d92b75c
AG
155 } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
156 strncmp(name, SGI_ACL_DEFAULT,
157 SGI_ACL_DEFAULT_SIZE) == 0) {
f7a136ae 158 __xfs_xattr_put_listent(
5d92b75c
AG
159 context, XATTR_SYSTEM_PREFIX,
160 XATTR_SYSTEM_PREFIX_LEN,
161 XATTR_POSIX_ACL_DEFAULT,
162 strlen(XATTR_POSIX_ACL_DEFAULT));
5d92b75c
AG
163 }
164#endif
f9e09f09 165
5d92b75c
AG
166 /*
167 * Only show root namespace entries if we are actually allowed to
168 * see them.
169 */
170 if (!capable(CAP_SYS_ADMIN))
f7a136ae 171 return;
5d92b75c
AG
172
173 prefix = XATTR_TRUSTED_PREFIX;
174 prefix_len = XATTR_TRUSTED_PREFIX_LEN;
175 } else if (flags & XFS_ATTR_SECURE) {
176 prefix = XATTR_SECURITY_PREFIX;
177 prefix_len = XATTR_SECURITY_PREFIX_LEN;
178 } else {
179 prefix = XATTR_USER_PREFIX;
180 prefix_len = XATTR_USER_PREFIX_LEN;
181 }
182
f7a136ae
ES
183 __xfs_xattr_put_listent(context, prefix, prefix_len, name,
184 namelen);
185 return;
f9e09f09
LM
186}
187
188ssize_t
2a6fba6d
ES
189xfs_vn_listxattr(
190 struct dentry *dentry,
191 char *data,
192 size_t size)
f9e09f09
LM
193{
194 struct xfs_attr_list_context context;
2a6fba6d
ES
195 struct inode *inode = d_inode(dentry);
196 int error;
f9e09f09
LM
197
198 /*
199 * First read the regular on-disk attributes.
200 */
201 memset(&context, 0, sizeof(context));
202 context.dp = XFS_I(inode);
f9e09f09 203 context.resynch = 1;
a9c8c69b 204 context.buffer = size ? data : NULL;
f9e09f09
LM
205 context.bufsize = size;
206 context.firstu = context.bufsize;
5d92b75c 207 context.put_listent = xfs_xattr_put_listent;
f9e09f09 208
17e1dd83 209 error = xfs_attr_list(&context);
2a6fba6d
ES
210 if (error)
211 return error;
f9e09f09
LM
212 if (context.count < 0)
213 return -ERANGE;
214
f9e09f09
LM
215 return context.count;
216}