-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 125798 b: refs/heads/master c: 929fb01 h: refs/heads/master v: v3
- Loading branch information
Tiger Yang
authored and
Mark Fasheh
committed
Jan 5, 2009
1 parent
e6a14c1
commit fdb3dc2
Showing
7 changed files
with
427 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 4e3e9d027f63488e676bf7700ec515a192e54f69 | ||
refs/heads/master: 929fb014e041c6572c5e8c3686f1e32742b5b953 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,378 @@ | ||
/* -*- mode: c; c-basic-offset: 8; -*- | ||
* vim: noexpandtab sw=8 ts=8 sts=0: | ||
* | ||
* acl.c | ||
* | ||
* Copyright (C) 2004, 2008 Oracle. All rights reserved. | ||
* | ||
* CREDITS: | ||
* Lots of code in this file is copy from linux/fs/ext3/acl.c. | ||
* Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public | ||
* License version 2 as published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will 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. | ||
*/ | ||
|
||
#include <linux/init.h> | ||
#include <linux/module.h> | ||
#include <linux/string.h> | ||
|
||
#define MLOG_MASK_PREFIX ML_INODE | ||
#include <cluster/masklog.h> | ||
|
||
#include "ocfs2.h" | ||
#include "alloc.h" | ||
#include "dlmglue.h" | ||
#include "file.h" | ||
#include "ocfs2_fs.h" | ||
|
||
#include "xattr.h" | ||
#include "acl.h" | ||
|
||
/* | ||
* Convert from xattr value to acl struct. | ||
*/ | ||
static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size) | ||
{ | ||
int n, count; | ||
struct posix_acl *acl; | ||
|
||
if (!value) | ||
return NULL; | ||
if (size < sizeof(struct posix_acl_entry)) | ||
return ERR_PTR(-EINVAL); | ||
|
||
count = size / sizeof(struct posix_acl_entry); | ||
if (count < 0) | ||
return ERR_PTR(-EINVAL); | ||
if (count == 0) | ||
return NULL; | ||
|
||
acl = posix_acl_alloc(count, GFP_NOFS); | ||
if (!acl) | ||
return ERR_PTR(-ENOMEM); | ||
for (n = 0; n < count; n++) { | ||
struct ocfs2_acl_entry *entry = | ||
(struct ocfs2_acl_entry *)value; | ||
|
||
acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); | ||
acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); | ||
acl->a_entries[n].e_id = le32_to_cpu(entry->e_id); | ||
value += sizeof(struct posix_acl_entry); | ||
|
||
} | ||
return acl; | ||
} | ||
|
||
/* | ||
* Convert acl struct to xattr value. | ||
*/ | ||
static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size) | ||
{ | ||
struct ocfs2_acl_entry *entry = NULL; | ||
char *ocfs2_acl; | ||
size_t n; | ||
|
||
*size = acl->a_count * sizeof(struct posix_acl_entry); | ||
|
||
ocfs2_acl = kmalloc(*size, GFP_NOFS); | ||
if (!ocfs2_acl) | ||
return ERR_PTR(-ENOMEM); | ||
|
||
entry = (struct ocfs2_acl_entry *)ocfs2_acl; | ||
for (n = 0; n < acl->a_count; n++, entry++) { | ||
entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); | ||
entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); | ||
entry->e_id = cpu_to_le32(acl->a_entries[n].e_id); | ||
} | ||
return ocfs2_acl; | ||
} | ||
|
||
static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode, | ||
int type, | ||
struct buffer_head *di_bh) | ||
{ | ||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
int name_index; | ||
char *value = NULL; | ||
struct posix_acl *acl; | ||
int retval; | ||
|
||
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
return NULL; | ||
|
||
switch (type) { | ||
case ACL_TYPE_ACCESS: | ||
name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; | ||
break; | ||
case ACL_TYPE_DEFAULT: | ||
name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; | ||
break; | ||
default: | ||
return ERR_PTR(-EINVAL); | ||
} | ||
|
||
retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0); | ||
if (retval > 0) { | ||
value = kmalloc(retval, GFP_NOFS); | ||
if (!value) | ||
return ERR_PTR(-ENOMEM); | ||
retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, | ||
"", value, retval); | ||
} | ||
|
||
if (retval > 0) | ||
acl = ocfs2_acl_from_xattr(value, retval); | ||
else if (retval == -ENODATA || retval == 0) | ||
acl = NULL; | ||
else | ||
acl = ERR_PTR(retval); | ||
|
||
kfree(value); | ||
|
||
return acl; | ||
} | ||
|
||
|
||
/* | ||
* Get posix acl. | ||
*/ | ||
static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type) | ||
{ | ||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
struct buffer_head *di_bh = NULL; | ||
struct posix_acl *acl; | ||
int ret; | ||
|
||
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
return NULL; | ||
|
||
ret = ocfs2_inode_lock(inode, &di_bh, 0); | ||
if (ret < 0) { | ||
mlog_errno(ret); | ||
acl = ERR_PTR(ret); | ||
return acl; | ||
} | ||
|
||
acl = ocfs2_get_acl_nolock(inode, type, di_bh); | ||
|
||
ocfs2_inode_unlock(inode, 0); | ||
|
||
brelse(di_bh); | ||
|
||
return acl; | ||
} | ||
|
||
/* | ||
* Set the access or default ACL of an inode. | ||
*/ | ||
static int ocfs2_set_acl(handle_t *handle, | ||
struct inode *inode, | ||
struct buffer_head *di_bh, | ||
int type, | ||
struct posix_acl *acl, | ||
struct ocfs2_alloc_context *meta_ac, | ||
struct ocfs2_alloc_context *data_ac) | ||
{ | ||
int name_index; | ||
void *value = NULL; | ||
size_t size = 0; | ||
int ret; | ||
|
||
if (S_ISLNK(inode->i_mode)) | ||
return -EOPNOTSUPP; | ||
|
||
switch (type) { | ||
case ACL_TYPE_ACCESS: | ||
name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; | ||
if (acl) { | ||
mode_t mode = inode->i_mode; | ||
ret = posix_acl_equiv_mode(acl, &mode); | ||
if (ret < 0) | ||
return ret; | ||
else { | ||
inode->i_mode = mode; | ||
if (ret == 0) | ||
acl = NULL; | ||
} | ||
} | ||
break; | ||
case ACL_TYPE_DEFAULT: | ||
name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; | ||
if (!S_ISDIR(inode->i_mode)) | ||
return acl ? -EACCES : 0; | ||
break; | ||
default: | ||
return -EINVAL; | ||
} | ||
|
||
if (acl) { | ||
value = ocfs2_acl_to_xattr(acl, &size); | ||
if (IS_ERR(value)) | ||
return (int)PTR_ERR(value); | ||
} | ||
|
||
if (handle) | ||
ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index, | ||
"", value, size, 0, | ||
meta_ac, data_ac); | ||
else | ||
ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0); | ||
|
||
kfree(value); | ||
|
||
return ret; | ||
} | ||
|
||
static size_t ocfs2_xattr_list_acl_access(struct inode *inode, | ||
char *list, | ||
size_t list_len, | ||
const char *name, | ||
size_t name_len) | ||
{ | ||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); | ||
|
||
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
return 0; | ||
|
||
if (list && size <= list_len) | ||
memcpy(list, POSIX_ACL_XATTR_ACCESS, size); | ||
return size; | ||
} | ||
|
||
static size_t ocfs2_xattr_list_acl_default(struct inode *inode, | ||
char *list, | ||
size_t list_len, | ||
const char *name, | ||
size_t name_len) | ||
{ | ||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); | ||
|
||
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
return 0; | ||
|
||
if (list && size <= list_len) | ||
memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); | ||
return size; | ||
} | ||
|
||
static int ocfs2_xattr_get_acl(struct inode *inode, | ||
int type, | ||
void *buffer, | ||
size_t size) | ||
{ | ||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
struct posix_acl *acl; | ||
int ret; | ||
|
||
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
return -EOPNOTSUPP; | ||
|
||
acl = ocfs2_get_acl(inode, type); | ||
if (IS_ERR(acl)) | ||
return PTR_ERR(acl); | ||
if (acl == NULL) | ||
return -ENODATA; | ||
ret = posix_acl_to_xattr(acl, buffer, size); | ||
posix_acl_release(acl); | ||
|
||
return ret; | ||
} | ||
|
||
static int ocfs2_xattr_get_acl_access(struct inode *inode, | ||
const char *name, | ||
void *buffer, | ||
size_t size) | ||
{ | ||
if (strcmp(name, "") != 0) | ||
return -EINVAL; | ||
return ocfs2_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size); | ||
} | ||
|
||
static int ocfs2_xattr_get_acl_default(struct inode *inode, | ||
const char *name, | ||
void *buffer, | ||
size_t size) | ||
{ | ||
if (strcmp(name, "") != 0) | ||
return -EINVAL; | ||
return ocfs2_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size); | ||
} | ||
|
||
static int ocfs2_xattr_set_acl(struct inode *inode, | ||
int type, | ||
const void *value, | ||
size_t size) | ||
{ | ||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
struct posix_acl *acl; | ||
int ret = 0; | ||
|
||
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | ||
return -EOPNOTSUPP; | ||
|
||
if (!is_owner_or_cap(inode)) | ||
return -EPERM; | ||
|
||
if (value) { | ||
acl = posix_acl_from_xattr(value, size); | ||
if (IS_ERR(acl)) | ||
return PTR_ERR(acl); | ||
else if (acl) { | ||
ret = posix_acl_valid(acl); | ||
if (ret) | ||
goto cleanup; | ||
} | ||
} else | ||
acl = NULL; | ||
|
||
ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); | ||
|
||
cleanup: | ||
posix_acl_release(acl); | ||
return ret; | ||
} | ||
|
||
static int ocfs2_xattr_set_acl_access(struct inode *inode, | ||
const char *name, | ||
const void *value, | ||
size_t size, | ||
int flags) | ||
{ | ||
if (strcmp(name, "") != 0) | ||
return -EINVAL; | ||
return ocfs2_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); | ||
} | ||
|
||
static int ocfs2_xattr_set_acl_default(struct inode *inode, | ||
const char *name, | ||
const void *value, | ||
size_t size, | ||
int flags) | ||
{ | ||
if (strcmp(name, "") != 0) | ||
return -EINVAL; | ||
return ocfs2_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); | ||
} | ||
|
||
struct xattr_handler ocfs2_xattr_acl_access_handler = { | ||
.prefix = POSIX_ACL_XATTR_ACCESS, | ||
.list = ocfs2_xattr_list_acl_access, | ||
.get = ocfs2_xattr_get_acl_access, | ||
.set = ocfs2_xattr_set_acl_access, | ||
}; | ||
|
||
struct xattr_handler ocfs2_xattr_acl_default_handler = { | ||
.prefix = POSIX_ACL_XATTR_DEFAULT, | ||
.list = ocfs2_xattr_list_acl_default, | ||
.get = ocfs2_xattr_get_acl_default, | ||
.set = ocfs2_xattr_set_acl_default, | ||
}; |
Oops, something went wrong.