您的位置:首页 > 产品设计 > UI/UE

android usb挂载分析--ext*支持uid、gid等选项

2012-04-13 22:44 387 查看
同ntfs一样,android默认的是不支持ext*格式的,可以自己把这些格式的支持加上去,但有一个问题,ext*不像fat那样挂载的时候支持uid、gid、fdmask等 参数,这会导致文件系统挂载上去后,发现还有一个问题,ext2,ext3,ext4的挂载上去后在应用中文件看不到,查了下原因是因为应用不能写u盘,说的具体点是应用的这个用户没有权限写u盘,我们看下fat挂载上去后的目录权限:

ls -l
drwxr-xr-x root     system            1970-01-01 08:00 obb
drwxr-xr-x root     system            1970-01-01 08:00 asec
drwx------ root     root              1970-01-01 08:00 secure
d---rwxr-x system   sdcard_rw          2012-03-29 17:11 sdcard


可以看到用户为systme,组为sdcard_rw但system的权限为0,组sdcard_rw的权限为7,可以读写,所以应用可以操作存储设备,这是因为在挂载fat格式的设备时mount的选项有uid=1000,gid=1015,fmask=702,dmask=702,1000在定义的是system,1015定义的是组sdcard_rw,fmask=702,dmask=702表示的是实际的权限与这个mask的~,所以:就有了上面的目录权限,只要是sdcard_rw组的用户都可以读写存储设备,但我在做其它格式的u盘挂载的时候,由于mount选项不支持,所以没有了这些选项的支持,导致挂载上去的目录是这样的:

ls -l
drwxr-xr-x root     system            1970-01-01 08:00 obb
drwxr-xr-x root     system            1970-01-01 08:00 asec
drwx------ root     root              1970-01-01 08:00 secure
d rwxr-x --- root     root      	  2012-03-29 17:11 sdcard

只有root用户才能写,所以应用进行写操作的时候会失败。开始用了一个很猥琐的方法,去解决这个问题,在mount上去后用chmod把sdcard这个目录的权限改为777 ,这样所有的用户对这个目录都有读写权限了,不过这好像感觉不太好,违背了android的权限管理,所以想办法搞成和fat挂载上去的权限一样,用了chown改变用户以及chgrp改变组,后面试了在mount的前面setgid改变组,不能使用setuid(1000),这样后没有权限mount了,这办法都试了,不过看了下效果还是不行,而且感觉做的很**,没办法,网上找了下,发现一个可以给内核打个补丁,使ext*打补丁能支持uid,gid选项,后面参照这个把mask的设置也加上去了,

ls -l
drwxr-xr-x root     system            1970-01-01 08:00 obb
drwxr-xr-x root     system            1970-01-01 08:00 asec
drwx------ root     root              1970-01-01 08:00 secure
d---rwxr-x system   sdcard_rw          2012-03-29 17:11 sdcard# cd sdcard
cd sdcard
# ls -l
ls -l
d---rwxr-x system sdcard_rw 2012-03-29 17:04 lost+found
d---rwxr-x system sdcard_rw 2012-03-29 17:07 test
drwxr-xr-x root root 2012-03-29 17:11 LOST.DIR
细心的读者可能发现,虽说挂载上去的文件权限已经uid、gid对了,但是新建出来的文件还是不对,所以这里还要针对这个问题修改一下内核,如果不修改的话,会导致应用安装不上去。
先看一下mount的步骤:



这里不去介绍这个系统调用的过程了,主要看到最后调用 了ext2_fill_super取填充超级块结构,而这里super结构中的s_fs_info正是针对具体文件系统的一些信息,我们的修改也主要在此

首先在ext2_sb_info结构中增加如下成员:

uid_t s_uid; /* make all files appear to belong to this uid */
	uid_t s_diskuid; /* write this uid to disk (if s_uid != 0) */
	gid_t s_gid; /* make all files appear to belong to this gid */
	gid_t s_diskgid; /* write this gid to disk (if s_gid != 0) */
	unsigned short fs_fmask;
	unsigned short fs_dmask;
这里的s_diskuid和 s_diskgid这里暂时还有用到,不过也加进去了

在ext2.h 增加下面两个函数,用来进行uid,gid,mode的相应修改:

static inline mode_t ext2_make_mode(struct ext2_sb_info *ei, umode_t i_mode)
{
	umode_t		mode;
	if(S_ISDIR(i_mode) ||i_mode == 0)
	{
		mode =   (00777 & ~ei->fs_dmask) | S_IFDIR;
	}
	else
	{
		mode =   (00777 &~ei->fs_fmask) | S_IFREG;
	}
	return mode;
}
static inline void ext2_fill_inode(struct super_block *sb, struct inode *inode)
{
	if (EXT2_SB(sb)->fs_fmask  || EXT2_SB(sb)->fs_dmask) {
		inode->i_mode = ext2_make_mode(EXT2_SB(sb), inode->i_mode);
	}
	if (EXT2_SB(sb)->s_uid) {
		inode->i_uid = EXT2_SB(sb)->s_uid;
	}
	if (EXT2_SB(sb)->s_gid) {
		inode->i_gid = EXT2_SB(sb)->s_gid;
	}
	return;
}


在fs/ext2/super.c中增加上面 ext2_sb_info结构中增加成员对应的解析选项:

enum {
   ...
   Opt_uid, Opt_diskuid, Opt_gid, Opt_diskgid,Opt_fmask, Opt_dmask,
};


在tokens中增加相应的字符串映射:

static const match_table_t tokens = {
    ....
        {Opt_uid, "uid=%u"},
	{Opt_diskuid, "uid=%u:%u"},
	{Opt_gid, "gid=%u"},
	{Opt_diskgid, "gid=%u:%u"},
	{Opt_dmask, "dmask=%o"},
	{Opt_fmask, "fmask=%o"},
	{Opt_err, NULL}
};
在解析mount选项的时候保存相应的值:

static int parse_options(char *options, struct super_block *sb)
{
      ...
      case Opt_uid:
			if (match_int(&args[0], &option))
				return 0;
			sbi->s_uid = sbi->s_diskuid = option;
			break;
		case Opt_diskuid:
			if (match_int(&args[0], &option))
				return 0;
			sbi->s_uid = option;
			if (match_int(&args[1], &option))
				return 0;
			sbi->s_diskuid = option;
			break;
		case Opt_gid:
			if (match_int(&args[0], &option))
				return 0;
			sbi->s_gid = sbi->s_diskgid = option;
			break;
		case Opt_diskgid:
			if (match_int(&args[0], &option))
				return 0;
			sbi->s_gid = option;
			if (match_int(&args[1], &option))
				return 0;
			sbi->s_diskgid = option;
			break;
		case Opt_dmask:
			if (match_octal(&args[0], &option))
				return 0;
			sbi->fs_dmask = option;
			break;
		case Opt_fmask:
			if (match_octal(&args[0], &option))
				return 0;
			sbi->fs_fmask = option;
			break;
      ...
}
这样,相应的从外面 传进来的选项就已经可以解析并保存起来了,然后,就是要在读写inode的时候把它们相应的值转变过去:

fs/ext2/inode.c

在ext2_iget函数 中,添加ext2_fill_inode的调用如:

struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
{
   ...
        inode->i_mode = le16_to_cpu(raw_inode->i_mode);
	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
	ext2_fill_inode(sb, inode);
   ...
}
还有static int __ext2_write_inode(struct inode *inode, int do_sync)函数中:

static int parse_options(char *options, struct super_block *sb)
{
   ...
   ext2_get_inode_flags(ei);
   ext2_fill_inode(sb, inode);
   ...
   if (!(test_opt(sb, NO_UID32))) {
		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
/*
 * Fix up interopera.bility with old kernels. Otherwise, old inodes get
 * re-used with the upper 16 bits of the uid/gid intact
 */
		if (!ei->i_dtime) {
			raw_inode->i_uid_high = cpu_to_le16(high_16_bits(inode->i_uid));
			raw_inode->i_gid_high = cpu_to_le16(high_16_bits(inode->i_gid));
		} else {
			raw_inode->i_uid_high = 0;
			raw_inode->i_gid_high = 0;
		}
	} else {
		raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(inode->i_uid));
		raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(inode->i_gid));
		raw_inode->i_uid_high = 0;
		raw_inode->i_gid_high = 0;
	}
这里都要做相应的更改,这样修改以后,挂载上去的文件的权限都及uid,gid都没有问题了,但是这个时候 我们发现新建文件还是会有问题,就是上面 列出来的,权限还是不对,这里还需要在创建文件或文件夹时做一些修改。

fs/ext2/namei.c

static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd)
{
   ...
   inode = ext2_new_inode(dir, mode);
   ext2_fill_inode(dir->i_sb, inode);
   ...
}
static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
   ...
   inode = ext2_new_inode (dir, S_IFDIR | mode);
   ext2_fill_inode(dir->i_sb, inode
   ...

这样,挂载的文件在android暂时就应该可以读写了,而且一般的操作应该是没问题,关于ext3、ext4的也跟这个类似,具体代码可以到下面这个链接去下载:

http://download.csdn.net/detail/new_abc/4226893
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: