原址:http://blog.csdn.net/new_abc/article/details/7459299
同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));
-
-
-
-
- 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