]> asedeno.scripts.mit.edu Git - linux.git/blob - fs/afs/xattr.c
31db360947a6b6168c8204eb9bcfb898f8353ddb
[linux.git] / fs / afs / xattr.c
1 /* Extended attribute handling for AFS.  We use xattrs to get and set metadata
2  * instead of providing pioctl().
3  *
4  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public Licence
9  * as published by the Free Software Foundation; either version
10  * 2 of the Licence, or (at your option) any later version.
11  */
12
13 #include <linux/slab.h>
14 #include <linux/fs.h>
15 #include <linux/xattr.h>
16 #include "internal.h"
17
18 static const char afs_xattr_list[] =
19         "afs.acl\0"
20         "afs.cell\0"
21         "afs.fid\0"
22         "afs.volume";
23
24 /*
25  * Retrieve a list of the supported xattrs.
26  */
27 ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
28 {
29         if (size == 0)
30                 return sizeof(afs_xattr_list);
31         if (size < sizeof(afs_xattr_list))
32                 return -ERANGE;
33         memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list));
34         return sizeof(afs_xattr_list);
35 }
36
37 /*
38  * Get a file's ACL.
39  */
40 static int afs_xattr_get_acl(const struct xattr_handler *handler,
41                              struct dentry *dentry,
42                              struct inode *inode, const char *name,
43                              void *buffer, size_t size)
44 {
45         struct afs_fs_cursor fc;
46         struct afs_vnode *vnode = AFS_FS_I(inode);
47         struct afs_acl *acl = NULL;
48         struct key *key;
49         int ret;
50
51         key = afs_request_key(vnode->volume->cell);
52         if (IS_ERR(key))
53                 return PTR_ERR(key);
54
55         ret = -ERESTARTSYS;
56         if (afs_begin_vnode_operation(&fc, vnode, key)) {
57                 while (afs_select_fileserver(&fc)) {
58                         fc.cb_break = afs_calc_vnode_cb_break(vnode);
59                         acl = afs_fs_fetch_acl(&fc);
60                 }
61
62                 afs_check_for_remote_deletion(&fc, fc.vnode);
63                 afs_vnode_commit_status(&fc, vnode, fc.cb_break);
64                 ret = afs_end_vnode_operation(&fc);
65         }
66
67         if (ret == 0) {
68                 ret = acl->size;
69                 if (size > 0) {
70                         ret = -ERANGE;
71                         if (acl->size > size)
72                                 return -ERANGE;
73                         memcpy(buffer, acl->data, acl->size);
74                         ret = acl->size;
75                 }
76                 kfree(acl);
77         }
78
79         key_put(key);
80         return ret;
81 }
82
83 /*
84  * Set a file's AFS3 ACL.
85  */
86 static int afs_xattr_set_acl(const struct xattr_handler *handler,
87                              struct dentry *dentry,
88                              struct inode *inode, const char *name,
89                              const void *buffer, size_t size, int flags)
90 {
91         struct afs_fs_cursor fc;
92         struct afs_vnode *vnode = AFS_FS_I(inode);
93         struct afs_acl *acl = NULL;
94         struct key *key;
95         int ret;
96
97         if (flags == XATTR_CREATE)
98                 return -EINVAL;
99
100         key = afs_request_key(vnode->volume->cell);
101         if (IS_ERR(key))
102                 return PTR_ERR(key);
103
104         acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
105         if (!acl) {
106                 key_put(key);
107                 return -ENOMEM;
108         }
109
110         acl->size = size;
111         memcpy(acl->data, buffer, size);
112
113         ret = -ERESTARTSYS;
114         if (afs_begin_vnode_operation(&fc, vnode, key)) {
115                 while (afs_select_fileserver(&fc)) {
116                         fc.cb_break = afs_calc_vnode_cb_break(vnode);
117                         afs_fs_store_acl(&fc, acl);
118                 }
119
120                 afs_check_for_remote_deletion(&fc, fc.vnode);
121                 afs_vnode_commit_status(&fc, vnode, fc.cb_break);
122                 ret = afs_end_vnode_operation(&fc);
123         }
124
125         kfree(acl);
126         key_put(key);
127         return ret;
128 }
129
130 static const struct xattr_handler afs_xattr_afs_acl_handler = {
131         .name   = "afs.acl",
132         .get    = afs_xattr_get_acl,
133         .set    = afs_xattr_set_acl,
134 };
135
136 /*
137  * Get the name of the cell on which a file resides.
138  */
139 static int afs_xattr_get_cell(const struct xattr_handler *handler,
140                               struct dentry *dentry,
141                               struct inode *inode, const char *name,
142                               void *buffer, size_t size)
143 {
144         struct afs_vnode *vnode = AFS_FS_I(inode);
145         struct afs_cell *cell = vnode->volume->cell;
146         size_t namelen;
147
148         namelen = cell->name_len;
149         if (size == 0)
150                 return namelen;
151         if (namelen > size)
152                 return -ERANGE;
153         memcpy(buffer, cell->name, namelen);
154         return namelen;
155 }
156
157 static const struct xattr_handler afs_xattr_afs_cell_handler = {
158         .name   = "afs.cell",
159         .get    = afs_xattr_get_cell,
160 };
161
162 /*
163  * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
164  * hex numbers separated by colons.
165  */
166 static int afs_xattr_get_fid(const struct xattr_handler *handler,
167                              struct dentry *dentry,
168                              struct inode *inode, const char *name,
169                              void *buffer, size_t size)
170 {
171         struct afs_vnode *vnode = AFS_FS_I(inode);
172         char text[16 + 1 + 24 + 1 + 8 + 1];
173         size_t len;
174
175         /* The volume ID is 64-bit, the vnode ID is 96-bit and the
176          * uniquifier is 32-bit.
177          */
178         len = sprintf(text, "%llx:", vnode->fid.vid);
179         if (vnode->fid.vnode_hi)
180                 len += sprintf(text + len, "%x%016llx",
181                                vnode->fid.vnode_hi, vnode->fid.vnode);
182         else
183                 len += sprintf(text + len, "%llx", vnode->fid.vnode);
184         len += sprintf(text + len, ":%x", vnode->fid.unique);
185
186         if (size == 0)
187                 return len;
188         if (len > size)
189                 return -ERANGE;
190         memcpy(buffer, text, len);
191         return len;
192 }
193
194 static const struct xattr_handler afs_xattr_afs_fid_handler = {
195         .name   = "afs.fid",
196         .get    = afs_xattr_get_fid,
197 };
198
199 /*
200  * Get the name of the volume on which a file resides.
201  */
202 static int afs_xattr_get_volume(const struct xattr_handler *handler,
203                               struct dentry *dentry,
204                               struct inode *inode, const char *name,
205                               void *buffer, size_t size)
206 {
207         struct afs_vnode *vnode = AFS_FS_I(inode);
208         const char *volname = vnode->volume->name;
209         size_t namelen;
210
211         namelen = strlen(volname);
212         if (size == 0)
213                 return namelen;
214         if (namelen > size)
215                 return -ERANGE;
216         memcpy(buffer, volname, namelen);
217         return namelen;
218 }
219
220 static const struct xattr_handler afs_xattr_afs_volume_handler = {
221         .name   = "afs.volume",
222         .get    = afs_xattr_get_volume,
223 };
224
225 const struct xattr_handler *afs_xattr_handlers[] = {
226         &afs_xattr_afs_acl_handler,
227         &afs_xattr_afs_cell_handler,
228         &afs_xattr_afs_fid_handler,
229         &afs_xattr_afs_volume_handler,
230         NULL
231 };