HDFS-文件访问权限处理模块儿

Hadoop文件访问权限处理与linux采用类似的方式,文件对操作对应有:读,,执行。文件有其属主,以及群。

该部分主要涉及的类如下:

 

FsAction

public enum FsAction

 

这是一个enum对象,描述对文件的操作行为,主要的成员为:

 

  NONE(0, "---"),

  EXECUTE(1, "--x"),

  WRITE(2, "-w-"),

  WRITE_EXECUTE(3, "-wx"),

  READ(4, "r--"),

  READ_EXECUTE(5, "r-x"),

  READ_WRITE(6, "rw-"),

  ALL(7, "rwx");

 

  //constants

  /** Octal representation */

  public final int INDEX;

  /** Symbolic representation */

  public final String SYMBOL;

 

 //构造函数,构造枚举类型

 private FsAction(int v, String s)

{

    INDEX = v;

    SYMBOL = s;

}

 

几个枚举类型对应的实例主要为:

none,执行,,写并和执行,读,读并可执行,读并可写,ALL

 

同时该对象提供的主要方法:

/** AND operation. */

  public FsAction and(FsAction that) {

    return values()[this.INDEX & that.INDEX];

  }

  /** OR operation. */

  public FsAction or(FsAction that) {

    return values()[this.INDEX | that.INDEX];

  }

  /** NOT operation. */

  public FsAction not() {

    return values()[7 - INDEX];

  }

//这个方法最为重要,主要是检测用户的某个行为是否具有权限。

public boolean implies(FsAction that)

{

if (that != null)

{

          return (this.INDEX & that.INDEX) == that.INDEX;

       }

       return false;

    }

 

FsPermission

public class FsPermission implements Writable

 

该对象主要描述各类用户(文件属主,群用户以及其他用户)对文件的访问权限。

该对象主要的三个属性为:

private FsAction useraction = null;

private FsAction groupaction = null;

private FsAction otheraction = null;

从属性命名中我们也可以了解到,这表示一个文件的各类用户对该文件的不同访问权限。

 

值得一提的方法:

public void fromShort(short n)

{

    //枚举中的values方法为静态方法,返回该枚举类型所有值列表

FsAction[] v = FsAction.values();

 

    set(v[(n >>> 6) & 7], v[(n >>> 3) & 7], v[n & 7]);

}

该方法可以从一个short,生成文件的访问权限。

0666,表示所有用户可以读写。

 

 

PermissionStatus

public class PermissionStatus implements Writable

 

该对象包含文件与权限相关的所有信息,主要的属性如下:

private String username;

private String groupname;

private FsPermission permission;

可以看到,该对象描述了文件的属主,文件所属的群,文件各类用户的访问权限。

 

以上提到的权限相关对象,如何在系统中发挥作用呢?

上文已经提到过INode表示文件目录树形结构中一个抽象的节点,它包含一个重要的属性:

 

// Only updated by updatePermissionStatus(...).

// Other codes should not modify it.

private long permission;

 

所有节点INodeFileINodeDirectory 都继承与INode,所有类型节点都包含这个属性,如何通过这个属性构建出节点的PermissionStatus呢?

 

INode中值得一提的对象:

private static enum PermissionStatusFormat

{

MODE(0, 16), GROUP(MODE.OFFSET + MODE.LENGTH, 25),

USER(GROUP.OFFSET + GROUP.LENGTH, 23);

 

        final int OFFSET;

        final int LENGTH; // bit length

        final long MASK;

 

        PermissionStatusFormat(int offset, int length)

        {

            OFFSET = offset;

            LENGTH = length;

            MASK = ((-1L) >>> (64 - LENGTH)) << OFFSET;

    }

}

上文提到,private long permission表示文件的访问权限信息, 如何通过它的到PermissionStatus, 我们知道PermissionStatus中包含userName,groupName以及一个FsPermission对象,如何通过一个(long permission)长整型对象恢复出上述三个对象呢?我们知道FsPermission可以通过fromShort(short n)这个函数进行恢复。

 

PermissionStatusFormat其实主要存在三个枚举值:

MODEGROUPUSER

1.MODE存储FsPermissionlong(长整型) 中的开始字节数以及字节总数。

2.GROUP存储groupNamelong(长整型) 中的开始字节数以及字节总数。

3.GROUP存储userNamelong(长整型) 中的开始字节数以及字节总数。

 

long retrieve(long record)

{

        return (record & MASK) >>> OFFSET;

}

该函数从一个长整形中,截取OFFSET偏移量处,LENGTH长度的bits

OK,FsPermission可以截取前16个字节进行恢复,那userNamegroupName?

 

我们看一下代码:

public String getGroupName()

{

        int n = (int) PermissionStatusFormat.GROUP.retrieve(permission);

        return SerialNumberManager.INSTANCE.getGroup(n);

}

其实原理和FsPermission有些相似,只不过是通过截取long中部分字节做为index获得最终userName

 

PermissionChecker

 

class PermissionChecker

这个类从命名上就很容易看出一些端倪,这个类主要的作用就是进行用户行为的权限验证

 

该对象主要的方法:

 

private void check(INode inode, FsAction access)

            throws AccessControlException

{

    if (inode == null)

    {

        return;

    }

    FsPermission mode = inode.getFsPermission();

//如果访问该节点的用户是节点属主

    if (user.equals(inode.getUserName()))

    { // user class

        if (mode.getUserAction().implies(access))

        {

            return;

        }

    }

//如果访问该节点的用户包含在文件所属群中

    else if (groups.contains(inode.getGroupName()))

    { // group class

        if (mode.getGroupAction().implies(access))

        {

            return;

        }

    }

//其他用户

    else

    { // other class

        if (mode.getOtherAction().implies(access))

        {

            return;

        }

    }

    throw new AccessControlException("Permission denied: user=" + user + ", access=" + access + ", inode=" + inode);

}

 

下面我们一起通过构建文件时权限处理流程来熟悉这部分。

               

在这里我们通过以上文件创建流程的一个实例,了解文件权限该模块儿的主要实现,其中可能包含一些前面未曾提到的类(后面会逐个详细讲解),本模块主要是讲解权限模块儿的实现,主要首先关注创建流程与权限验证部分的实现,其中绿色字体部分为权限相关部分。

1.FileSystem(非常重要的抽象类,文件系统访问的主要接口)首先利用FSPermission得到缺省的文件访问权限

permission = FsPermission.getDefault();

 

2.DFSClient.create(src,permission)

(DFSClient是用户与文件打交道的接口类,可以理解为前项层)

 

在权限对象上应用权限umask(该功能类似于unix中的 umask

FsPermission masked = permission

.applyUMask(FsPermission.getUMask(conf));

 

后续该参数会一直传递到具体文件创建部分。

 

3.DFSOutputStream实例(后续的文件写操作就是通过操作该Stream对象)

new DFSOutputStream(src, masked, overwrite,               replication, blockSize, progress, buffersize, conf.getInt(

                        "io.bytes.per.checksum", 512));

可以看到masked(前面提到的应用过umask后的权限访问对象)和src这两个关键参数进行往下传递。

 

4.利用RPC调用Namenode上的create方法。

namenode.create(src, masked, clientName, overwrite,

                        replication, blockSize);

 

5.session中取得当前用戶,利用当前用户构建文件权限相关信息,文件的属主属于当前用户,访问权限为开始时创建并应用了umask的权限访问对象。

new PermissionStatus(UserGroupInformation.getCurrentUGI().getUserName(), null, masked)

 

6.调用namesystem的文件创建方法

namesystem.startFile(src,new PermissionStatus(UserGroupInformation.getCurrentUGI().getUserName(), null, masked),clientName, clientMachine, overwrite, replication, blockSize);

 

其中重要的参数src和上述已经提到的new出来的PermissionStatus

 

7.调用调用namesystemstartFileInternal方法

startFileInternal(src, permissions, holder, clientMachine, overwrite,

                false, replication, blockSize);

其中重要的参数src和上述已经提到的new出来的PermissionStatus

8.好,文件访问权限的关键点来了。

//一定会有权限检验的

if (isPermissionEnabled)

    {

        if (append || (overwrite && dir.exists(src)))

        {

            checkPathAccess(src, FsAction.WRITE);

        }

        else

        {

//主要是这里,判断用户对父节点是否有可写权限。

            checkAncestorAccess(src, FsAction.WRITE);

        }

}

9.new出一个PermissionChecker实例

10.

INode[] inodes = root.getExistingPathINodes(path);

int ancestorIndex = inodes.length - 2;

for (; ancestorIndex >= 0 && inodes[ancestorIndex] == null; ancestorIndex--);

checkTraverse(inodes, ancestorIndex);

 

该部分代码的主要作用,举例:

用户创建文件/user/boss/tmp/tmp2/tmp3/data,但是tmp2/tmp3这个子目录不存在。

 

那就要找到所谓的ancestorIndex,就是/user/boss/tmp这个文件夹。

就需要判断/user/boss/tmp这个文件加用户是否具有写权限

check(inodes, ancestorIndex, ancestorAccess);

最终调用

check(INode inode, FsAction access)

 

FsPermission mode = inode.getFsPermission();

 

if (user.equals(inode.getUserName()))

{   if (mode.getUserAction().implies(access))

    {return;} }

else if (groups.contains(inode.getGroupName()))

{ // group class

    if (mode.getGroupAction().implies(access))

    {return;} }

else

{ // other class

    if (mode.getOtherAction().implies(access))

    {return;}      }

 

11.用户对祖先目录具有写权限以后,就可以首先创建不存在的子目录,再创建末节点的文件。

所有创建的INode都会将第5步创建的PermissionStatus,转化并赋值给INodeprivate long permission

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值