afs: Get an AFS3 ACL as an xattr
Implement an xattr on AFS files called "afs.acl" that retrieves a file's ACL. It returns the raw AFS3 ACL from the result of calling FS.FetchACL, leaving any interpretation to userspace. Note that whilst YFS servers will respond to FS.FetchACL, this will render a more-advanced YFS ACL down. Use "afs.yfs.acl" instead for that. Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
parent
a2f611a3dc
commit
260f082bae
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
enum AFS_FS_Operations {
|
enum AFS_FS_Operations {
|
||||||
FSFETCHDATA = 130, /* AFS Fetch file data */
|
FSFETCHDATA = 130, /* AFS Fetch file data */
|
||||||
|
FSFETCHACL = 131, /* AFS Fetch file ACL */
|
||||||
FSFETCHSTATUS = 132, /* AFS Fetch file status */
|
FSFETCHSTATUS = 132, /* AFS Fetch file status */
|
||||||
FSSTOREDATA = 133, /* AFS Store file data */
|
FSSTOREDATA = 133, /* AFS Store file data */
|
||||||
FSSTORESTATUS = 135, /* AFS Store file status */
|
FSSTORESTATUS = 135, /* AFS Store file status */
|
||||||
|
|
|
@ -2391,3 +2391,125 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
|
||||||
afs_make_call(&fc->ac, call, GFP_NOFS);
|
afs_make_call(&fc->ac, call, GFP_NOFS);
|
||||||
return afs_wait_for_call_to_complete(call, &fc->ac);
|
return afs_wait_for_call_to_complete(call, &fc->ac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* deliver reply data to an FS.FetchACL
|
||||||
|
*/
|
||||||
|
static int afs_deliver_fs_fetch_acl(struct afs_call *call)
|
||||||
|
{
|
||||||
|
struct afs_vnode *vnode = call->reply[1];
|
||||||
|
struct afs_acl *acl;
|
||||||
|
const __be32 *bp;
|
||||||
|
unsigned int size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
_enter("{%u}", call->unmarshall);
|
||||||
|
|
||||||
|
switch (call->unmarshall) {
|
||||||
|
case 0:
|
||||||
|
afs_extract_to_tmp(call);
|
||||||
|
call->unmarshall++;
|
||||||
|
|
||||||
|
/* extract the returned data length */
|
||||||
|
case 1:
|
||||||
|
ret = afs_extract_data(call, true);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
size = call->count2 = ntohl(call->tmp);
|
||||||
|
size = round_up(size, 4);
|
||||||
|
|
||||||
|
acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
|
||||||
|
if (!acl)
|
||||||
|
return -ENOMEM;
|
||||||
|
call->reply[0] = acl;
|
||||||
|
acl->size = call->count2;
|
||||||
|
afs_extract_begin(call, acl->data, size);
|
||||||
|
call->unmarshall++;
|
||||||
|
|
||||||
|
/* extract the returned data */
|
||||||
|
case 2:
|
||||||
|
ret = afs_extract_data(call, true);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
afs_extract_to_buf(call, (21 + 6) * 4);
|
||||||
|
call->unmarshall++;
|
||||||
|
|
||||||
|
/* extract the metadata */
|
||||||
|
case 3:
|
||||||
|
ret = afs_extract_data(call, false);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
bp = call->buffer;
|
||||||
|
ret = afs_decode_status(call, &bp, &vnode->status, vnode,
|
||||||
|
&vnode->status.data_version, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
xdr_decode_AFSVolSync(&bp, call->reply[2]);
|
||||||
|
|
||||||
|
call->unmarshall++;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_leave(" = 0 [done]");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void afs_destroy_fs_fetch_acl(struct afs_call *call)
|
||||||
|
{
|
||||||
|
kfree(call->reply[0]);
|
||||||
|
afs_flat_call_destructor(call);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FS.FetchACL operation type
|
||||||
|
*/
|
||||||
|
static const struct afs_call_type afs_RXFSFetchACL = {
|
||||||
|
.name = "FS.FetchACL",
|
||||||
|
.op = afs_FS_FetchACL,
|
||||||
|
.deliver = afs_deliver_fs_fetch_acl,
|
||||||
|
.destructor = afs_destroy_fs_fetch_acl,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch the ACL for a file.
|
||||||
|
*/
|
||||||
|
struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc)
|
||||||
|
{
|
||||||
|
struct afs_vnode *vnode = fc->vnode;
|
||||||
|
struct afs_call *call;
|
||||||
|
struct afs_net *net = afs_v2net(vnode);
|
||||||
|
__be32 *bp;
|
||||||
|
|
||||||
|
_enter(",%x,{%llx:%llu},,",
|
||||||
|
key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
|
||||||
|
|
||||||
|
call = afs_alloc_flat_call(net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
|
||||||
|
if (!call) {
|
||||||
|
fc->ac.error = -ENOMEM;
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
call->key = fc->key;
|
||||||
|
call->reply[0] = NULL;
|
||||||
|
call->reply[1] = vnode;
|
||||||
|
call->reply[2] = NULL; /* volsync */
|
||||||
|
call->ret_reply0 = true;
|
||||||
|
|
||||||
|
/* marshall the parameters */
|
||||||
|
bp = call->request;
|
||||||
|
bp[0] = htonl(FSFETCHACL);
|
||||||
|
bp[1] = htonl(vnode->fid.vid);
|
||||||
|
bp[2] = htonl(vnode->fid.vnode);
|
||||||
|
bp[3] = htonl(vnode->fid.unique);
|
||||||
|
|
||||||
|
call->cb_break = fc->cb_break;
|
||||||
|
afs_use_fs_server(call, fc->cbi);
|
||||||
|
trace_afs_make_fs_call(call, &vnode->fid);
|
||||||
|
afs_make_call(&fc->ac, call, GFP_KERNEL);
|
||||||
|
return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
|
||||||
|
}
|
||||||
|
|
|
@ -977,6 +977,13 @@ extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
|
||||||
struct afs_fid *, struct afs_file_status *,
|
struct afs_fid *, struct afs_file_status *,
|
||||||
struct afs_callback *, struct afs_volsync *);
|
struct afs_callback *, struct afs_volsync *);
|
||||||
|
|
||||||
|
struct afs_acl {
|
||||||
|
u32 size;
|
||||||
|
u8 data[];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fs_probe.c
|
* fs_probe.c
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
static const char afs_xattr_list[] =
|
static const char afs_xattr_list[] =
|
||||||
|
"afs.acl\0"
|
||||||
"afs.cell\0"
|
"afs.cell\0"
|
||||||
"afs.fid\0"
|
"afs.fid\0"
|
||||||
"afs.volume";
|
"afs.volume";
|
||||||
|
@ -33,6 +34,57 @@ ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||||
return sizeof(afs_xattr_list);
|
return sizeof(afs_xattr_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a file's ACL.
|
||||||
|
*/
|
||||||
|
static int afs_xattr_get_acl(const struct xattr_handler *handler,
|
||||||
|
struct dentry *dentry,
|
||||||
|
struct inode *inode, const char *name,
|
||||||
|
void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
struct afs_fs_cursor fc;
|
||||||
|
struct afs_vnode *vnode = AFS_FS_I(inode);
|
||||||
|
struct afs_acl *acl = NULL;
|
||||||
|
struct key *key;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
key = afs_request_key(vnode->volume->cell);
|
||||||
|
if (IS_ERR(key))
|
||||||
|
return PTR_ERR(key);
|
||||||
|
|
||||||
|
ret = -ERESTARTSYS;
|
||||||
|
if (afs_begin_vnode_operation(&fc, vnode, key)) {
|
||||||
|
while (afs_select_fileserver(&fc)) {
|
||||||
|
fc.cb_break = afs_calc_vnode_cb_break(vnode);
|
||||||
|
acl = afs_fs_fetch_acl(&fc);
|
||||||
|
}
|
||||||
|
|
||||||
|
afs_check_for_remote_deletion(&fc, fc.vnode);
|
||||||
|
afs_vnode_commit_status(&fc, vnode, fc.cb_break);
|
||||||
|
ret = afs_end_vnode_operation(&fc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = acl->size;
|
||||||
|
if (size > 0) {
|
||||||
|
ret = -ERANGE;
|
||||||
|
if (acl->size > size)
|
||||||
|
return -ERANGE;
|
||||||
|
memcpy(buffer, acl->data, acl->size);
|
||||||
|
ret = acl->size;
|
||||||
|
}
|
||||||
|
kfree(acl);
|
||||||
|
}
|
||||||
|
|
||||||
|
key_put(key);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct xattr_handler afs_xattr_afs_acl_handler = {
|
||||||
|
.name = "afs.acl",
|
||||||
|
.get = afs_xattr_get_acl,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the name of the cell on which a file resides.
|
* Get the name of the cell on which a file resides.
|
||||||
*/
|
*/
|
||||||
|
@ -123,6 +175,7 @@ static const struct xattr_handler afs_xattr_afs_volume_handler = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct xattr_handler *afs_xattr_handlers[] = {
|
const struct xattr_handler *afs_xattr_handlers[] = {
|
||||||
|
&afs_xattr_afs_acl_handler,
|
||||||
&afs_xattr_afs_cell_handler,
|
&afs_xattr_afs_cell_handler,
|
||||||
&afs_xattr_afs_fid_handler,
|
&afs_xattr_afs_fid_handler,
|
||||||
&afs_xattr_afs_volume_handler,
|
&afs_xattr_afs_volume_handler,
|
||||||
|
|
|
@ -33,6 +33,7 @@ enum afs_call_trace {
|
||||||
|
|
||||||
enum afs_fs_operation {
|
enum afs_fs_operation {
|
||||||
afs_FS_FetchData = 130, /* AFS Fetch file data */
|
afs_FS_FetchData = 130, /* AFS Fetch file data */
|
||||||
|
afs_FS_FetchACL = 131, /* AFS Fetch file ACL */
|
||||||
afs_FS_FetchStatus = 132, /* AFS Fetch file status */
|
afs_FS_FetchStatus = 132, /* AFS Fetch file status */
|
||||||
afs_FS_StoreData = 133, /* AFS Store file data */
|
afs_FS_StoreData = 133, /* AFS Store file data */
|
||||||
afs_FS_StoreStatus = 135, /* AFS Store file status */
|
afs_FS_StoreStatus = 135, /* AFS Store file status */
|
||||||
|
|
Loading…
Reference in New Issue