今天继续看ext2源代码的acl.c文件,这个文件代码有点多是一些acl权限控制的实现,有点麻烦-_-,代码注释都是中文的,大家有问题随时欢迎骚扰哦
在分析之前,为了不让大家看代码的时候感到有疑惑,给大家科普一下acl结构体的posix实现和ext2实现。acl的基本我上节应该都说过了,然后我们来看一下posix实现,定义如下
看到这里大家可能会感到疑惑定义a_entries[0]是什么意思,这不和没定义一样吗?错了,大不一样!这里的实现非常巧妙,在linux内核里,posix结构是开头是struct posix_acl,后边的控制项有几个,就连这几个posix_acl_entry结构体,而这个a_entries[0]明明不占用空间,却方便了访问后边的acl项,如果想访问第一个,就直接p->a_entries[0]就可以了,因为后边的acl项在内存上是连续的,至少虚拟内存上是这样的。看到这里我真的是赞不绝口,为这些内核coder深深折服啊。
而ext2的acl实现我们上节就已经探讨过了,然后就可以直接看acl.c啦
在分析之前,为了不让大家看代码的时候感到有疑惑,给大家科普一下acl结构体的posix实现和ext2实现。acl的基本我上节应该都说过了,然后我们来看一下posix实现,定义如下
struct posix_acl {
/*引用计数*/
atomic_t a_refcount;
/*内部有几个acl项*/
unsigned int a_count;
/*实际数据区*/
struct posix_acl_entry a_entries[0];
};
/*acl项结构体*/
struct posix_acl_entry {
short e_tag;
unsigned short e_perm;
unsigned int e_id;
};
看到这里大家可能会感到疑惑定义a_entries[0]是什么意思,这不和没定义一样吗?错了,大不一样!这里的实现非常巧妙,在linux内核里,posix结构是开头是struct posix_acl,后边的控制项有几个,就连这几个posix_acl_entry结构体,而这个a_entries[0]明明不占用空间,却方便了访问后边的acl项,如果想访问第一个,就直接p->a_entries[0]就可以了,因为后边的acl项在内存上是连续的,至少虚拟内存上是这样的。看到这里我真的是赞不绝口,为这些内核coder深深折服啊。
而ext2的acl实现我们上节就已经探讨过了,然后就可以直接看acl.c啦
/*
* linux/fs/ext2/acl.c
*
* Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
*/
#include <linux/capability.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
/*把硬盘上的ext2的acl数据转成内存上的posix标准的acl数据
ext2文件系统的acl格式数据是开头是一个ext2_acl_header结构体的ext2头部,然后接下来是ext2_acl_entry_short或者是ext2_acl_entry结构体的acl实体
内存存储的posix标准的acl数据是开头是一个posix_acl结构体,然后随后就是count个posix_acl_entry结构体
*/
static struct posix_acl *
ext2_acl_from_disk(const void *value, size_t size)
{
const char *end = (char *)value + size;
int n, count;
struct posix_acl *acl;
/*如果参数是NULL,直接返回NULL*/
if (!value)
return NULL;
/*如果大小小于ext2_acl_header大小,说明有错误*/
if (size < sizeof(ext2_acl_header))
return ERR_PTR(-EINVAL);
/*如果数据合法的话,开头肯定是ext2_acl_header,直接转化为ext2_acl_header指针,检验当前版本是否一致*/
if (((ext2_acl_header *)value)->a_version !=
cpu_to_le32(EXT2_ACL_VERSION))
return ERR_PTR(-EINVAL);
/*value指向头部后边的数据部分*/
value = (char *)value + sizeof(ext2_acl_header);
/*这个函数之前讲过,根据acl数据大小返回数据项数目*/
count = ext2_acl_count(size);
/*返回参数检查*/
if (count < 0)
return ERR_PTR(-EINVAL);
if (count == 0)
return NULL;
/*根据返回的 项数,分配一定的posix标准结构体内存,这个函数是在fs/posix_acl.c实现,实现很简单*/
acl = posix_acl_alloc(count, GFP_KERNEL);
if (!acl)
return ERR_PTR(-ENOMEM);
/*大循环来啦,对于每一项赋值*/
for (n=0; n < count; n++) {
/*entry指针指向第n项的ext2格式数据*/
ext2_acl_entry *entry =
(ext2_acl_entry *)value;
/*检验边界是不是有问题,linux内核源代码真的是好严谨,至少我不会这么做*/
if ((char *)value + sizeof(ext2_acl_entry_short) > end)
goto fail;
/*直接赋值,ext2文件系统是小端字节序,使用宏转化为cpu字节序
另外我也觉得posix标准的struct posix_acl实现是一个很巧妙的实现,利用了c语言的开放性,大家可以看一下posix标准的linux源代码,真的很巧妙*/
acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
/*根据e_tag的不同,e_id也不同,仅有两种e_tag的e_id不是空的,这是POSIX标准规定的*/
switch(acl->a_entries[n].e_tag) {
/*这四种情况,在ext2的实现上都是为空,但是在POSIX标准,都是ACL_UNDEFINED_ID*/
case ACL_USER_OBJ:
case ACL_GROUP_OBJ:
case ACL_MASK:
case ACL_OTHER:
value = (char *)value +
sizeof(ext2_acl_entry_sho