public inbox for linux-xfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] kill attr_capable callbacks
@ 2008-04-30 11:22 Christoph Hellwig
  2008-05-12  1:47 ` David Chinner
  2008-05-14  7:05 ` Timothy Shimmin
  0 siblings, 2 replies; 5+ messages in thread
From: Christoph Hellwig @ 2008-04-30 11:22 UTC (permalink / raw)
  To: xfs

No need for addition permission checks in the xattr handler,
fs/xattr.c:xattr_permission() already does them, and in fact slightly
more strict then what was in the attr_capable handlers.


Signed-off-by: Christoph Hellwig <hch@lst.de>

Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/linux-2.6/xfs_iops.c	2008-04-29 21:32:56.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c	2008-04-29 21:33:30.000000000 +0200
@@ -747,15 +747,11 @@ xfs_vn_setxattr(
 	char		*attr = (char *)name;
 	attrnames_t	*namesp;
 	int		xflags = 0;
-	int		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;
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (flags & XATTR_CREATE)
@@ -777,15 +773,11 @@ xfs_vn_getxattr(
 	char		*attr = (char *)name;
 	attrnames_t	*namesp;
 	int		xflags = 0;
-	ssize_t		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;
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (!size) {
@@ -825,15 +817,12 @@ xfs_vn_removexattr(
 	char		*attr = (char *)name;
 	attrnames_t	*namesp;
 	int		xflags = 0;
-	int		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);
 }
Index: linux-2.6-xfs/fs/xfs/xfs_attr.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_attr.c	2008-04-29 21:32:25.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/xfs_attr.c	2008-04-29 21:32:51.000000000 +0200
@@ -2622,43 +2622,6 @@ attr_lookup_namespace(
 	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(
-	bhv_vnode_t	*vp,
-	cred_t		*cred)
-{
-	struct inode	*inode = vn_to_inode(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(
-	bhv_vnode_t	*vp,
-	cred_t		*cred)
-{
-	struct inode	*inode = vn_to_inode(vp);
-
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-		return -EPERM;
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	return 0;
-}
-
 STATIC int
 attr_system_set(
 	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
@@ -2709,7 +2672,6 @@ struct attrnames 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 = {
@@ -2719,7 +2681,6 @@ struct attrnames attr_trusted = {
 	.attr_get	= attr_generic_get,
 	.attr_set	= attr_generic_set,
 	.attr_remove	= attr_generic_remove,
-	.attr_capable	= attr_trusted_capable,
 };
 
 struct attrnames attr_secure = {
@@ -2729,7 +2690,6 @@ struct attrnames attr_secure = {
 	.attr_get	= attr_generic_get,
 	.attr_set	= attr_generic_set,
 	.attr_remove	= attr_generic_remove,
-	.attr_capable	= (attrcapable_t)fs_noerr,
 };
 
 struct attrnames attr_user = {
@@ -2738,7 +2698,6 @@ struct attrnames attr_user = {
 	.attr_get	= attr_generic_get,
 	.attr_set	= attr_generic_set,
 	.attr_remove	= attr_generic_remove,
-	.attr_capable	= attr_user_capable,
 };
 
 struct attrnames *attr_namespaces[] =
Index: linux-2.6-xfs/fs/xfs/xfs_attr.h
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_attr.h	2008-04-29 21:33:38.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/xfs_attr.h	2008-04-29 21:33:52.000000000 +0200
@@ -42,7 +42,6 @@ typedef int (*attrset_t)(bhv_vnode_t *, 
 typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int);
 typedef int (*attrremove_t)(bhv_vnode_t *, char *, int);
 typedef int (*attrexists_t)(bhv_vnode_t *);
-typedef int (*attrcapable_t)(bhv_vnode_t *, struct cred *);
 
 typedef struct attrnames {
 	char *		attr_name;
@@ -52,7 +51,6 @@ typedef struct attrnames {
 	attrset_t	attr_set;
 	attrremove_t	attr_remove;
 	attrexists_t	attr_exists;
-	attrcapable_t	attr_capable;
 } attrnames_t;
 
 #define ATTR_NAMECOUNT	4

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] kill attr_capable callbacks
  2008-04-30 11:22 [PATCH 1/2] kill attr_capable callbacks Christoph Hellwig
@ 2008-05-12  1:47 ` David Chinner
  2008-05-12  6:22   ` Timothy Shimmin
  2008-05-12  6:27   ` Christoph Hellwig
  2008-05-14  7:05 ` Timothy Shimmin
  1 sibling, 2 replies; 5+ messages in thread
From: David Chinner @ 2008-05-12  1:47 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: xfs

Tim,

Seeing you are working on xattr stuff right now, can you pick this up?
(and the followup patch as well?)

Cheers,

Dave.

On Wed, Apr 30, 2008 at 01:22:13PM +0200, Christoph Hellwig wrote:
> No need for addition permission checks in the xattr handler,
> fs/xattr.c:xattr_permission() already does them, and in fact slightly
> more strict then what was in the attr_capable handlers.
> 
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> 
> Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c
> ===================================================================
> --- linux-2.6-xfs.orig/fs/xfs/linux-2.6/xfs_iops.c	2008-04-29 21:32:56.000000000 +0200
> +++ linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c	2008-04-29 21:33:30.000000000 +0200
> @@ -747,15 +747,11 @@ xfs_vn_setxattr(
>  	char		*attr = (char *)name;
>  	attrnames_t	*namesp;
>  	int		xflags = 0;
> -	int		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;
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (flags & XATTR_CREATE)
> @@ -777,15 +773,11 @@ xfs_vn_getxattr(
>  	char		*attr = (char *)name;
>  	attrnames_t	*namesp;
>  	int		xflags = 0;
> -	ssize_t		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;
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (!size) {
> @@ -825,15 +817,12 @@ xfs_vn_removexattr(
>  	char		*attr = (char *)name;
>  	attrnames_t	*namesp;
>  	int		xflags = 0;
> -	int		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);
>  }
> Index: linux-2.6-xfs/fs/xfs/xfs_attr.c
> ===================================================================
> --- linux-2.6-xfs.orig/fs/xfs/xfs_attr.c	2008-04-29 21:32:25.000000000 +0200
> +++ linux-2.6-xfs/fs/xfs/xfs_attr.c	2008-04-29 21:32:51.000000000 +0200
> @@ -2622,43 +2622,6 @@ attr_lookup_namespace(
>  	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(
> -	bhv_vnode_t	*vp,
> -	cred_t		*cred)
> -{
> -	struct inode	*inode = vn_to_inode(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(
> -	bhv_vnode_t	*vp,
> -	cred_t		*cred)
> -{
> -	struct inode	*inode = vn_to_inode(vp);
> -
> -	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
> -		return -EPERM;
> -	if (!capable(CAP_SYS_ADMIN))
> -		return -EPERM;
> -	return 0;
> -}
> -
>  STATIC int
>  attr_system_set(
>  	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
> @@ -2709,7 +2672,6 @@ struct attrnames 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 = {
> @@ -2719,7 +2681,6 @@ struct attrnames attr_trusted = {
>  	.attr_get	= attr_generic_get,
>  	.attr_set	= attr_generic_set,
>  	.attr_remove	= attr_generic_remove,
> -	.attr_capable	= attr_trusted_capable,
>  };
>  
>  struct attrnames attr_secure = {
> @@ -2729,7 +2690,6 @@ struct attrnames attr_secure = {
>  	.attr_get	= attr_generic_get,
>  	.attr_set	= attr_generic_set,
>  	.attr_remove	= attr_generic_remove,
> -	.attr_capable	= (attrcapable_t)fs_noerr,
>  };
>  
>  struct attrnames attr_user = {
> @@ -2738,7 +2698,6 @@ struct attrnames attr_user = {
>  	.attr_get	= attr_generic_get,
>  	.attr_set	= attr_generic_set,
>  	.attr_remove	= attr_generic_remove,
> -	.attr_capable	= attr_user_capable,
>  };
>  
>  struct attrnames *attr_namespaces[] =
> Index: linux-2.6-xfs/fs/xfs/xfs_attr.h
> ===================================================================
> --- linux-2.6-xfs.orig/fs/xfs/xfs_attr.h	2008-04-29 21:33:38.000000000 +0200
> +++ linux-2.6-xfs/fs/xfs/xfs_attr.h	2008-04-29 21:33:52.000000000 +0200
> @@ -42,7 +42,6 @@ typedef int (*attrset_t)(bhv_vnode_t *, 
>  typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int);
>  typedef int (*attrremove_t)(bhv_vnode_t *, char *, int);
>  typedef int (*attrexists_t)(bhv_vnode_t *);
> -typedef int (*attrcapable_t)(bhv_vnode_t *, struct cred *);
>  
>  typedef struct attrnames {
>  	char *		attr_name;
> @@ -52,7 +51,6 @@ typedef struct attrnames {
>  	attrset_t	attr_set;
>  	attrremove_t	attr_remove;
>  	attrexists_t	attr_exists;
> -	attrcapable_t	attr_capable;
>  } attrnames_t;
>  
>  #define ATTR_NAMECOUNT	4
> 

-- 
Dave Chinner
Principal Engineer
SGI Australian Software Group

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] kill attr_capable callbacks
  2008-05-12  1:47 ` David Chinner
@ 2008-05-12  6:22   ` Timothy Shimmin
  2008-05-12  6:27   ` Christoph Hellwig
  1 sibling, 0 replies; 5+ messages in thread
From: Timothy Shimmin @ 2008-05-12  6:22 UTC (permalink / raw)
  To: David Chinner; +Cc: Christoph Hellwig, xfs

David Chinner wrote:
> Tim,
> 
> Seeing you are working on xattr stuff right now, can you pick this up?
> (and the followup patch as well?)
> 
> Cheers,
> 
> Dave.
> 
Yep.

--Tim

> On Wed, Apr 30, 2008 at 01:22:13PM +0200, Christoph Hellwig wrote:
>> No need for addition permission checks in the xattr handler,
>> fs/xattr.c:xattr_permission() already does them, and in fact slightly
>> more strict then what was in the attr_capable handlers.
>>
>>
>> Signed-off-by: Christoph Hellwig <hch@lst.de>
>>
>> Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c
>> ===================================================================
>> --- linux-2.6-xfs.orig/fs/xfs/linux-2.6/xfs_iops.c	2008-04-29 21:32:56.000000000 +0200
>> +++ linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c	2008-04-29 21:33:30.000000000 +0200
>> @@ -747,15 +747,11 @@ xfs_vn_setxattr(
>>  	char		*attr = (char *)name;
>>  	attrnames_t	*namesp;
>>  	int		xflags = 0;
>> -	int		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;
>>  
>>  	/* Convert Linux syscall to XFS internal ATTR flags */
>>  	if (flags & XATTR_CREATE)
>> @@ -777,15 +773,11 @@ xfs_vn_getxattr(
>>  	char		*attr = (char *)name;
>>  	attrnames_t	*namesp;
>>  	int		xflags = 0;
>> -	ssize_t		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;
>>  
>>  	/* Convert Linux syscall to XFS internal ATTR flags */
>>  	if (!size) {
>> @@ -825,15 +817,12 @@ xfs_vn_removexattr(
>>  	char		*attr = (char *)name;
>>  	attrnames_t	*namesp;
>>  	int		xflags = 0;
>> -	int		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);
>>  }
>> Index: linux-2.6-xfs/fs/xfs/xfs_attr.c
>> ===================================================================
>> --- linux-2.6-xfs.orig/fs/xfs/xfs_attr.c	2008-04-29 21:32:25.000000000 +0200
>> +++ linux-2.6-xfs/fs/xfs/xfs_attr.c	2008-04-29 21:32:51.000000000 +0200
>> @@ -2622,43 +2622,6 @@ attr_lookup_namespace(
>>  	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(
>> -	bhv_vnode_t	*vp,
>> -	cred_t		*cred)
>> -{
>> -	struct inode	*inode = vn_to_inode(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(
>> -	bhv_vnode_t	*vp,
>> -	cred_t		*cred)
>> -{
>> -	struct inode	*inode = vn_to_inode(vp);
>> -
>> -	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>> -		return -EPERM;
>> -	if (!capable(CAP_SYS_ADMIN))
>> -		return -EPERM;
>> -	return 0;
>> -}
>> -
>>  STATIC int
>>  attr_system_set(
>>  	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
>> @@ -2709,7 +2672,6 @@ struct attrnames 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 = {
>> @@ -2719,7 +2681,6 @@ struct attrnames attr_trusted = {
>>  	.attr_get	= attr_generic_get,
>>  	.attr_set	= attr_generic_set,
>>  	.attr_remove	= attr_generic_remove,
>> -	.attr_capable	= attr_trusted_capable,
>>  };
>>  
>>  struct attrnames attr_secure = {
>> @@ -2729,7 +2690,6 @@ struct attrnames attr_secure = {
>>  	.attr_get	= attr_generic_get,
>>  	.attr_set	= attr_generic_set,
>>  	.attr_remove	= attr_generic_remove,
>> -	.attr_capable	= (attrcapable_t)fs_noerr,
>>  };
>>  
>>  struct attrnames attr_user = {
>> @@ -2738,7 +2698,6 @@ struct attrnames attr_user = {
>>  	.attr_get	= attr_generic_get,
>>  	.attr_set	= attr_generic_set,
>>  	.attr_remove	= attr_generic_remove,
>> -	.attr_capable	= attr_user_capable,
>>  };
>>  
>>  struct attrnames *attr_namespaces[] =
>> Index: linux-2.6-xfs/fs/xfs/xfs_attr.h
>> ===================================================================
>> --- linux-2.6-xfs.orig/fs/xfs/xfs_attr.h	2008-04-29 21:33:38.000000000 +0200
>> +++ linux-2.6-xfs/fs/xfs/xfs_attr.h	2008-04-29 21:33:52.000000000 +0200
>> @@ -42,7 +42,6 @@ typedef int (*attrset_t)(bhv_vnode_t *, 
>>  typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int);
>>  typedef int (*attrremove_t)(bhv_vnode_t *, char *, int);
>>  typedef int (*attrexists_t)(bhv_vnode_t *);
>> -typedef int (*attrcapable_t)(bhv_vnode_t *, struct cred *);
>>  
>>  typedef struct attrnames {
>>  	char *		attr_name;
>> @@ -52,7 +51,6 @@ typedef struct attrnames {
>>  	attrset_t	attr_set;
>>  	attrremove_t	attr_remove;
>>  	attrexists_t	attr_exists;
>> -	attrcapable_t	attr_capable;
>>  } attrnames_t;
>>  
>>  #define ATTR_NAMECOUNT	4
>>
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] kill attr_capable callbacks
  2008-05-12  1:47 ` David Chinner
  2008-05-12  6:22   ` Timothy Shimmin
@ 2008-05-12  6:27   ` Christoph Hellwig
  1 sibling, 0 replies; 5+ messages in thread
From: Christoph Hellwig @ 2008-05-12  6:27 UTC (permalink / raw)
  To: David Chinner; +Cc: Christoph Hellwig, xfs

On Mon, May 12, 2008 at 11:47:21AM +1000, David Chinner wrote:
> Tim,
> 
> Seeing you are working on xattr stuff right now, can you pick this up?
> (and the followup patch as well?)

Btw, here's the generic acl conversion rebased ontop of these two
patches.  Still haven't managed to sort out the other issues with it.


Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_acl.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-xfs/fs/xfs/linux-2.6/xfs_acl.c	2008-05-02 19:34:18.000000000 +0200
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2008 Christoph Hellwig.
+ *	Released under GPL v2.
+ */
+#include "xfs.h"
+#include "xfs_acl.h"
+#include "xfs_attr.h"
+#include "xfs_bmap_btree.h"	/* required by xfs_inode.h */
+#include "xfs_inode.h"
+#include "xfs_vnodeops.h"
+
+#include <linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
+
+
+#define XFS_ACL_NOT_CACHED	((void *)-1)
+
+/*
+ * Convert from extended attribute to in-memory representation.
+ */
+static struct posix_acl *xfs_acl_from_disk(struct xfs_acl *aclp)
+{
+	struct posix_acl_entry *acl_e;
+	struct posix_acl *acl;
+	struct xfs_acl_entry *ace;
+	int count, i;
+
+	count = be32_to_cpu(aclp->acl_cnt);
+
+	acl = posix_acl_alloc(count, GFP_KERNEL);
+	if (!acl)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < count; i++) {
+		acl_e = &acl->a_entries[i];
+		ace = &aclp->acl_entry[i];
+
+		/*
+		 * XXX(hch): the tag is 32 bits on disk and 16 bits in core.
+		 *		Any special handling required??
+		 */
+		acl_e->e_tag = be32_to_cpu(ace->ae_tag);
+		acl_e->e_perm = be16_to_cpu(ace->ae_perm);
+
+		switch(acl_e->e_tag) {
+		case ACL_USER:
+		case ACL_GROUP:
+			acl_e->e_id = be32_to_cpu(ace->ae_id);
+			break;
+		case ACL_USER_OBJ:
+		case ACL_GROUP_OBJ:
+		case ACL_MASK:
+		case ACL_OTHER:
+			acl_e->e_id = ACL_UNDEFINED_ID;
+			break;
+		default:
+			goto fail;
+		}
+	}
+	return acl;
+
+fail:
+	posix_acl_release(acl);
+	return ERR_PTR(-EINVAL);
+}
+
+/*
+ * Convert from in-memory to extended attribute representation.
+ */
+static void xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl)
+{
+	const struct posix_acl_entry *acl_e;
+	struct xfs_acl_entry *ace;
+	int i;
+
+	for (i = 0; i < acl->a_count; i++) {
+		ace = &aclp->acl_entry[i];
+		acl_e = &acl->a_entries[i];
+
+		ace->ae_tag = cpu_to_be32(acl_e->e_tag);
+		ace->ae_id = cpu_to_be32(acl_e->e_id);
+		ace->ae_perm = cpu_to_be16(acl_e->e_perm);
+	}
+}
+
+struct posix_acl *xfs_get_acl(struct inode *inode, int type)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+	struct posix_acl *acl = NULL, **p_acl;
+	struct xfs_acl *xfs_acl;
+	int len = sizeof(struct xfs_acl);
+	char *ea_name;
+	int error;
+
+	switch (type) {
+	case ACL_TYPE_ACCESS:
+		ea_name = SGI_ACL_FILE;
+		p_acl = &ip->i_acl;
+		break;
+	case ACL_TYPE_DEFAULT:
+		ea_name = SGI_ACL_DEFAULT;
+		p_acl = &ip->i_default_acl;
+		break;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (*p_acl != XFS_ACL_NOT_CACHED)
+		return posix_acl_dup(*p_acl);
+
+	xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
+	if (!xfs_acl)
+		return ERR_PTR(-ENOMEM);
+
+	error = -xfs_attr_get(ip, ea_name, (char *)xfs_acl, &len, ATTR_ROOT);
+	if (!error) {
+		acl = xfs_acl_from_disk(xfs_acl);
+		if (!IS_ERR(acl))
+			*p_acl = posix_acl_dup(acl);
+	} else {
+		*p_acl = NULL;
+	}
+
+	kfree(xfs_acl);
+	return acl;
+}
+
+static int xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+	struct posix_acl **p_acl;
+	char *ea_name;
+	int error;
+
+	if (S_ISLNK(inode->i_mode))
+		return -EOPNOTSUPP;
+
+	switch (type) {
+	case ACL_TYPE_ACCESS:
+		ea_name = SGI_ACL_FILE;
+		p_acl = &ip->i_acl;
+		break;
+	case ACL_TYPE_DEFAULT:
+		ea_name = SGI_ACL_DEFAULT;
+		p_acl = &ip->i_default_acl;
+		if (!S_ISDIR(inode->i_mode))
+			return acl ? -EACCES : 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (acl) {
+		struct xfs_acl *xfs_acl;
+		int len;
+
+		xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
+		if (!xfs_acl)
+			return -ENOMEM;
+
+		xfs_acl_to_disk(xfs_acl, acl);
+		len = sizeof(struct xfs_acl) -
+			(sizeof(struct xfs_acl_entry) *
+			 (XFS_ACL_MAX_ENTRIES - acl->a_count));
+
+		error = -xfs_attr_set(ip, ea_name, (char *)xfs_acl,
+				len, ATTR_ROOT);
+
+		kfree(xfs_acl);
+	} else {
+		error = -xfs_attr_remove(ip, ea_name, ATTR_ROOT);
+
+		/*
+		 * If the attribute didn't exist to start with that's fine.
+		 */
+		if (error == -ENOATTR)
+			error = 0;
+	}
+
+	if (!error) {
+		if (*p_acl && *p_acl != XFS_ACL_NOT_CACHED)
+			posix_acl_release(*p_acl);
+		*p_acl = posix_acl_dup(acl);
+	}
+	return error;
+}
+
+static int xfs_check_acl(struct inode *inode, int mask)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+
+	xfs_itrace_entry(ip);
+
+	if (!XFS_IFORK_Q(ip))
+		return -EAGAIN;
+
+	if (ip->i_acl == XFS_ACL_NOT_CACHED) {
+		struct posix_acl *acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
+		if (IS_ERR(acl))
+			return PTR_ERR(acl);
+		posix_acl_release(acl);
+	}
+
+	if (ip->i_acl)
+		return posix_acl_permission(inode, ip->i_acl, mask);
+	return -EAGAIN;
+}
+
+int xfs_vn_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+	return generic_permission(inode, mask, xfs_check_acl);
+}
+
+
+/*
+ * Helper to propagate i_mode the xfs_inode.
+ */
+static int xfs_set_mode(struct inode *inode, mode_t mode)
+{
+	int error = 0;
+
+	if (mode != inode->i_mode) {
+		struct bhv_vattr va = {
+			.va_mask	= XFS_AT_MODE,
+			.va_mode	= mode,
+		};
+
+		va.va_mask = XFS_AT_MODE;
+		va.va_mode = mode;
+
+		error = -xfs_setattr(XFS_I(inode), &va, 0, sys_cred);
+		inode->i_mode = mode;
+	}
+
+	return error;
+}
+
+static int xfs_acl_exists(struct inode *inode, char *name)
+{
+	int len = sizeof(struct xfs_acl);
+
+	return xfs_attr_get(XFS_I(inode), name, NULL, &len,
+			    ATTR_ROOT|ATTR_KERNOVAL);
+}
+
+int posix_acl_access_exists(struct inode *inode)
+{
+	return xfs_acl_exists(inode, SGI_ACL_FILE);
+}
+
+int posix_acl_default_exists(struct inode *inode)
+{
+	if (!S_ISDIR(inode->i_mode))
+		return 0;
+	return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
+}
+
+static int
+xfs_decode_acl(const char *name)
+{
+	if (strcmp(name, "posix_acl_access") == 0)
+		return ACL_TYPE_ACCESS;
+	else if (strcmp(name, "posix_acl_default") == 0)
+		return ACL_TYPE_DEFAULT;
+	return -EINVAL;
+}
+
+/*
+ * Extended attribute handlers
+ */
+
+static int
+xfs_xattr_system_get(struct inode *inode, const char *name,
+		void *value, size_t size)
+{
+	struct posix_acl *acl;
+	int type, error;
+
+	type = xfs_decode_acl(name);
+	if (type < 0)
+		return type;
+
+	acl = xfs_get_acl(inode, type);
+	if (IS_ERR(acl))
+		return PTR_ERR(acl);
+	if (acl == NULL)
+		return -ENODATA;
+	error = posix_acl_to_xattr(acl, value, size);
+	posix_acl_release(acl);
+
+	return error;
+}
+
+static int
+xfs_xattr_system_set(struct inode *inode, const char *name,
+		const void *value, size_t size, int flags)
+{
+	struct posix_acl *acl = NULL;
+	int error, type;
+
+	type = xfs_decode_acl(name);
+	if (type < 0)
+		return type;
+	if (flags & XATTR_CREATE)
+		return -EINVAL;
+	if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
+		return value ? -EACCES : 0;
+	if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+		return -EPERM;
+
+	if (!value)
+		goto set_acl;
+
+	acl = posix_acl_from_xattr(value, size);
+	if (IS_ERR(acl))
+		return PTR_ERR(acl);
+	if (!acl)
+		goto set_acl;
+
+	error = posix_acl_valid(acl);
+	if (error)
+		goto out_release;
+
+	error = -EINVAL;
+	if (acl->a_count > XFS_ACL_MAX_ENTRIES)
+		goto out_release;
+
+	if (type == ACL_TYPE_ACCESS) {
+		mode_t mode = inode->i_mode;
+		error = posix_acl_equiv_mode(acl, &mode);
+		if (error < 0)
+			return error; // XXX
+
+		if (error == 0) {
+			posix_acl_release(acl);
+			acl = NULL;
+		}
+		error = xfs_set_mode(inode, mode);
+		if (error)
+			goto out_release;
+	}
+
+ set_acl:
+	error = xfs_set_acl(inode, type, acl);
+
+ out_release:
+	posix_acl_release(acl);
+	if (!error)
+		vn_revalidate(inode);
+	return error;
+}
+
+struct xattr_handler xfs_xattr_system_handler = {
+	.prefix	= XATTR_SYSTEM_PREFIX,
+	.get	= xfs_xattr_system_get,
+	.set	= xfs_xattr_system_set,
+};
+
+/*
+ * Unlike the other functions in this file this returns positive errors.
+ */
+int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+	struct posix_acl *clone;
+	mode_t mode;
+	int error = 0;
+
+	if (S_ISDIR(inode->i_mode)) {
+		error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl);
+		if (error)
+			return -error;
+	}
+
+	clone = posix_acl_clone(default_acl, GFP_KERNEL);
+	if (!clone)
+		return ENOMEM;
+
+	mode = inode->i_mode;
+	error = posix_acl_create_masq(clone, &mode);
+	if (error < 0)
+		goto out_release_clone;
+
+	error = xfs_set_mode(inode, mode);
+	if (error > 0)
+		error = xfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
+	xfs_iflags_set(ip, XFS_IMODIFIED);
+
+ out_release_clone:
+	posix_acl_release(clone);
+	return -error;
+}
+
+int xfs_acl_chmod(struct inode *inode)
+{
+	struct posix_acl *acl, *clone;
+	int error;
+
+	if (S_ISLNK(inode->i_mode))
+		return -EOPNOTSUPP;
+
+	acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
+	if (IS_ERR(acl) || !acl)
+		return PTR_ERR(acl);
+
+	clone = posix_acl_clone(acl, GFP_KERNEL);
+	posix_acl_release(acl);
+	if (!clone)
+		return -ENOMEM;
+
+	error = posix_acl_chmod_masq(clone, inode->i_mode);
+	if (!error)
+		error = xfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
+
+	posix_acl_release(clone);
+	return error;
+}
+
+void xfs_inode_init_acls(struct xfs_inode *ip)
+{
+	ip->i_acl = XFS_ACL_NOT_CACHED;
+	ip->i_default_acl = XFS_ACL_NOT_CACHED;
+}
+
+static void xfs_clear_acl(struct posix_acl **aclp)
+{
+	if (*aclp != XFS_ACL_NOT_CACHED) {
+		posix_acl_release(*aclp);
+		*aclp = XFS_ACL_NOT_CACHED;
+	}
+}
+
+void xfs_inode_clear_acls(struct xfs_inode *ip)
+{
+	xfs_clear_acl(&ip->i_acl);
+	xfs_clear_acl(&ip->i_default_acl);
+}
Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/linux-2.6/xfs_iops.c	2008-05-02 19:20:38.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c	2008-05-02 19:34:18.000000000 +0200
@@ -51,6 +51,7 @@
 #include <linux/capability.h>
 #include <linux/xattr.h>
 #include <linux/namei.h>
+#include <linux/posix_acl.h>
 #include <linux/security.h>
 #include <linux/falloc.h>
 
@@ -276,9 +277,8 @@ xfs_vn_mknod(
 {
 	struct inode	*inode;
 	struct xfs_inode *ip = NULL;
-	xfs_acl_t	*default_acl = NULL;
+	struct posix_acl *default_acl = NULL;
 	struct xfs_name	name;
-	int (*test_default_acl)(struct inode *) = _ACL_DEFAULT_EXISTS;
 	int		error;
 
 	/*
@@ -288,21 +288,17 @@ xfs_vn_mknod(
 	if (unlikely(!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff))
 		return -EINVAL;
 
-	if (test_default_acl && test_default_acl(dir)) {
-		if (!_ACL_ALLOC(default_acl)) {
-			return -ENOMEM;
-		}
-		if (!_ACL_GET_DEFAULT(dir, default_acl)) {
-			_ACL_FREE(default_acl);
-			default_acl = NULL;
-		}
+	if (IS_POSIXACL(dir)) {
+		default_acl = xfs_get_acl(dir, ACL_TYPE_DEFAULT);
+		if (IS_ERR(default_acl))
+			return -PTR_ERR(default_acl);
+
+		if (!default_acl)
+			mode &= ~current->fs->umask;
 	}
 
 	xfs_dentry_to_name(&name, dentry);
 
-	if (IS_POSIXACL(dir) && !default_acl)
-		mode &= ~current->fs->umask;
-
 	switch (mode & S_IFMT) {
 	case S_IFCHR:
 	case S_IFBLK:
@@ -330,11 +326,11 @@ xfs_vn_mknod(
 		goto out_cleanup_inode;
 
 	if (default_acl) {
-		error = _ACL_INHERIT(inode, mode, default_acl);
+		error = xfs_inherit_acl(inode, default_acl);
 		if (unlikely(error))
 			goto out_cleanup_inode;
 		xfs_iflags_set(ip, XFS_IMODIFIED);
-		_ACL_FREE(default_acl);
+		posix_acl_release(default_acl);
 	}
 
 
@@ -347,8 +343,7 @@ xfs_vn_mknod(
  out_cleanup_inode:
 	xfs_cleanup_inode(dir, inode, dentry);
  out_free_acl:
-	if (default_acl)
-		_ACL_FREE(default_acl);
+	posix_acl_release(default_acl);
 	return -error;
 }
 
@@ -550,38 +545,6 @@ xfs_vn_put_link(
 		kfree(s);
 }
 
-#ifdef CONFIG_XFS_POSIX_ACL
-STATIC int
-xfs_check_acl(
-	struct inode		*inode,
-	int			mask)
-{
-	struct xfs_inode	*ip = XFS_I(inode);
-	int			error;
-
-	xfs_itrace_entry(ip);
-
-	if (XFS_IFORK_Q(ip)) {
-		error = xfs_acl_iaccess(ip, mask, NULL);
-		if (error != -1)
-			return -error;
-	}
-
-	return -EAGAIN;
-}
-
-STATIC int
-xfs_vn_permission(
-	struct inode		*inode,
-	int			mask,
-	struct nameidata	*nd)
-{
-	return generic_permission(inode, mask, xfs_check_acl);
-}
-#else
-#define xfs_vn_permission NULL
-#endif
-
 STATIC int
 xfs_vn_getattr(
 	struct vfsmount		*mnt,
@@ -694,6 +657,9 @@ xfs_vn_setattr(
 	error = xfs_setattr(XFS_I(inode), &vattr, flags, NULL);
 	if (likely(!error))
 		vn_revalidate(vn_from_inode(inode));
+
+	if (!error && (attr->ia_valid & ATTR_MODE))
+		error = -xfs_acl_chmod(inode);
 	return -error;
 }
 
Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.h
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/linux-2.6/xfs_iops.h	2008-05-02 19:14:00.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.h	2008-05-02 19:34:18.000000000 +0200
@@ -31,6 +31,12 @@ extern void xfs_ichgtime_fast(struct xfs
 
 extern void xfs_setup_inode(struct xfs_inode *);
 
+#ifdef CONFIG_XFS_POSIX_ACL
+int xfs_vn_permission(struct inode *inode, int mask, struct nameidata *nd);
+#else
+#define xfs_vn_permission NULL
+#endif
+
 #define xfs_vtoi(vp) \
 	((struct xfs_inode *)vn_to_inode(vp)->i_private)
 
Index: linux-2.6-xfs/fs/xfs/xfs_acl.h
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_acl.h	2008-05-02 19:14:00.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/xfs_acl.h	2008-05-02 19:34:18.000000000 +0200
@@ -18,27 +18,25 @@
 #ifndef __XFS_ACL_H__
 #define __XFS_ACL_H__
 
+struct inode;
+struct posix_acl;
+struct xfs_inode;
+
+
 /*
  * Access Control Lists
  */
-typedef __uint16_t	xfs_acl_perm_t;
-typedef __int32_t	xfs_acl_type_t;
-typedef __int32_t	xfs_acl_tag_t;
-typedef __int32_t	xfs_acl_id_t;
-
 #define XFS_ACL_MAX_ENTRIES 25
 #define XFS_ACL_NOT_PRESENT (-1)
 
-typedef struct xfs_acl_entry {
-	xfs_acl_tag_t	ae_tag;
-	xfs_acl_id_t	ae_id;
-	xfs_acl_perm_t	ae_perm;
-} xfs_acl_entry_t;
-
-typedef struct xfs_acl {
-	__int32_t	acl_cnt;
-	xfs_acl_entry_t	acl_entry[XFS_ACL_MAX_ENTRIES];
-} xfs_acl_t;
+struct xfs_acl {
+	__be32		acl_cnt;
+	struct xfs_acl_entry {
+		__be32	ae_tag;
+		__be32	ae_id;
+		__be16	ae_perm;
+	} acl_entry[XFS_ACL_MAX_ENTRIES];
+};
 
 /* On-disk XFS extended attribute names */
 #define SGI_ACL_FILE	"SGI_ACL_FILE"
@@ -49,51 +47,35 @@ typedef struct xfs_acl {
 
 #ifdef CONFIG_XFS_POSIX_ACL
 
-struct vattr;
-struct xfs_inode;
-
-extern struct kmem_zone *xfs_acl_zone;
-#define xfs_acl_zone_init(zone, name)	\
-		(zone) = kmem_zone_init(sizeof(xfs_acl_t), (name))
-#define xfs_acl_zone_destroy(zone)	kmem_zone_destroy(zone)
-
-extern int xfs_acl_inherit(bhv_vnode_t *, mode_t mode, xfs_acl_t *);
-extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *);
-extern int xfs_acl_vtoacl(bhv_vnode_t *, xfs_acl_t *, xfs_acl_t *);
-extern int xfs_acl_vhasacl_access(bhv_vnode_t *);
-extern int xfs_acl_vhasacl_default(bhv_vnode_t *);
-extern int xfs_acl_vset(bhv_vnode_t *, void *, size_t, int);
-extern int xfs_acl_vget(bhv_vnode_t *, void *, size_t, int);
-extern int xfs_acl_vremove(bhv_vnode_t *, int);
-
-#define _ACL_TYPE_ACCESS	1
-#define _ACL_TYPE_DEFAULT	2
-#define _ACL_PERM_INVALID(perm)	((perm) & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE))
-
-#define _ACL_INHERIT(c,m,d)	(xfs_acl_inherit(c,m,d))
-#define _ACL_GET_ACCESS(pv,pa)	(xfs_acl_vtoacl(pv,pa,NULL) == 0)
-#define _ACL_GET_DEFAULT(pv,pd)	(xfs_acl_vtoacl(pv,NULL,pd) == 0)
-#define _ACL_ACCESS_EXISTS	xfs_acl_vhasacl_access
-#define _ACL_DEFAULT_EXISTS	xfs_acl_vhasacl_default
+struct posix_acl *xfs_get_acl(struct inode *inode, int type);
+int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl);
+int xfs_acl_chmod(struct inode *inode);
+void xfs_inode_init_acls(struct xfs_inode *ip);
+void xfs_inode_clear_acls(struct xfs_inode *ip);
+int posix_acl_access_exists(struct inode *inode);
+int posix_acl_default_exists(struct inode *inode);
 
-#define _ACL_ALLOC(a)		((a) = kmem_zone_alloc(xfs_acl_zone, KM_SLEEP))
-#define _ACL_FREE(a)		((a)? kmem_zone_free(xfs_acl_zone, (a)):(void)0)
+extern struct xattr_handler xfs_xattr_system_handler;
 
 #else
-#define xfs_acl_zone_init(zone,name)
-#define xfs_acl_zone_destroy(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_ALLOC(a)		(1)	/* successfully allocate nothing */
-#define _ACL_FREE(a)		((void)0)
-#define _ACL_INHERIT(c,m,d)	(0)
-#define _ACL_GET_ACCESS(pv,pa)	(0)
-#define _ACL_GET_DEFAULT(pv,pd)	(0)
-#define _ACL_ACCESS_EXISTS	(NULL)
-#define _ACL_DEFAULT_EXISTS	(NULL)
-#endif
 
+static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
+{
+	BUG();
+}
+static inline int xfs_inherit_acl(struct inode *inode,
+		struct posix_acl *default_acl)
+{
+	BUG();
+}
+
+static inline void xfs_inode_init_acls(struct xfs_inode *ip)
+{
+}
+
+static inline void xfs_inode_clear_acls(struct xfs_inode *ip)
+{
+}
+
+#endif /* CONFIG_XFS_POSIX_ACL */
 #endif	/* __XFS_ACL_H__ */
Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_ksyms.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/linux-2.6/xfs_ksyms.c	2008-05-02 19:14:00.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/linux-2.6/xfs_ksyms.c	2008-05-02 19:34:18.000000000 +0200
@@ -51,7 +51,6 @@
 #include "xfs_dir2_block.h"
 #include "xfs_dir2_node.h"
 #include "xfs_dir2_trace.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_inode_item.h"
@@ -179,10 +178,6 @@ EXPORT_SYMBOL(uuid_table_remove);
 EXPORT_SYMBOL(vn_hold);
 EXPORT_SYMBOL(vn_revalidate);
 
-#if defined(CONFIG_XFS_POSIX_ACL)
-EXPORT_SYMBOL(xfs_acl_vtoacl);
-EXPORT_SYMBOL(xfs_acl_inherit);
-#endif
 EXPORT_SYMBOL(xfs_alloc_buftarg);
 EXPORT_SYMBOL(xfs_flush_buftarg);
 EXPORT_SYMBOL(xfs_free_buftarg);
Index: linux-2.6-xfs/fs/xfs/xfs_vfsops.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_vfsops.c	2008-05-02 19:14:00.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/xfs_vfsops.c	2008-05-02 19:34:18.000000000 +0200
@@ -80,7 +80,6 @@ xfs_init(void)
 	xfs_dabuf_zone = kmem_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf");
 	xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork");
 	xfs_trans_zone = kmem_zone_init(sizeof(xfs_trans_t), "xfs_trans");
-	xfs_acl_zone_init(xfs_acl_zone, "xfs_acl");
 	xfs_mru_cache_init();
 	xfs_filestream_init();
 
@@ -157,7 +156,6 @@ xfs_cleanup(void)
 	xfs_sysctl_unregister();
 	xfs_filestream_uninit();
 	xfs_mru_cache_uninit();
-	xfs_acl_zone_destroy(xfs_acl_zone);
 
 #ifdef XFS_DIR2_TRACE
 	ktrace_free(xfs_dir2_trace_buf);
Index: linux-2.6-xfs/fs/xfs/xfs_acl.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_acl.c	2008-05-02 19:14:00.000000000 +0200
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,882 +0,0 @@
-/*
- * Copyright (c) 2001-2002,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_types.h"
-#include "xfs_bit.h"
-#include "xfs_inum.h"
-#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
-#include "xfs_inode.h"
-#include "xfs_btree.h"
-#include "xfs_acl.h"
-#include "xfs_attr.h"
-#include "xfs_vnodeops.h"
-
-#include <linux/capability.h>
-#include <linux/posix_acl_xattr.h>
-
-STATIC int	xfs_acl_setmode(bhv_vnode_t *, xfs_acl_t *, int *);
-STATIC void     xfs_acl_filter_mode(mode_t, xfs_acl_t *);
-STATIC void	xfs_acl_get_endian(xfs_acl_t *);
-STATIC int	xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *);
-STATIC int	xfs_acl_invalid(xfs_acl_t *);
-STATIC void	xfs_acl_sync_mode(mode_t, xfs_acl_t *);
-STATIC void	xfs_acl_get_attr(bhv_vnode_t *, xfs_acl_t *, int, int, int *);
-STATIC void	xfs_acl_set_attr(bhv_vnode_t *, xfs_acl_t *, int, int *);
-STATIC int	xfs_acl_allow_set(bhv_vnode_t *, int);
-
-kmem_zone_t *xfs_acl_zone;
-
-
-/*
- * Test for existence of access ACL attribute as efficiently as possible.
- */
-int
-xfs_acl_vhasacl_access(
-	bhv_vnode_t	*vp)
-{
-	int		error;
-
-	xfs_acl_get_attr(vp, NULL, _ACL_TYPE_ACCESS, ATTR_KERNOVAL, &error);
-	return (error == 0);
-}
-
-/*
- * Test for existence of default ACL attribute as efficiently as possible.
- */
-int
-xfs_acl_vhasacl_default(
-	bhv_vnode_t	*vp)
-{
-	int		error;
-
-	if (!S_ISDIR(vp->i_mode))
-		return 0;
-	xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error);
-	return (error == 0);
-}
-
-/*
- * Convert from extended attribute representation to in-memory for XFS.
- */
-STATIC int
-posix_acl_xattr_to_xfs(
-	posix_acl_xattr_header	*src,
-	size_t			size,
-	xfs_acl_t		*dest)
-{
-	posix_acl_xattr_entry	*src_entry;
-	xfs_acl_entry_t		*dest_entry;
-	int			n;
-
-	if (!src || !dest)
-		return EINVAL;
-
-	if (size < sizeof(posix_acl_xattr_header))
-		return EINVAL;
-
-	if (src->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
-		return EOPNOTSUPP;
-
-	memset(dest, 0, sizeof(xfs_acl_t));
-	dest->acl_cnt = posix_acl_xattr_count(size);
-	if (dest->acl_cnt < 0 || dest->acl_cnt > XFS_ACL_MAX_ENTRIES)
-		return EINVAL;
-
-	/*
-	 * acl_set_file(3) may request that we set default ACLs with
-	 * zero length -- defend (gracefully) against that here.
-	 */
-	if (!dest->acl_cnt)
-		return 0;
-
-	src_entry = (posix_acl_xattr_entry *)((char *)src + sizeof(*src));
-	dest_entry = &dest->acl_entry[0];
-
-	for (n = 0; n < dest->acl_cnt; n++, src_entry++, dest_entry++) {
-		dest_entry->ae_perm = le16_to_cpu(src_entry->e_perm);
-		if (_ACL_PERM_INVALID(dest_entry->ae_perm))
-			return EINVAL;
-		dest_entry->ae_tag  = le16_to_cpu(src_entry->e_tag);
-		switch(dest_entry->ae_tag) {
-		case ACL_USER:
-		case ACL_GROUP:
-			dest_entry->ae_id = le32_to_cpu(src_entry->e_id);
-			break;
-		case ACL_USER_OBJ:
-		case ACL_GROUP_OBJ:
-		case ACL_MASK:
-		case ACL_OTHER:
-			dest_entry->ae_id = ACL_UNDEFINED_ID;
-			break;
-		default:
-			return EINVAL;
-		}
-	}
-	if (xfs_acl_invalid(dest))
-		return EINVAL;
-
-	return 0;
-}
-
-/*
- * Comparison function called from xfs_sort().
- * Primary key is ae_tag, secondary key is ae_id.
- */
-STATIC int
-xfs_acl_entry_compare(
-	const void	*va,
-	const void	*vb)
-{
-	xfs_acl_entry_t	*a = (xfs_acl_entry_t *)va,
-			*b = (xfs_acl_entry_t *)vb;
-
-	if (a->ae_tag == b->ae_tag)
-		return (a->ae_id - b->ae_id);
-	return (a->ae_tag - b->ae_tag);
-}
-
-/*
- * Convert from in-memory XFS to extended attribute representation.
- */
-STATIC int
-posix_acl_xfs_to_xattr(
-	xfs_acl_t		*src,
-	posix_acl_xattr_header	*dest,
-	size_t			size)
-{
-	int			n;
-	size_t			new_size = posix_acl_xattr_size(src->acl_cnt);
-	posix_acl_xattr_entry	*dest_entry;
-	xfs_acl_entry_t		*src_entry;
-
-	if (size < new_size)
-		return -ERANGE;
-
-	/* Need to sort src XFS ACL by <ae_tag,ae_id> */
-	xfs_sort(src->acl_entry, src->acl_cnt, sizeof(src->acl_entry[0]),
-		 xfs_acl_entry_compare);
-
-	dest->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
-	dest_entry = &dest->a_entries[0];
-	src_entry = &src->acl_entry[0];
-	for (n = 0; n < src->acl_cnt; n++, dest_entry++, src_entry++) {
-		dest_entry->e_perm = cpu_to_le16(src_entry->ae_perm);
-		if (_ACL_PERM_INVALID(src_entry->ae_perm))
-			return -EINVAL;
-		dest_entry->e_tag  = cpu_to_le16(src_entry->ae_tag);
-		switch (src_entry->ae_tag) {
-		case ACL_USER:
-		case ACL_GROUP:
-			dest_entry->e_id = cpu_to_le32(src_entry->ae_id);
-				break;
-		case ACL_USER_OBJ:
-		case ACL_GROUP_OBJ:
-		case ACL_MASK:
-		case ACL_OTHER:
-			dest_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-	return new_size;
-}
-
-int
-xfs_acl_vget(
-	bhv_vnode_t	*vp,
-	void		*acl,
-	size_t		size,
-	int		kind)
-{
-	int			error;
-	xfs_acl_t		*xfs_acl = NULL;
-	posix_acl_xattr_header	*ext_acl = acl;
-	int			flags = 0;
-
-	VN_HOLD(vp);
-	if(size) {
-		if (!(_ACL_ALLOC(xfs_acl))) {
-			error = ENOMEM;
-			goto out;
-		}
-		memset(xfs_acl, 0, sizeof(xfs_acl_t));
-	} else
-		flags = ATTR_KERNOVAL;
-
-	xfs_acl_get_attr(vp, xfs_acl, kind, flags, &error);
-	if (error)
-		goto out;
-
-	if (!size) {
-		error = -posix_acl_xattr_size(XFS_ACL_MAX_ENTRIES);
-	} else {
-		if (xfs_acl_invalid(xfs_acl)) {
-			error = EINVAL;
-			goto out;
-		}
-		if (kind == _ACL_TYPE_ACCESS)
-			xfs_acl_sync_mode(xfs_vtoi(vp)->i_d.di_mode, xfs_acl);
-		error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size);
-	}
-out:
-	VN_RELE(vp);
-	if(xfs_acl)
-		_ACL_FREE(xfs_acl);
-	return -error;
-}
-
-int
-xfs_acl_vremove(
-	bhv_vnode_t	*vp,
-	int		kind)
-{
-	int		error;
-
-	VN_HOLD(vp);
-	error = xfs_acl_allow_set(vp, kind);
-	if (!error) {
-		error = xfs_attr_remove(xfs_vtoi(vp),
-						kind == _ACL_TYPE_DEFAULT?
-						SGI_ACL_DEFAULT: SGI_ACL_FILE,
-						ATTR_ROOT);
-		if (error == ENOATTR)
-			error = 0;	/* 'scool */
-	}
-	VN_RELE(vp);
-	return -error;
-}
-
-int
-xfs_acl_vset(
-	bhv_vnode_t		*vp,
-	void			*acl,
-	size_t			size,
-	int			kind)
-{
-	posix_acl_xattr_header	*ext_acl = acl;
-	xfs_acl_t		*xfs_acl;
-	int			error;
-	int			basicperms = 0; /* more than std unix perms? */
-
-	if (!acl)
-		return -EINVAL;
-
-	if (!(_ACL_ALLOC(xfs_acl)))
-		return -ENOMEM;
-
-	error = posix_acl_xattr_to_xfs(ext_acl, size, xfs_acl);
-	if (error) {
-		_ACL_FREE(xfs_acl);
-		return -error;
-	}
-	if (!xfs_acl->acl_cnt) {
-		_ACL_FREE(xfs_acl);
-		return 0;
-	}
-
-	VN_HOLD(vp);
-	error = xfs_acl_allow_set(vp, kind);
-
-	/* Incoming ACL exists, set file mode based on its value */
-	if (!error && kind == _ACL_TYPE_ACCESS)
-		error = xfs_acl_setmode(vp, xfs_acl, &basicperms);
-
-	if (error)
-		goto out;
-
-	/*
-	 * If we have more than std unix permissions, set up the actual attr.
-	 * Otherwise, delete any existing attr.  This prevents us from
-	 * having actual attrs for permissions that can be stored in the
-	 * standard permission bits.
-	 */
-	if (!basicperms) {
-		xfs_acl_set_attr(vp, xfs_acl, kind, &error);
-	} else {
-		error = -xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
-	}
-
-out:
-	VN_RELE(vp);
-	_ACL_FREE(xfs_acl);
-	return -error;
-}
-
-int
-xfs_acl_iaccess(
-	xfs_inode_t	*ip,
-	mode_t		mode,
-	cred_t		*cr)
-{
-	xfs_acl_t	*acl;
-	int		rval;
-	struct xfs_name	acl_name = {SGI_ACL_FILE, SGI_ACL_FILE_SIZE};
-
-	if (!(_ACL_ALLOC(acl)))
-		return -1;
-
-	/* If the file has no ACL return -1. */
-	rval = sizeof(xfs_acl_t);
-	if (xfs_attr_fetch(ip, &acl_name, (char *)acl, &rval,
-					ATTR_ROOT | ATTR_KERNACCESS)) {
-		_ACL_FREE(acl);
-		return -1;
-	}
-	xfs_acl_get_endian(acl);
-
-	/* If the file has an empty ACL return -1. */
-	if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) {
-		_ACL_FREE(acl);
-		return -1;
-	}
-
-	/* Synchronize ACL with mode bits */
-	xfs_acl_sync_mode(ip->i_d.di_mode, acl);
-
-	rval = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr);
-	_ACL_FREE(acl);
-	return rval;
-}
-
-STATIC int
-xfs_acl_allow_set(
-	bhv_vnode_t	*vp,
-	int		kind)
-{
-	if (vp->i_flags & (S_IMMUTABLE|S_APPEND))
-		return EPERM;
-	if (kind == _ACL_TYPE_DEFAULT && !S_ISDIR(vp->i_mode))
-		return ENOTDIR;
-	if (vp->i_sb->s_flags & MS_RDONLY)
-		return EROFS;
-	if (xfs_vtoi(vp)->i_d.di_uid != current->fsuid && !capable(CAP_FOWNER))
-		return EPERM;
-	return 0;
-}
-
-/*
- * Note: cr is only used here for the capability check if the ACL test fails.
- *       It is not used to find out the credentials uid or groups etc, as was
- *       done in IRIX. It is assumed that the uid and groups for the current
- *       thread are taken from "current" instead of the cr parameter.
- */
-STATIC int
-xfs_acl_access(
-	uid_t		fuid,
-	gid_t		fgid,
-	xfs_acl_t	*fap,
-	mode_t		md,
-	cred_t		*cr)
-{
-	xfs_acl_entry_t	matched;
-	int		i, allows;
-	int		maskallows = -1;	/* true, but not 1, either */
-	int		seen_userobj = 0;
-
-	matched.ae_tag = 0;	/* Invalid type */
-	matched.ae_perm = 0;
-
-	for (i = 0; i < fap->acl_cnt; i++) {
-		/*
-		 * Break out if we've got a user_obj entry or
-		 * a user entry and the mask (and have processed USER_OBJ)
-		 */
-		if (matched.ae_tag == ACL_USER_OBJ)
-			break;
-		if (matched.ae_tag == ACL_USER) {
-			if (maskallows != -1 && seen_userobj)
-				break;
-			if (fap->acl_entry[i].ae_tag != ACL_MASK &&
-			    fap->acl_entry[i].ae_tag != ACL_USER_OBJ)
-				continue;
-		}
-		/* True if this entry allows the requested access */
-		allows = ((fap->acl_entry[i].ae_perm & md) == md);
-
-		switch (fap->acl_entry[i].ae_tag) {
-		case ACL_USER_OBJ:
-			seen_userobj = 1;
-			if (fuid != current->fsuid)
-				continue;
-			matched.ae_tag = ACL_USER_OBJ;
-			matched.ae_perm = allows;
-			break;
-		case ACL_USER:
-			if (fap->acl_entry[i].ae_id != current->fsuid)
-				continue;
-			matched.ae_tag = ACL_USER;
-			matched.ae_perm = allows;
-			break;
-		case ACL_GROUP_OBJ:
-			if ((matched.ae_tag == ACL_GROUP_OBJ ||
-			    matched.ae_tag == ACL_GROUP) && !allows)
-				continue;
-			if (!in_group_p(fgid))
-				continue;
-			matched.ae_tag = ACL_GROUP_OBJ;
-			matched.ae_perm = allows;
-			break;
-		case ACL_GROUP:
-			if ((matched.ae_tag == ACL_GROUP_OBJ ||
-			    matched.ae_tag == ACL_GROUP) && !allows)
-				continue;
-			if (!in_group_p(fap->acl_entry[i].ae_id))
-				continue;
-			matched.ae_tag = ACL_GROUP;
-			matched.ae_perm = allows;
-			break;
-		case ACL_MASK:
-			maskallows = allows;
-			break;
-		case ACL_OTHER:
-			if (matched.ae_tag != 0)
-				continue;
-			matched.ae_tag = ACL_OTHER;
-			matched.ae_perm = allows;
-			break;
-		}
-	}
-	/*
-	 * First possibility is that no matched entry allows access.
-	 * The capability to override DAC may exist, so check for it.
-	 */
-	switch (matched.ae_tag) {
-	case ACL_OTHER:
-	case ACL_USER_OBJ:
-		if (matched.ae_perm)
-			return 0;
-		break;
-	case ACL_USER:
-	case ACL_GROUP_OBJ:
-	case ACL_GROUP:
-		if (maskallows && matched.ae_perm)
-			return 0;
-		break;
-	case 0:
-		break;
-	}
-
-	/* EACCES tells generic_permission to check for capability overrides */
-	return EACCES;
-}
-EXPORT_SYMBOL(xfs_acl_access);
-
-/*
- * ACL validity checker.
- *   This acl validation routine checks each ACL entry read in makes sense.
- */
-STATIC int
-xfs_acl_invalid(
-	xfs_acl_t	*aclp)
-{
-	xfs_acl_entry_t	*entry, *e;
-	int		user = 0, group = 0, other = 0, mask = 0;
-	int		mask_required = 0;
-	int		i, j;
-
-	if (!aclp)
-		goto acl_invalid;
-
-	if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES)
-		goto acl_invalid;
-
-	for (i = 0; i < aclp->acl_cnt; i++) {
-		entry = &aclp->acl_entry[i];
-		switch (entry->ae_tag) {
-		case ACL_USER_OBJ:
-			if (user++)
-				goto acl_invalid;
-			break;
-		case ACL_GROUP_OBJ:
-			if (group++)
-				goto acl_invalid;
-			break;
-		case ACL_OTHER:
-			if (other++)
-				goto acl_invalid;
-			break;
-		case ACL_USER:
-		case ACL_GROUP:
-			for (j = i + 1; j < aclp->acl_cnt; j++) {
-				e = &aclp->acl_entry[j];
-				if (e->ae_id == entry->ae_id &&
-				    e->ae_tag == entry->ae_tag)
-					goto acl_invalid;
-			}
-			mask_required++;
-			break;
-		case ACL_MASK:
-			if (mask++)
-				goto acl_invalid;
-			break;
-		default:
-			goto acl_invalid;
-		}
-	}
-	if (!user || !group || !other || (mask_required && !mask))
-		goto acl_invalid;
-	else
-		return 0;
-acl_invalid:
-	return EINVAL;
-}
-
-/*
- * Do ACL endian conversion.
- */
-STATIC void
-xfs_acl_get_endian(
-	xfs_acl_t	*aclp)
-{
-	xfs_acl_entry_t	*ace, *end;
-
-	INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
-	end = &aclp->acl_entry[0]+aclp->acl_cnt;
-	for (ace = &aclp->acl_entry[0]; ace < end; ace++) {
-		INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag);
-		INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id);
-		INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm);
-	}
-}
-
-/*
- * Get the ACL from the EA and do endian conversion.
- */
-STATIC void
-xfs_acl_get_attr(
-	bhv_vnode_t	*vp,
-	xfs_acl_t	*aclp,
-	int		kind,
-	int		flags,
-	int		*error)
-{
-	int		len = sizeof(xfs_acl_t);
-
-	ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1);
-	flags |= ATTR_ROOT;
-	*error = xfs_attr_get(xfs_vtoi(vp),
-					kind == _ACL_TYPE_ACCESS ?
-					SGI_ACL_FILE : SGI_ACL_DEFAULT,
-					(char *)aclp, &len, flags);
-	if (*error || (flags & ATTR_KERNOVAL))
-		return;
-	xfs_acl_get_endian(aclp);
-}
-
-/*
- * Set the EA with the ACL and do endian conversion.
- */
-STATIC void
-xfs_acl_set_attr(
-	bhv_vnode_t	*vp,
-	xfs_acl_t	*aclp,
-	int		kind,
-	int		*error)
-{
-	xfs_acl_entry_t	*ace, *newace, *end;
-	xfs_acl_t	*newacl;
-	int		len;
-
-	if (!(_ACL_ALLOC(newacl))) {
-		*error = ENOMEM;
-		return;
-	}
-
-	len = sizeof(xfs_acl_t) -
-	      (sizeof(xfs_acl_entry_t) * (XFS_ACL_MAX_ENTRIES - aclp->acl_cnt));
-	end = &aclp->acl_entry[0]+aclp->acl_cnt;
-	for (ace = &aclp->acl_entry[0], newace = &newacl->acl_entry[0];
-	     ace < end;
-	     ace++, newace++) {
-		INT_SET(newace->ae_tag, ARCH_CONVERT, ace->ae_tag);
-		INT_SET(newace->ae_id, ARCH_CONVERT, ace->ae_id);
-		INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm);
-	}
-	INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
-	*error = xfs_attr_set(xfs_vtoi(vp),
-				kind == _ACL_TYPE_ACCESS ?
-				SGI_ACL_FILE: SGI_ACL_DEFAULT,
-				(char *)newacl, len, ATTR_ROOT);
-	_ACL_FREE(newacl);
-}
-
-int
-xfs_acl_vtoacl(
-	bhv_vnode_t	*vp,
-	xfs_acl_t	*access_acl,
-	xfs_acl_t	*default_acl)
-{
-	int		error = 0;
-
-	if (access_acl) {
-		/*
-		 * Get the Access ACL and the mode.  If either cannot
-		 * be obtained for some reason, invalidate the access ACL.
-		 */
-		xfs_acl_get_attr(vp, access_acl, _ACL_TYPE_ACCESS, 0, &error);
-		if (error)
-			access_acl->acl_cnt = XFS_ACL_NOT_PRESENT;
-		else /* We have a good ACL and the file mode, synchronize. */
-			xfs_acl_sync_mode(xfs_vtoi(vp)->i_d.di_mode, access_acl);
-	}
-
-	if (default_acl) {
-		xfs_acl_get_attr(vp, default_acl, _ACL_TYPE_DEFAULT, 0, &error);
-		if (error)
-			default_acl->acl_cnt = XFS_ACL_NOT_PRESENT;
-	}
-	return error;
-}
-
-/*
- * This function retrieves the parent directory's acl, processes it
- * and lets the child inherit the acl(s) that it should.
- */
-int
-xfs_acl_inherit(
-	bhv_vnode_t	*vp,
-	mode_t		mode,
-	xfs_acl_t	*pdaclp)
-{
-	xfs_acl_t	*cacl;
-	int		error = 0;
-	int		basicperms = 0;
-
-	/*
-	 * If the parent does not have a default ACL, or it's an
-	 * invalid ACL, we're done.
-	 */
-	if (!vp)
-		return 0;
-	if (!pdaclp || xfs_acl_invalid(pdaclp))
-		return 0;
-
-	/*
-	 * Copy the default ACL of the containing directory to
-	 * the access ACL of the new file and use the mode that
-	 * was passed in to set up the correct initial values for
-	 * the u::,g::[m::], and o:: entries.  This is what makes
-	 * umask() "work" with ACL's.
-	 */
-
-	if (!(_ACL_ALLOC(cacl)))
-		return ENOMEM;
-
-	memcpy(cacl, pdaclp, sizeof(xfs_acl_t));
-	xfs_acl_filter_mode(mode, cacl);
-	error = xfs_acl_setmode(vp, cacl, &basicperms);
-	if (error)
-		goto out_error;
-
-	/*
-	 * Set the Default and Access ACL on the file.  The mode is already
-	 * set on the file, so we don't need to worry about that.
-	 *
-	 * If the new file is a directory, its default ACL is a copy of
-	 * the containing directory's default ACL.
-	 */
-	if (S_ISDIR(vp->i_mode))
-		xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error);
-	if (!error && !basicperms)
-		xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error);
-out_error:
-	_ACL_FREE(cacl);
-	return error;
-}
-
-/*
- * Set up the correct mode on the file based on the supplied ACL.  This
- * makes sure that the mode on the file reflects the state of the
- * u::,g::[m::], and o:: entries in the ACL.  Since the mode is where
- * the ACL is going to get the permissions for these entries, we must
- * synchronize the mode whenever we set the ACL on a file.
- */
-STATIC int
-xfs_acl_setmode(
-	bhv_vnode_t	*vp,
-	xfs_acl_t	*acl,
-	int		*basicperms)
-{
-	bhv_vattr_t	va;
-	xfs_acl_entry_t	*ap;
-	xfs_acl_entry_t	*gap = NULL;
-	int		i, nomask = 1;
-
-	*basicperms = 1;
-
-	if (acl->acl_cnt == XFS_ACL_NOT_PRESENT)
-		return 0;
-
-	/*
-	 * Copy the u::, g::, o::, and m:: bits from the ACL into the
-	 * mode.  The m:: bits take precedence over the g:: bits.
-	 */
-	va.va_mask = XFS_AT_MODE;
-	va.va_mode = xfs_vtoi(vp)->i_d.di_mode;
-	va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
-	ap = acl->acl_entry;
-	for (i = 0; i < acl->acl_cnt; ++i) {
-		switch (ap->ae_tag) {
-		case ACL_USER_OBJ:
-			va.va_mode |= ap->ae_perm << 6;
-			break;
-		case ACL_GROUP_OBJ:
-			gap = ap;
-			break;
-		case ACL_MASK:	/* more than just standard modes */
-			nomask = 0;
-			va.va_mode |= ap->ae_perm << 3;
-			*basicperms = 0;
-			break;
-		case ACL_OTHER:
-			va.va_mode |= ap->ae_perm;
-			break;
-		default:	/* more than just standard modes */
-			*basicperms = 0;
-			break;
-		}
-		ap++;
-	}
-
-	/* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */
-	if (gap && nomask)
-		va.va_mode |= gap->ae_perm << 3;
-
-	return xfs_setattr(xfs_vtoi(vp), &va, 0, sys_cred);
-}
-
-/*
- * The permissions for the special ACL entries (u::, g::[m::], o::) are
- * actually stored in the file mode (if there is both a group and a mask,
- * the group is stored in the ACL entry and the mask is stored on the file).
- * This allows the mode to remain automatically in sync with the ACL without
- * the need for a call-back to the ACL system at every point where the mode
- * could change.  This function takes the permissions from the specified mode
- * and places it in the supplied ACL.
- *
- * This implementation draws its validity from the fact that, when the ACL
- * was assigned, the mode was copied from the ACL.
- * If the mode did not change, therefore, the mode remains exactly what was
- * taken from the special ACL entries at assignment.
- * If a subsequent chmod() was done, the POSIX spec says that the change in
- * mode must cause an update to the ACL seen at user level and used for
- * access checks.  Before and after a mode change, therefore, the file mode
- * most accurately reflects what the special ACL entries should permit/deny.
- *
- * CAVEAT: If someone sets the SGI_ACL_FILE attribute directly,
- *         the existing mode bits will override whatever is in the
- *         ACL. Similarly, if there is a pre-existing ACL that was
- *         never in sync with its mode (owing to a bug in 6.5 and
- *         before), it will now magically (or mystically) be
- *         synchronized.  This could cause slight astonishment, but
- *         it is better than inconsistent permissions.
- *
- * The supplied ACL is a template that may contain any combination
- * of special entries.  These are treated as place holders when we fill
- * out the ACL.  This routine does not add or remove special entries, it
- * simply unites each special entry with its associated set of permissions.
- */
-STATIC void
-xfs_acl_sync_mode(
-	mode_t		mode,
-	xfs_acl_t	*acl)
-{
-	int		i, nomask = 1;
-	xfs_acl_entry_t	*ap;
-	xfs_acl_entry_t	*gap = NULL;
-
-	/*
-	 * Set ACL entries. POSIX1003.1eD16 requires that the MASK
-	 * be set instead of the GROUP entry, if there is a MASK.
-	 */
-	for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) {
-		switch (ap->ae_tag) {
-		case ACL_USER_OBJ:
-			ap->ae_perm = (mode >> 6) & 0x7;
-			break;
-		case ACL_GROUP_OBJ:
-			gap = ap;
-			break;
-		case ACL_MASK:
-			nomask = 0;
-			ap->ae_perm = (mode >> 3) & 0x7;
-			break;
-		case ACL_OTHER:
-			ap->ae_perm = mode & 0x7;
-			break;
-		default:
-			break;
-		}
-	}
-	/* Set the ACL_GROUP_OBJ if there's no ACL_MASK */
-	if (gap && nomask)
-		gap->ae_perm = (mode >> 3) & 0x7;
-}
-
-/*
- * When inheriting an Access ACL from a directory Default ACL,
- * the ACL bits are set to the intersection of the ACL default
- * permission bits and the file permission bits in mode. If there
- * are no permission bits on the file then we must not give them
- * the ACL. This is what what makes umask() work with ACLs.
- */
-STATIC void
-xfs_acl_filter_mode(
-	mode_t		mode,
-	xfs_acl_t	*acl)
-{
-	int		i, nomask = 1;
-	xfs_acl_entry_t	*ap;
-	xfs_acl_entry_t	*gap = NULL;
-
-	/*
-	 * Set ACL entries. POSIX1003.1eD16 requires that the MASK
-	 * be merged with GROUP entry, if there is a MASK.
-	 */
-	for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) {
-		switch (ap->ae_tag) {
-		case ACL_USER_OBJ:
-			ap->ae_perm &= (mode >> 6) & 0x7;
-			break;
-		case ACL_GROUP_OBJ:
-			gap = ap;
-			break;
-		case ACL_MASK:
-			nomask = 0;
-			ap->ae_perm &= (mode >> 3) & 0x7;
-			break;
-		case ACL_OTHER:
-			ap->ae_perm &= mode & 0x7;
-			break;
-		default:
-			break;
-		}
-	}
-	/* Set the ACL_GROUP_OBJ if there's no ACL_MASK */
-	if (gap && nomask)
-		gap->ae_perm &= (mode >> 3) & 0x7;
-}
Index: linux-2.6-xfs/fs/xfs/Makefile
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/Makefile	2008-05-02 19:14:00.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/Makefile	2008-05-02 19:34:18.000000000 +0200
@@ -29,7 +29,7 @@ obj-$(CONFIG_XFS_QUOTA)		+= quota/
 obj-$(CONFIG_XFS_DMAPI)		+= dmapi/
 
 xfs-$(CONFIG_XFS_RT)		+= xfs_rtalloc.o
-xfs-$(CONFIG_XFS_POSIX_ACL)	+= xfs_acl.o
+xfs-$(CONFIG_XFS_POSIX_ACL)	+= $(XFS_LINUX)/xfs_acl.o
 xfs-$(CONFIG_PROC_FS)		+= $(XFS_LINUX)/xfs_stats.o
 xfs-$(CONFIG_SYSCTL)		+= $(XFS_LINUX)/xfs_sysctl.o
 xfs-$(CONFIG_COMPAT)		+= $(XFS_LINUX)/xfs_ioctl32.o
Index: linux-2.6-xfs/fs/xfs/xfs_inode.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_inode.c	2008-05-02 19:14:00.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/xfs_inode.c	2008-05-02 19:34:18.000000000 +0200
@@ -52,6 +52,7 @@
 #include "xfs_acl.h"
 #include "xfs_filestream.h"
 #include "xfs_vnodeops.h"
+#include "xfs_acl.h"
 
 kmem_zone_t *xfs_ifork_zone;
 kmem_zone_t *xfs_inode_zone;
@@ -816,6 +817,7 @@ xfs_iread(
 	ip->i_mount = mp;
 	atomic_set(&ip->i_iocount, 0);
 	spin_lock_init(&ip->i_flags_lock);
+	xfs_inode_init_acls(ip);
 
 	/*
 	 * Get pointer's to the on-disk inode and the buffer containing it.
@@ -2668,6 +2670,8 @@ xfs_idestroy(
 		}
 		xfs_inode_item_destroy(ip);
 	}
+
+	xfs_inode_clear_acls(ip);
 	kmem_zone_free(xfs_inode_zone, ip);
 }
 
Index: linux-2.6-xfs/fs/xfs/xfs_inode.h
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_inode.h	2008-05-02 19:14:00.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/xfs_inode.h	2008-05-02 19:34:18.000000000 +0200
@@ -18,6 +18,7 @@
 #ifndef	__XFS_INODE_H__
 #define	__XFS_INODE_H__
 
+struct posix_acl;
 struct xfs_dinode;
 struct xfs_dinode_core;
 
@@ -239,6 +240,11 @@ typedef struct xfs_inode {
 	xfs_fsize_t		i_size;		/* in-memory size */
 	xfs_fsize_t		i_new_size;	/* size when write completes */
 	atomic_t		i_iocount;	/* outstanding I/O count */
+
+#ifdef CONFIG_XFS_POSIX_ACL
+	struct posix_acl	*i_acl;
+	struct posix_acl	*i_default_acl;
+#endif
 	/* Trace buffers per inode. */
 #ifdef XFS_INODE_TRACE
 	struct ktrace		*i_trace;	/* general inode trace */
Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_xattr.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/linux-2.6/xfs_xattr.c	2008-05-02 19:14:00.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/linux-2.6/xfs_xattr.c	2008-05-02 19:34:18.000000000 +0200
@@ -12,66 +12,6 @@
 #include <linux/xattr.h>
 
 
-/*
- * ACL handling.  Should eventually be moved into xfs_acl.c
- */
-
-static int
-xfs_decode_acl(const char *name)
-{
-	if (strcmp(name, "posix_acl_access") == 0)
-		return _ACL_TYPE_ACCESS;
-	else if (strcmp(name, "posix_acl_default") == 0)
-		return _ACL_TYPE_DEFAULT;
-	return -EINVAL;
-}
-
-static int
-xfs_xattr_system_get(struct inode *inode, const char *name,
-		void *buffer, size_t size)
-{
-	int acl;
-
-	acl = xfs_decode_acl(name);
-	if (acl < 0)
-		return acl;
-
-	return xfs_acl_vget(inode, buffer, size, acl);
-}
-
-static int
-xfs_xattr_system_set(struct inode *inode, const char *name,
-		const void *value, size_t size, int flags)
-{
-	int error, acl;
-
-	acl = xfs_decode_acl(name);
-	if (acl < 0)
-		return acl;
-	if (flags & XATTR_CREATE)
-		return -EINVAL;
-
-	if (!value)
-		return xfs_acl_vremove(inode, acl);
-
-	error = xfs_acl_vset(inode, (void *)value, size, acl);
-	if (!error)
-		vn_revalidate(inode);
-	return error;
-}
-
-static struct xattr_handler xfs_xattr_system_handler = {
-	.prefix	= XATTR_SYSTEM_PREFIX,
-	.get	= xfs_xattr_system_get,
-	.set	= xfs_xattr_system_set,
-};
-
-
-/*
- * Real xattr handling.  The only difference between the namespaces is
- * a flag passed to the low-level attr code.
- */
-
 static int
 __xfs_xattr_get(struct inode *inode, const char *name,
 		void *value, size_t size, int xflags)
@@ -196,7 +136,9 @@ struct xattr_handler *xfs_xattr_handlers
 	&xfs_xattr_user_handler,
 	&xfs_xattr_trusted_handler,
 	&xfs_xattr_security_handler,
+#ifdef CONFIG_XFS_POSIX_ACL
 	&xfs_xattr_system_handler,
+#endif
 	NULL
 };
 
@@ -246,7 +188,7 @@ xfs_vn_listxattr(struct dentry *dentry, 
 	/*
 	 * Then add the two synthetic ACL attributes.
 	 */
-	if (xfs_acl_vhasacl_access(inode)) {
+	if (posix_acl_access_exists(inode)) {
 		error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
 				strlen(POSIX_ACL_XATTR_ACCESS) + 1,
 				data, size, &result);
@@ -254,7 +196,7 @@ xfs_vn_listxattr(struct dentry *dentry, 
 			return error;
 	}
 
-	if (xfs_acl_vhasacl_default(inode)) {
+	if (posix_acl_default_exists(inode)) {
 		error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
 				strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
 				data, size, &result);
Index: linux-2.6-xfs/fs/xfs/Kconfig
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/Kconfig	2008-05-02 19:14:00.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/Kconfig	2008-05-02 19:34:18.000000000 +0200
@@ -51,6 +51,7 @@ config XFS_DMAPI
 config XFS_POSIX_ACL
 	bool "XFS POSIX ACL support"
 	depends on XFS_FS
+	select FS_POSIX_ACL
 	help
 	  POSIX Access Control Lists (ACLs) support permissions for users and
 	  groups beyond the owner/group/world scheme.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] kill attr_capable callbacks
  2008-04-30 11:22 [PATCH 1/2] kill attr_capable callbacks Christoph Hellwig
  2008-05-12  1:47 ` David Chinner
@ 2008-05-14  7:05 ` Timothy Shimmin
  1 sibling, 0 replies; 5+ messages in thread
From: Timothy Shimmin @ 2008-05-14  7:05 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: xfs

Hi Christoph,

Looks reasonable to me - comparing xattr_permission() with
attr_user_capable() and attr_trusted_capable().
Also the xattr_permission() makes more sense with its MAY_WRITE
testing otherwise it looks like we'd be doing some unfair
tests in the getxattr case.

I'll run thru qa and check in soon.

--Tim


Christoph Hellwig wrote:
> No need for addition permission checks in the xattr handler,
> fs/xattr.c:xattr_permission() already does them, and in fact slightly
> more strict then what was in the attr_capable handlers.
> 
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> 
> Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c
> ===================================================================
> --- linux-2.6-xfs.orig/fs/xfs/linux-2.6/xfs_iops.c	2008-04-29 21:32:56.000000000 +0200
> +++ linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c	2008-04-29 21:33:30.000000000 +0200
> @@ -747,15 +747,11 @@ xfs_vn_setxattr(
>  	char		*attr = (char *)name;
>  	attrnames_t	*namesp;
>  	int		xflags = 0;
> -	int		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;
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (flags & XATTR_CREATE)
> @@ -777,15 +773,11 @@ xfs_vn_getxattr(
>  	char		*attr = (char *)name;
>  	attrnames_t	*namesp;
>  	int		xflags = 0;
> -	ssize_t		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;
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (!size) {
> @@ -825,15 +817,12 @@ xfs_vn_removexattr(
>  	char		*attr = (char *)name;
>  	attrnames_t	*namesp;
>  	int		xflags = 0;
> -	int		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);
>  }
> Index: linux-2.6-xfs/fs/xfs/xfs_attr.c
> ===================================================================
> --- linux-2.6-xfs.orig/fs/xfs/xfs_attr.c	2008-04-29 21:32:25.000000000 +0200
> +++ linux-2.6-xfs/fs/xfs/xfs_attr.c	2008-04-29 21:32:51.000000000 +0200
> @@ -2622,43 +2622,6 @@ attr_lookup_namespace(
>  	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(
> -	bhv_vnode_t	*vp,
> -	cred_t		*cred)
> -{
> -	struct inode	*inode = vn_to_inode(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(
> -	bhv_vnode_t	*vp,
> -	cred_t		*cred)
> -{
> -	struct inode	*inode = vn_to_inode(vp);
> -
> -	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
> -		return -EPERM;
> -	if (!capable(CAP_SYS_ADMIN))
> -		return -EPERM;
> -	return 0;
> -}
> -
>  STATIC int
>  attr_system_set(
>  	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
> @@ -2709,7 +2672,6 @@ struct attrnames 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 = {
> @@ -2719,7 +2681,6 @@ struct attrnames attr_trusted = {
>  	.attr_get	= attr_generic_get,
>  	.attr_set	= attr_generic_set,
>  	.attr_remove	= attr_generic_remove,
> -	.attr_capable	= attr_trusted_capable,
>  };
>  
>  struct attrnames attr_secure = {
> @@ -2729,7 +2690,6 @@ struct attrnames attr_secure = {
>  	.attr_get	= attr_generic_get,
>  	.attr_set	= attr_generic_set,
>  	.attr_remove	= attr_generic_remove,
> -	.attr_capable	= (attrcapable_t)fs_noerr,
>  };
>  
>  struct attrnames attr_user = {
> @@ -2738,7 +2698,6 @@ struct attrnames attr_user = {
>  	.attr_get	= attr_generic_get,
>  	.attr_set	= attr_generic_set,
>  	.attr_remove	= attr_generic_remove,
> -	.attr_capable	= attr_user_capable,
>  };
>  
>  struct attrnames *attr_namespaces[] =
> Index: linux-2.6-xfs/fs/xfs/xfs_attr.h
> ===================================================================
> --- linux-2.6-xfs.orig/fs/xfs/xfs_attr.h	2008-04-29 21:33:38.000000000 +0200
> +++ linux-2.6-xfs/fs/xfs/xfs_attr.h	2008-04-29 21:33:52.000000000 +0200
> @@ -42,7 +42,6 @@ typedef int (*attrset_t)(bhv_vnode_t *, 
>  typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int);
>  typedef int (*attrremove_t)(bhv_vnode_t *, char *, int);
>  typedef int (*attrexists_t)(bhv_vnode_t *);
> -typedef int (*attrcapable_t)(bhv_vnode_t *, struct cred *);
>  
>  typedef struct attrnames {
>  	char *		attr_name;
> @@ -52,7 +51,6 @@ typedef struct attrnames {
>  	attrset_t	attr_set;
>  	attrremove_t	attr_remove;
>  	attrexists_t	attr_exists;
> -	attrcapable_t	attr_capable;
>  } attrnames_t;
>  
>  #define ATTR_NAMECOUNT	4
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2008-05-14  7:05 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-30 11:22 [PATCH 1/2] kill attr_capable callbacks Christoph Hellwig
2008-05-12  1:47 ` David Chinner
2008-05-12  6:22   ` Timothy Shimmin
2008-05-12  6:27   ` Christoph Hellwig
2008-05-14  7:05 ` Timothy Shimmin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox