Commit 663be8db authored by Nathan Scott's avatar Nathan Scott

[XFS] Rework some extended attributes code to make it more easily extended.

SGI Modid: 2.5.x-xfs:slinx:163383a
parent 6bda7ecb
......@@ -110,7 +110,7 @@ linvfs_mknod(
vattr_t va;
vnode_t *vp = NULL, *dvp = LINVFS_GET_VP(dir);
xfs_acl_t *default_acl = NULL;
xattr_exists_t test_default_acl = _ACL_DEFAULT_EXISTS;
attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS;
int error;
/*
......@@ -552,61 +552,6 @@ linvfs_truncate(
block_truncate_page(inode->i_mapping, inode->i_size, linvfs_get_block);
}
/*
* Extended attributes interfaces
*/
#define SYSTEM_NAME "system." /* VFS shared names/values */
#define ROOT_NAME "trusted." /* root's own names/values */
#define USER_NAME "user." /* user's own names/values */
STATIC xattr_namespace_t xfs_namespace_array[] = {
{ .name= SYSTEM_NAME, .namelen= sizeof(SYSTEM_NAME)-1,.exists= NULL },
{ .name= ROOT_NAME, .namelen= sizeof(ROOT_NAME)-1, .exists= NULL },
{ .name= USER_NAME, .namelen= sizeof(USER_NAME)-1, .exists= NULL },
{ .name= NULL }
};
xattr_namespace_t *xfs_namespaces = &xfs_namespace_array[0];
#define POSIXACL_ACCESS "posix_acl_access"
#define POSIXACL_ACCESS_SIZE (sizeof(POSIXACL_ACCESS)-1)
#define POSIXACL_DEFAULT "posix_acl_default"
#define POSIXACL_DEFAULT_SIZE (sizeof(POSIXACL_DEFAULT)-1)
#define POSIXCAP "posix_capabilities"
#define POSIXCAP_SIZE (sizeof(POSIXCAP)-1)
#define POSIXMAC "posix_mac"
#define POSIXMAC_SIZE (sizeof(POSIXMAC)-1)
STATIC xattr_namespace_t sys_namespace_array[] = {
{ .name= POSIXACL_ACCESS,
.namelen= POSIXACL_ACCESS_SIZE, .exists= _ACL_ACCESS_EXISTS },
{ .name= POSIXACL_DEFAULT,
.namelen= POSIXACL_DEFAULT_SIZE, .exists= _ACL_DEFAULT_EXISTS },
{ .name= POSIXCAP,
.namelen= POSIXCAP_SIZE, .exists= _CAP_EXISTS },
{ .name= POSIXMAC,
.namelen= POSIXMAC_SIZE, .exists= _MAC_EXISTS },
{ .name= NULL }
};
/*
* Some checks to prevent people abusing EAs to get over quota:
* - Don't allow modifying user EAs on devices/symlinks;
* - Don't allow modifying user EAs if sticky bit set;
*/
STATIC int
capable_user_xattr(
struct inode *inode)
{
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) &&
!capable(CAP_SYS_ADMIN))
return 0;
if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
(current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
return 0;
return 1;
}
STATIC int
linvfs_setxattr(
struct dentry *dentry,
......@@ -615,59 +560,27 @@ linvfs_setxattr(
size_t size,
int flags)
{
struct inode *inode = dentry->d_inode;
vnode_t *vp = LINVFS_GET_VP(inode);
char *p = (char *)name;
vnode_t *vp = LINVFS_GET_VP(dentry->d_inode);
char *attr = (char *)name;
attrnames_t *namesp;
int xflags = 0;
int error;
if (strncmp(name, xfs_namespaces[SYSTEM_NAMES].name,
xfs_namespaces[SYSTEM_NAMES].namelen) == 0) {
error = -EINVAL;
if (flags & XATTR_CREATE)
return error;
error = -EOPNOTSUPP;
p += xfs_namespaces[SYSTEM_NAMES].namelen;
if (strcmp(p, POSIXACL_ACCESS) == 0)
error = xfs_acl_vset(vp, (void *) data, size,
_ACL_TYPE_ACCESS);
else if (strcmp(p, POSIXACL_DEFAULT) == 0)
error = xfs_acl_vset(vp, (void *) data, size,
_ACL_TYPE_DEFAULT);
else if (strcmp(p, POSIXCAP) == 0)
error = xfs_cap_vset(vp, (void *) data, size);
if (!error)
error = vn_revalidate(vp);
namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
if (!namesp)
return -EOPNOTSUPP;
attr += namesp->attr_namelen;
error = namesp->attr_capable(vp, NULL);
if (error)
return error;
}
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
/* Convert Linux syscall to XFS internal ATTR flags */
if (flags & XATTR_CREATE)
xflags |= ATTR_CREATE;
if (flags & XATTR_REPLACE)
xflags |= ATTR_REPLACE;
if (strncmp(name, xfs_namespaces[ROOT_NAMES].name,
xfs_namespaces[ROOT_NAMES].namelen) == 0) {
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
xflags |= ATTR_ROOT;
p += xfs_namespaces[ROOT_NAMES].namelen;
VOP_ATTR_SET(vp, p, (void *) data, size, xflags, NULL, error);
return -error;
}
if (strncmp(name, xfs_namespaces[USER_NAMES].name,
xfs_namespaces[USER_NAMES].namelen) == 0) {
if (!capable_user_xattr(inode))
return -EPERM;
p += xfs_namespaces[USER_NAMES].namelen;
VOP_ATTR_SET(vp, p, (void *) data, size, xflags, NULL, error);
return -error;
}
return -EOPNOTSUPP;
xflags |= namesp->attr_flag;
return namesp->attr_set(vp, attr, (void *)data, size, xflags);
}
STATIC ssize_t
......@@ -677,53 +590,27 @@ linvfs_getxattr(
void *data,
size_t size)
{
struct inode *inode = dentry->d_inode;
vnode_t *vp = LINVFS_GET_VP(inode);
char *p = (char *)name;
vnode_t *vp = LINVFS_GET_VP(dentry->d_inode);
char *attr = (char *)name;
attrnames_t *namesp;
int xflags = 0;
ssize_t error;
if (strncmp(name, xfs_namespaces[SYSTEM_NAMES].name,
xfs_namespaces[SYSTEM_NAMES].namelen) == 0) {
error = -EOPNOTSUPP;
p += xfs_namespaces[SYSTEM_NAMES].namelen;
if (strcmp(p, POSIXACL_ACCESS) == 0)
error = xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
else if (strcmp(p, POSIXACL_DEFAULT) == 0)
error = xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
else if (strcmp(p, POSIXCAP) == 0)
error = xfs_cap_vget(vp, data, size);
namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
if (!namesp)
return -EOPNOTSUPP;
attr += namesp->attr_namelen;
error = namesp->attr_capable(vp, NULL);
if (error)
return error;
}
/* Convert Linux syscall to XFS internal ATTR flags */
if (!size) {
xflags |= ATTR_KERNOVAL;
data = NULL;
}
if (strncmp(name, xfs_namespaces[ROOT_NAMES].name,
xfs_namespaces[ROOT_NAMES].namelen) == 0) {
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
xflags |= ATTR_ROOT;
p += xfs_namespaces[ROOT_NAMES].namelen;
VOP_ATTR_GET(vp, p, data, (int *)&size, xflags, NULL, error);
if (!error)
error = -size;
return -error;
}
if (strncmp(name, xfs_namespaces[USER_NAMES].name,
xfs_namespaces[USER_NAMES].namelen) == 0) {
p += xfs_namespaces[USER_NAMES].namelen;
if (!capable_user_xattr(inode))
return -EPERM;
VOP_ATTR_GET(vp, p, data, (int *)&size, xflags, NULL, error);
if (!error)
error = -size;
return -error;
}
return -EOPNOTSUPP;
xflags |= namesp->attr_flag;
return namesp->attr_get(vp, attr, (void *)data, size, xflags);
}
STATIC ssize_t
......@@ -732,40 +619,18 @@ linvfs_listxattr(
char *data,
size_t size)
{
attrlist_cursor_kern_t cursor;
xattr_namespace_t *sys;
vnode_t *vp = LINVFS_GET_VP(dentry->d_inode);
char *k = data;
int xflags = ATTR_KERNAMELS;
int result = 0;
ssize_t error;
int error, xflags = ATTR_KERNAMELS;
ssize_t result;
if (!size)
xflags |= ATTR_KERNOVAL;
if (capable(CAP_SYS_ADMIN))
xflags |= ATTR_KERNFULLS;
memset(&cursor, 0, sizeof(cursor));
VOP_ATTR_LIST(vp, data, size, xflags, &cursor, NULL, error);
if (error > 0)
return -error;
result += -error;
k += result; /* advance start of our buffer */
for (sys = &sys_namespace_array[0]; sys->name != NULL; sys++) {
if (sys->exists == NULL || !sys->exists(vp))
continue;
result += xfs_namespaces[SYSTEM_NAMES].namelen;
result += sys->namelen + 1;
if (size) {
if (result > size)
return -ERANGE;
strcpy(k, xfs_namespaces[SYSTEM_NAMES].name);
k += xfs_namespaces[SYSTEM_NAMES].namelen;
strcpy(k, sys->name);
k += sys->namelen + 1;
}
}
error = attr_generic_list(vp, data, size, xflags, &result);
if (error < 0)
return error;
return result;
}
......@@ -774,51 +639,25 @@ linvfs_removexattr(
struct dentry *dentry,
const char *name)
{
struct inode *inode = dentry->d_inode;
vnode_t *vp = LINVFS_GET_VP(inode);
char *p = (char *)name;
vnode_t *vp = LINVFS_GET_VP(dentry->d_inode);
char *attr = (char *)name;
attrnames_t *namesp;
int xflags = 0;
int error;
if (strncmp(name, xfs_namespaces[SYSTEM_NAMES].name,
xfs_namespaces[SYSTEM_NAMES].namelen) == 0) {
error = -EOPNOTSUPP;
p += xfs_namespaces[SYSTEM_NAMES].namelen;
if (strcmp(p, POSIXACL_ACCESS) == 0)
error = xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
else if (strcmp(p, POSIXACL_DEFAULT) == 0)
error = xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT);
else if (strcmp(p, POSIXCAP) == 0)
error = xfs_cap_vremove(vp);
return error;
}
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
if (strncmp(name, xfs_namespaces[ROOT_NAMES].name,
xfs_namespaces[ROOT_NAMES].namelen) == 0) {
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
xflags |= ATTR_ROOT;
p += xfs_namespaces[ROOT_NAMES].namelen;
VOP_ATTR_REMOVE(vp, p, xflags, NULL, error);
return -error;
}
if (strncmp(name, xfs_namespaces[USER_NAMES].name,
xfs_namespaces[USER_NAMES].namelen) == 0) {
p += xfs_namespaces[USER_NAMES].namelen;
if (!capable_user_xattr(inode))
return -EPERM;
VOP_ATTR_REMOVE(vp, p, xflags, NULL, error);
return -error;
}
namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
if (!namesp)
return -EOPNOTSUPP;
attr += namesp->attr_namelen;
error = namesp->attr_capable(vp, NULL);
if (error)
return error;
xflags |= namesp->attr_flag;
return namesp->attr_remove(vp, attr, xflags);
}
struct inode_operations linvfs_file_inode_operations =
{
struct inode_operations linvfs_file_inode_operations = {
.permission = linvfs_permission,
.truncate = linvfs_truncate,
.getattr = linvfs_getattr,
......@@ -829,8 +668,7 @@ struct inode_operations linvfs_file_inode_operations =
.removexattr = linvfs_removexattr,
};
struct inode_operations linvfs_dir_inode_operations =
{
struct inode_operations linvfs_dir_inode_operations = {
.create = linvfs_create,
.lookup = linvfs_lookup,
.link = linvfs_link,
......@@ -849,8 +687,7 @@ struct inode_operations linvfs_dir_inode_operations =
.removexattr = linvfs_removexattr,
};
struct inode_operations linvfs_symlink_inode_operations =
{
struct inode_operations linvfs_symlink_inode_operations = {
.readlink = linvfs_readlink,
.follow_link = linvfs_follow_link,
.permission = linvfs_permission,
......
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
......@@ -32,30 +32,6 @@
#ifndef __XFS_IOPS_H__
#define __XFS_IOPS_H__
/*
* Extended system attributes.
* So far only POSIX ACLs are supported, but this will need to
* grow in time (capabilities, mandatory access control, etc).
*/
#define XFS_SYSTEM_NAMESPACE SYSTEM_POSIXACL
/*
* Define a table of the namespaces XFS supports
*/
typedef int (*xattr_exists_t)(vnode_t *);
typedef struct xattr_namespace {
char *name;
unsigned int namelen;
xattr_exists_t exists;
} xattr_namespace_t;
#define SYSTEM_NAMES 0
#define ROOT_NAMES 1
#define USER_NAMES 2
extern struct xattr_namespace *xfs_namespaces;
extern struct inode_operations linvfs_file_inode_operations;
extern struct inode_operations linvfs_dir_inode_operations;
extern struct inode_operations linvfs_symlink_inode_operations;
......
/*
* Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2001-2003 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
......@@ -102,6 +102,8 @@ extern struct kmem_zone *xfs_acl_zone;
#define xfs_acl_vset(v,p,sz,t) (-EOPNOTSUPP)
#define xfs_acl_vget(v,p,sz,t) (-EOPNOTSUPP)
#define xfs_acl_vremove(v,t) (-EOPNOTSUPP)
#define xfs_acl_vhasacl_access(v) (0)
#define xfs_acl_vhasacl_default(v) (0)
#define _ACL_DECL(a) ((void)0)
#define _ACL_ALLOC(a) (1) /* successfully allocate nothing */
#define _ACL_FREE(a) ((void)0)
......
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
......@@ -63,6 +63,7 @@
#include "xfs_quota.h"
#include "xfs_rw.h"
#include "xfs_trans_space.h"
#include "xfs_acl.h"
/*
* xfs_attr.c
......@@ -2357,3 +2358,307 @@ xfs_attr_trace_enter(int type, char *where,
(void *)a14, (void *)a15);
}
#endif /* XFS_ATTR_TRACE */
/*========================================================================
* System (pseudo) namespace attribute interface routines.
*========================================================================*/
STATIC int
posix_acl_access_set(
vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
}
STATIC int
posix_acl_access_remove(
struct vnode *vp, char *name, int xflags)
{
return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
}
STATIC int
posix_acl_access_get(
vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
}
STATIC int
posix_acl_access_exists(
vnode_t *vp)
{
return xfs_acl_vhasacl_access(vp);
}
STATIC int
posix_acl_default_set(
vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
}
STATIC int
posix_acl_default_get(
vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
}
STATIC int
posix_acl_default_remove(
struct vnode *vp, char *name, int xflags)
{
return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT);
}
STATIC int
posix_acl_default_exists(
vnode_t *vp)
{
return xfs_acl_vhasacl_default(vp);
}
struct attrnames posix_acl_access = {
.attr_name = "posix_acl_access",
.attr_namelen = sizeof("posix_acl_access") - 1,
.attr_get = posix_acl_access_get,
.attr_set = posix_acl_access_set,
.attr_remove = posix_acl_access_remove,
.attr_exists = posix_acl_access_exists,
};
struct attrnames posix_acl_default = {
.attr_name = "posix_acl_default",
.attr_namelen = sizeof("posix_acl_default") - 1,
.attr_get = posix_acl_default_get,
.attr_set = posix_acl_default_set,
.attr_remove = posix_acl_default_remove,
.attr_exists = posix_acl_default_exists,
};
struct attrnames *attr_system_names[] =
{ &posix_acl_access, &posix_acl_default };
/*========================================================================
* Namespace-prefix-style attribute name interface routines.
*========================================================================*/
STATIC int
attr_generic_set(
struct vnode *vp, char *name, void *data, size_t size, int xflags)
{
int error;
VOP_ATTR_SET(vp, name, data, size, xflags, NULL, error);
return -error;
}
STATIC int
attr_generic_get(
struct vnode *vp, char *name, void *data, size_t size, int xflags)
{
int error, asize = size;
VOP_ATTR_GET(vp, name, data, &asize, xflags, NULL, error);
if (!error)
return asize;
return -error;
}
STATIC int
attr_generic_remove(
struct vnode *vp, char *name, int xflags)
{
int error;
VOP_ATTR_REMOVE(vp, name, xflags, NULL, error);
return -error;
}
STATIC int
attr_generic_listadd(
attrnames_t *prefix,
attrnames_t *namesp,
void *data,
size_t size,
ssize_t *result)
{
char *p = data + *result;
*result += prefix->attr_namelen;
*result += namesp->attr_namelen + 1;
if (!size)
return 0;
if (*result > size)
return -ERANGE;
strcpy(p, prefix->attr_name);
p += prefix->attr_namelen;
strcpy(p, namesp->attr_name);
p += namesp->attr_namelen + 1;
return 0;
}
STATIC int
attr_system_list(
struct vnode *vp,
void *data,
size_t size,
ssize_t *result)
{
attrnames_t *namesp;
int i, error = 0;
for (i = 0; i < ATTR_SYSCOUNT; i++) {
namesp = attr_system_names[i];
if (!namesp->attr_exists || !namesp->attr_exists(vp))
continue;
error = attr_generic_listadd(&attr_system, namesp,
data, size, result);
if (error)
break;
}
return error;
}
int
attr_generic_list(
struct vnode *vp, void *data, size_t size, int xflags, ssize_t *result)
{
attrlist_cursor_kern_t cursor = { 0 };
int error;
VOP_ATTR_LIST(vp, data, size, xflags, &cursor, NULL, error);
if (error > 0)
return -error;
*result = -error;
return attr_system_list(vp, data, size, result);
}
attrnames_t *
attr_lookup_namespace(
char *name,
struct attrnames **names,
int nnames)
{
int i;
for (i = 0; i < nnames; i++)
if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen))
return names[i];
return NULL;
}
/*
* Some checks to prevent people abusing EAs to get over quota:
* - Don't allow modifying user EAs on devices/symlinks;
* - Don't allow modifying user EAs if sticky bit set;
*/
STATIC int
attr_user_capable(
struct vnode *vp,
cred_t *cred)
{
struct inode *inode = LINVFS_GET_IP(vp);
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
(current_fsuid(cred) != inode->i_uid) && !capable(CAP_FOWNER))
return -EPERM;
return 0;
}
STATIC int
attr_trusted_capable(
struct vnode *vp,
cred_t *cred)
{
struct inode *inode = LINVFS_GET_IP(vp);
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
}
STATIC int
attr_system_set(
struct vnode *vp, char *name, void *data, size_t size, int xflags)
{
attrnames_t *namesp;
int error;
if (xflags & ATTR_CREATE)
return -EINVAL;
namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
if (!namesp)
return -EOPNOTSUPP;
error = namesp->attr_set(vp, name, data, size, xflags);
if (!error)
error = vn_revalidate(vp);
return error;
}
STATIC int
attr_system_get(
struct vnode *vp, char *name, void *data, size_t size, int xflags)
{
attrnames_t *namesp;
namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
if (!namesp)
return -EOPNOTSUPP;
return namesp->attr_get(vp, name, data, size, xflags);
}
STATIC int
attr_system_remove(
struct vnode *vp, char *name, int xflags)
{
attrnames_t *namesp;
namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
if (!namesp)
return -EOPNOTSUPP;
return namesp->attr_remove(vp, name, xflags);
}
struct attrnames attr_system = {
.attr_name = "system.",
.attr_namelen = sizeof("system.") - 1,
.attr_flag = ATTR_SYSTEM,
.attr_get = attr_system_get,
.attr_set = attr_system_set,
.attr_remove = attr_system_remove,
.attr_capable = (attrcapable_t)fs_noerr,
};
struct attrnames attr_trusted = {
.attr_name = "trusted.",
.attr_namelen = sizeof("trusted.") - 1,
.attr_flag = ATTR_ROOT,
.attr_get = attr_generic_get,
.attr_set = attr_generic_set,
.attr_remove = attr_generic_remove,
.attr_capable = attr_trusted_capable,
};
struct attrnames attr_user = {
.attr_name = "user.",
.attr_namelen = sizeof("user.") - 1,
.attr_get = attr_generic_get,
.attr_set = attr_generic_set,
.attr_remove = attr_generic_remove,
.attr_capable = attr_user_capable,
};
struct attrnames *attr_namespaces[] =
{ &attr_system, &attr_trusted, &attr_user };
/*
* Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2000, 2002-2003 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
......@@ -49,9 +49,46 @@
* External interfaces
*========================================================================*/
#define ATTR_ROOT 0x0002 /* use attrs in root namespace, not user */
struct cred;
struct vnode;
typedef int (*attrset_t)(struct vnode *, char *, void *, size_t, int);
typedef int (*attrget_t)(struct vnode *, char *, void *, size_t, int);
typedef int (*attrremove_t)(struct vnode *, char *, int);
typedef int (*attrexists_t)(struct vnode *);
typedef int (*attrcapable_t)(struct vnode *, struct cred *);
typedef struct attrnames {
char * attr_name;
unsigned int attr_namelen;
unsigned int attr_flag;
attrget_t attr_get;
attrset_t attr_set;
attrremove_t attr_remove;
attrexists_t attr_exists;
attrcapable_t attr_capable;
} attrnames_t;
#define ATTR_NAMECOUNT 3
extern struct attrnames attr_user;
extern struct attrnames attr_system;
extern struct attrnames attr_trusted;
extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT];
#define ATTR_SYSCOUNT 2
extern struct attrnames posix_acl_access;
extern struct attrnames posix_acl_default;
extern struct attrnames *attr_system_names[ATTR_SYSCOUNT];
extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int);
extern int attr_generic_list(struct vnode *, void *, size_t, int, ssize_t *);
#define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */
#define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */
#define ATTR_TRUST 0x0004 /* -- unused, from IRIX -- */
#define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */
#define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */
#define ATTR_SYSTEM 0x0100 /* use attrs in system (pseudo) namespace */
#define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */
#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */
#define ATTR_KERNAMELS 0x4000 /* [kernel] list attr names (simple list) */
......@@ -126,11 +163,8 @@ typedef struct attrlist_cursor_kern {
* Function prototypes for the kernel.
*========================================================================*/
struct cred;
struct vnode;
struct xfs_inode;
struct attrlist_cursor_kern;
struct xfs_ext_attr;
struct xfs_da_args;
/*
......
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
......@@ -444,8 +444,10 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
< context->bufsize) {
for (i = 0, sfe = &sf->list[0];
i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {
int ns = (sfe->flags & XFS_ATTR_ROOT)?
ROOT_NAMES : USER_NAMES;
attrnames_t *namesp;
namesp = (sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted :
&attr_user;
if (((context->flags & ATTR_ROOT) != 0) !=
((sfe->flags & XFS_ATTR_ROOT) != 0) &&
!(context->flags & ATTR_KERNFULLS)) {
......@@ -454,11 +456,11 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
}
if (context->flags & ATTR_KERNOVAL) {
ASSERT(context->flags & ATTR_KERNAMELS);
context->count += xfs_namespaces[ns].namelen +
context->count += namesp->attr_namelen +
INT_GET(sfe->namelen, ARCH_CONVERT) + 1;
}
else {
if (xfs_attr_put_listent(context, ns,
if (xfs_attr_put_listent(context, namesp,
(char *)sfe->nameval,
(int)sfe->namelen,
(int)INT_GET(sfe->valuelen,
......@@ -544,18 +546,22 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
* Loop putting entries into the user buffer.
*/
for ( ; i < nsbuf; i++, sbp++) {
int ns = (sbp->flags & XFS_ATTR_ROOT)? ROOT_NAMES:USER_NAMES;
attrnames_t *namesp;
namesp = (sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted :
&attr_user;
if (cursor->hashval != INT_GET(sbp->hash, ARCH_CONVERT)) {
cursor->hashval = INT_GET(sbp->hash, ARCH_CONVERT);
cursor->offset = 0;
}
if (context->flags & ATTR_KERNOVAL) {
ASSERT(context->flags & ATTR_KERNAMELS);
context->count += xfs_namespaces[ns].namelen
+ sbp->namelen + 1;
context->count += namesp->attr_namelen +
sbp->namelen + 1;
}
else {
if (xfs_attr_put_listent(context, ns,
if (xfs_attr_put_listent(context, namesp,
sbp->name, sbp->namelen,
INT_GET(sbp->valuelen, ARCH_CONVERT)))
break;
......@@ -2270,7 +2276,7 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
retval = 0;
for ( ; (i < INT_GET(leaf->hdr.count, ARCH_CONVERT))
&& (retval == 0); entry++, i++) {
int ns = (entry->flags & XFS_ATTR_ROOT)? ROOT_NAMES:USER_NAMES;
attrnames_t *namesp;
if (INT_GET(entry->hashval, ARCH_CONVERT) != cursor->hashval) {
cursor->hashval = INT_GET(entry->hashval, ARCH_CONVERT);
......@@ -2284,14 +2290,17 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
!(context->flags & ATTR_KERNFULLS))
continue; /* skip non-matching entries */
namesp = (entry->flags & XFS_ATTR_ROOT) ? &attr_trusted :
&attr_user;
if (entry->flags & XFS_ATTR_LOCAL) {
name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
if (context->flags & ATTR_KERNOVAL) {
ASSERT(context->flags & ATTR_KERNAMELS);
context->count += xfs_namespaces[ns].namelen
+ (int)name_loc->namelen + 1;
context->count += namesp->attr_namelen +
(int)name_loc->namelen + 1;
} else {
retval = xfs_attr_put_listent(context, ns,
retval = xfs_attr_put_listent(context, namesp,
(char *)name_loc->nameval,
(int)name_loc->namelen,
(int)INT_GET(name_loc->valuelen,
......@@ -2301,10 +2310,10 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
if (context->flags & ATTR_KERNOVAL) {
ASSERT(context->flags & ATTR_KERNAMELS);
context->count += xfs_namespaces[ns].namelen
+ (int)name_rmt->namelen + 1;
context->count += namesp->attr_namelen +
(int)name_rmt->namelen + 1;
} else {
retval = xfs_attr_put_listent(context, ns,
retval = xfs_attr_put_listent(context, namesp,
(char *)name_rmt->name,
(int)name_rmt->namelen,
(int)INT_GET(name_rmt->valuelen,
......@@ -2333,7 +2342,7 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
/*ARGSUSED*/
int
xfs_attr_put_listent(xfs_attr_list_context_t *context,
int ns, char *name, int namelen, int valuelen)
attrnames_t *namesp, char *name, int namelen, int valuelen)
{
attrlist_ent_t *aep;
int arraytop;
......@@ -2341,23 +2350,21 @@ xfs_attr_put_listent(xfs_attr_list_context_t *context,
ASSERT(!(context->flags & ATTR_KERNOVAL));
if (context->flags & ATTR_KERNAMELS) {
char *offset;
xattr_namespace_t *nsp;
ASSERT(context->count >= 0);
nsp = &xfs_namespaces[ns];
arraytop = context->count + nsp->namelen + namelen+1;
arraytop = context->count + namesp->attr_namelen + namelen + 1;
if (arraytop > context->firstu) {
context->count = -1; /* insufficient space */
return(1);
}
offset = (char *)context->alist + context->count;
strncpy(offset, nsp->name, nsp->namelen); /* namespace */
offset += nsp->namelen;
strncpy(offset, namesp->attr_name, namesp->attr_namelen);
offset += namesp->attr_namelen;
strncpy(offset, name, namelen); /* real name */
offset += namelen;
*offset = '\0';
context->count += nsp->namelen + namelen + 1;
context->count += namesp->attr_namelen + namelen + 1;
return(0);
}
......
/*
* Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2000, 2002-2003 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
......@@ -44,6 +44,7 @@
struct attrlist;
struct attrlist_cursor_kern;
struct attrnames;
struct xfs_dabuf;
struct xfs_da_args;
struct xfs_da_state;
......@@ -128,7 +129,7 @@ typedef struct xfs_attr_leaf_name_remote xfs_attr_leaf_name_remote_t;
* on the system call, they are "or"ed together for various operations.
*/
#define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */
#define XFS_ATTR_ROOT_BIT 1 /* limit access to attr to userid 0 */
#define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */
#define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */
#define XFS_ATTR_LOCAL (1 << XFS_ATTR_LOCAL_BIT)
#define XFS_ATTR_ROOT (1 << XFS_ATTR_ROOT_BIT)
......@@ -299,7 +300,8 @@ int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int blocksize,
int *local);
int xfs_attr_leaf_entsize(struct xfs_attr_leafblock *leaf, int index);
int xfs_attr_put_listent(struct xfs_attr_list_context *context,
int ns, char *name, int namelen, int valuelen);
struct attrnames *, char *name, int namelen,
int valuelen);
int xfs_attr_rolltrans(struct xfs_trans **transp, struct xfs_inode *dp);
#endif /* __XFS_ATTR_LEAF_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment