| /* Extended attribute handling for AFS.  We use xattrs to get and set metadata | 
 |  * instead of providing pioctl(). | 
 |  * | 
 |  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. | 
 |  * Written by David Howells (dhowells@redhat.com) | 
 |  * | 
 |  * This program is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU General Public Licence | 
 |  * as published by the Free Software Foundation; either version | 
 |  * 2 of the Licence, or (at your option) any later version. | 
 |  */ | 
 |  | 
 | #include <linux/slab.h> | 
 | #include <linux/fs.h> | 
 | #include <linux/xattr.h> | 
 | #include "internal.h" | 
 |  | 
 | static const char afs_xattr_list[] = | 
 | 	"afs.cell\0" | 
 | 	"afs.fid\0" | 
 | 	"afs.volume"; | 
 |  | 
 | /* | 
 |  * Retrieve a list of the supported xattrs. | 
 |  */ | 
 | ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size) | 
 | { | 
 | 	if (size == 0) | 
 | 		return sizeof(afs_xattr_list); | 
 | 	if (size < sizeof(afs_xattr_list)) | 
 | 		return -ERANGE; | 
 | 	memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list)); | 
 | 	return sizeof(afs_xattr_list); | 
 | } | 
 |  | 
 | /* | 
 |  * Get the name of the cell on which a file resides. | 
 |  */ | 
 | static int afs_xattr_get_cell(const struct xattr_handler *handler, | 
 | 			      struct dentry *dentry, | 
 | 			      struct inode *inode, const char *name, | 
 | 			      void *buffer, size_t size) | 
 | { | 
 | 	struct afs_vnode *vnode = AFS_FS_I(inode); | 
 | 	struct afs_cell *cell = vnode->volume->cell; | 
 | 	size_t namelen; | 
 |  | 
 | 	namelen = cell->name_len; | 
 | 	if (size == 0) | 
 | 		return namelen; | 
 | 	if (namelen > size) | 
 | 		return -ERANGE; | 
 | 	memcpy(buffer, cell->name, size); | 
 | 	return namelen; | 
 | } | 
 |  | 
 | static const struct xattr_handler afs_xattr_afs_cell_handler = { | 
 | 	.name	= "afs.cell", | 
 | 	.get	= afs_xattr_get_cell, | 
 | }; | 
 |  | 
 | /* | 
 |  * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of | 
 |  * hex numbers separated by colons. | 
 |  */ | 
 | static int afs_xattr_get_fid(const struct xattr_handler *handler, | 
 | 			     struct dentry *dentry, | 
 | 			     struct inode *inode, const char *name, | 
 | 			     void *buffer, size_t size) | 
 | { | 
 | 	struct afs_vnode *vnode = AFS_FS_I(inode); | 
 | 	char text[8 + 1 + 8 + 1 + 8 + 1]; | 
 | 	size_t len; | 
 |  | 
 | 	len = sprintf(text, "%x:%x:%x", | 
 | 		      vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); | 
 | 	if (size == 0) | 
 | 		return len; | 
 | 	if (len > size) | 
 | 		return -ERANGE; | 
 | 	memcpy(buffer, text, len); | 
 | 	return len; | 
 | } | 
 |  | 
 | static const struct xattr_handler afs_xattr_afs_fid_handler = { | 
 | 	.name	= "afs.fid", | 
 | 	.get	= afs_xattr_get_fid, | 
 | }; | 
 |  | 
 | /* | 
 |  * Get the name of the volume on which a file resides. | 
 |  */ | 
 | static int afs_xattr_get_volume(const struct xattr_handler *handler, | 
 | 			      struct dentry *dentry, | 
 | 			      struct inode *inode, const char *name, | 
 | 			      void *buffer, size_t size) | 
 | { | 
 | 	struct afs_vnode *vnode = AFS_FS_I(inode); | 
 | 	const char *volname = vnode->volume->name; | 
 | 	size_t namelen; | 
 |  | 
 | 	namelen = strlen(volname); | 
 | 	if (size == 0) | 
 | 		return namelen; | 
 | 	if (namelen > size) | 
 | 		return -ERANGE; | 
 | 	memcpy(buffer, volname, size); | 
 | 	return namelen; | 
 | } | 
 |  | 
 | static const struct xattr_handler afs_xattr_afs_volume_handler = { | 
 | 	.name	= "afs.volume", | 
 | 	.get	= afs_xattr_get_volume, | 
 | }; | 
 |  | 
 | const struct xattr_handler *afs_xattr_handlers[] = { | 
 | 	&afs_xattr_afs_cell_handler, | 
 | 	&afs_xattr_afs_fid_handler, | 
 | 	&afs_xattr_afs_volume_handler, | 
 | 	NULL | 
 | }; |