CyanogenMod 10 修改 Vold 使 Android(安卓)自动挂载 NTFS 和 exFAT 格式的 SD 卡
2013-04-25 18:37 2572人阅读 评论(4) 收藏 举报 Android NTFS exFAT 自动挂载 源代码
目录(?)[+]
Android 不支持 NTFS 和 exFAT 格式的文件系统,但是 Linux 已经有相应的开源代码了,因此只需将其移植到 Android 上即可。
这里需要下载两份代码,分别是 ntfs-3g 和 exfat。下载地址ntfs-3gexfat。
由于 Android 并没有使用完整的 glibc 库,因此需要对源代码进行修改以使代码能被顺利地编译。
代码与编译好的文件都可以在 CSDN 资源里下载:
CyanogenMod10 ntfs 与 exfat 自动挂载支持
一、修改 ntfs-3g 代码
关于 ntfs-3g 代码的修改,可以参考 CSDN 上的这篇文章:ntfs-3g移植到android4.0.3方法总结。这里就不在重复叙述了。
二、修改 exfat 代码
exfat 也是使用了 fuse,但代码量很小。需要修改的地方不多:
1、fuse/main.c 文件
大约位于 264 行的fuse_exfat_statfs 函数,将参数中的 statvfs 改为 statfs,并将其代码中的sfs->f_namemax 改为sfs->f_namelen
将
[cpp] view plain copy- sfs->f_favail=sfs->f_bfree>>ef.sb->spc_bits;
- sfs->f_ffree=sfs->f_bavail;
- sfs->f_ffree=sfs->f_bfree>>ef.sb->spc_bits;
2、libexfat/io.c
大约位于 255 行的exfat_seek 函数,将里面的 lseek 函数改为 lseek64;
大约位于 283 行的exfat_pread 函数,将里面的 pread 函数改为 pread64;
大约位于 295 行的exfat_pwrite 函数,将里面的 pwrite 函数改为 pwrite64。
3、将所有代码文件中的 off_t 类型全部换为 off64_t 类型
Android 的编译器编译出来的 off_t 类型是4字节的,只有改为 off64_t 才是8字节的。不改的话无法挂载超过 4G 的 SD 卡或 U 盘。
三、提取文件,编写 Android.mk 文件
这里我将所有的项目都放在了和 vold 同级的 system 目录下
1、libfuse
由于 ntfs-3g 和 exfat 都使用了 fuse,因此他们可以共享这个库。
在 system 目录新建 libfuse 文件夹,并建立子文件夹 src 和 include。将 ntfs-3g 中 libfuse-lite 中的所有文件复制到 libfuse/src 目录中,将 ntfs-3g 中 include/fuse-lite 中的所有文件复制到 libfuse/include 目录中,将 ntfs-3g 中的 config.h 复制到 libfuse 目录。
修改 libfuse/src/helper.c,在最后添加如下代码(exfat 需要):
[cpp] view plain copy- intfuse_daemonize(intforeground)
- {
- intres;
- if(!foreground){
- res=daemon(0,0);
- if(res==-1){
- perror("fuse:failedtodaemonizeprogram\n");
- return-1;
- }
- }
- return0;
- }
在 libfuse 目录编写 Android.mk: [plain] view plain copy
- LOCAL_PATH:=$(callmy-dir)
- include$(CLEAR_VARS)
- LOCAL_SRC_FILES:=\
- src/fuse.c\
- src/fusermount.c\
- src/fuse_kern_chan.c\
- src/fuse_loop.c\
- src/fuse_lowlevel.c\
- src/fuse_opt.c\
- src/fuse_session.c\
- src/fuse_signals.c\
- src/helper.c\
- src/mount.c\
- src/mount_util.c
- LOCAL_C_INCLUDES:=$(LOCAL_PATH)/include
- LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DHAVE_CONFIG_H
- LOCAL_MODULE:=libfuse
- LOCAL_MODULE_TAGS:=eng
- LOCAL_SYSTEM_SHARED_LIBRARIES:=libclibcutils
- include$(BUILD_STATIC_LIBRARY)
2、ntfs-3g
则里只提取挂载 NTFS 分区的文件。
在 system 目录新建 ntfs-3g 文件夹,并建立子文件夹 include、libntfs-3g 和 src。将 ntfs-3g 中 include/ntfs-3g 中的所有文件复制到 ntfs-3g/include 目录中,将 ntfs-3g 中 libntfs-3g 中的所有文件复制到 ntfs-3g/libntfs-3g 目录中,将 ntfs-3g 中 src 目录中的 ntfs-3g.c ntfs-3g_common.c ntfs-3g_common.h 复制到 ntfs-3g/src 目录中,将 ntfs-3g 中的 config.h 复制到 ntfs-3g 目录。
在 ntfs-3g 目录中编写 Android.mk:
[plain] view plain copy- LOCAL_PATH:=$(callmy-dir)
- include$(CLEAR_VARS)
- LOCAL_SRC_FILES:=\
- libntfs-3g/acls.clibntfs-3g/attrib.clibntfs-3g/attrlist.c\
- libntfs-3g/bitmap.clibntfs-3g/bootsect.clibntfs-3g/cache.c\
- libntfs-3g/collate.clibntfs-3g/compat.clibntfs-3g/compress.c\
- libntfs-3g/debug.clibntfs-3g/device.clibntfs-3g/dir.c\
- libntfs-3g/efs.clibntfs-3g/index.clibntfs-3g/inode.c\
- libntfs-3g/lcnalloc.clibntfs-3g/logfile.clibntfs-3g/logging.c\
- libntfs-3g/mft.clibntfs-3g/misc.clibntfs-3g/mst.c\
- libntfs-3g/object_id.clibntfs-3g/realpath.clibntfs-3g/reparse.c\
- libntfs-3g/runlist.clibntfs-3g/security.clibntfs-3g/unistr.c\
- libntfs-3g/unix_io.clibntfs-3g/volume.c
- LOCAL_C_INCLUDES:=$(LOCAL_PATH)/includesystem/libfuse/include
- LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DHAVE_CONFIG_H
- LOCAL_MODULE:=libntfs-3g
- LOCAL_MODULE_TAGS:=eng
- LOCAL_SYSTEM_SHARED_LIBRARIES:=libclibcutils
- include$(BUILD_STATIC_LIBRARY)
- include$(CLEAR_VARS)
- LOCAL_SRC_FILES:=\
- src/ntfs-3g.csrc/ntfs-3g_common.c
- LOCAL_C_INCLUDES:=$(LOCAL_PATH)/include$(LOCAL_PATH)/srcsystem/libfuse/include
- LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DHAVE_CONFIG_H
- LOCAL_MODULE:=ntfs-3g
- LOCAL_MODULE_TAGS:=eng
- LOCAL_SYSTEM_SHARED_LIBRARIES:=libc
- LOCAL_STATIC_LIBRARIES:=libfuselibntfs-3g
- include$(BUILD_EXECUTABLE)
3、ntfsfix
这个是用来在挂载 NTFS 分区前检查错误的。
在 system 目录下建立 ntfsfix 目录,并建立子目录 src。将 ntfs-3g 中 ntfsprogs 中的 ntfsfix.c sd.c sd.h utils.c utils.h 复制到 ntfsfix/src 目录,将 ntfs-3g 中的 config.h 复制到 ntfsfix 目录。
在 ntfsfix 目录下建立 Android.mk:
[plain] view plain copy- LOCAL_PATH:=$(callmy-dir)
- include$(CLEAR_VARS)
- LOCAL_SRC_FILES:=\
- src/ntfsfix.c\
- src/utils.c\
- src/sd.c
- LOCAL_C_INCLUDES:=$(LOCAL_PATH)/srcsystem/ntfs-3g/include
- LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DHAVE_CONFIG_H
- LOCAL_MODULE:=ntfsfix
- LOCAL_MODULE_TAGS:=eng
- LOCAL_SYSTEM_SHARED_LIBRARIES:=libc
- LOCAL_STATIC_LIBRARIES:=libntfs-3glibfuse
- include$(BUILD_EXECUTABLE)
4、mkntfs
这个是用来格式化分区为 NTFS 格式的。
在 system 目录下建立 mkntfs 目录,并建立子目录 src。将 ntfs-3g 中 ntfsprogs 中的 attrdef.c attrdef.h boot.c boot.h mkntfs.c sd.c sd.h utils.c utils.h 复制到 mkntfs/src 目录,将 ntfs-3g 中的 config.h 复制到 mkntfs 目录。
在 mkntfs 目录下建立 Android.mk:
[plain] view plain copy- LOCAL_PATH:=$(callmy-dir)
- include$(CLEAR_VARS)
- LOCAL_SRC_FILES:=\
- src/attrdef.c\
- src/boot.c\
- src/utils.c\
- src/mkntfs.c\
- src/sd.c
- LOCAL_C_INCLUDES:=$(LOCAL_PATH)/srcsystem/ntfs-3g/include
- LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DHAVE_CONFIG_H
- LOCAL_MODULE:=mkntfs
- LOCAL_MODULE_TAGS:=eng
- LOCAL_SYSTEM_SHARED_LIBRARIES:=libc
- LOCAL_STATIC_LIBRARIES:=libntfs-3glibfuse
- include$(BUILD_EXECUTABLE)
5、exfat
这里只提取挂载 exFAT 分区所需的文件。
在 system 目录下建立 exfat 目录。将 exfat 源代码中的 fuse 和 libexfat 文件夹复制到 exfat 目录中。
建立 Android.mk:
[plain] view plain copy- LOCAL_PATH:=$(callmy-dir)
- include$(CLEAR_VARS)
- LOCAL_SRC_FILES:=\
- libexfat/cluster.clibexfat/io.clibexfat/log.c\
- libexfat/lookup.clibexfat/mount.clibexfat/node.c\
- libexfat/time.clibexfat/utf.clibexfat/utils.c
- LOCAL_C_INCLUDES:=$(LOCAL_PATH)/libexfatsystem/libfuse/include
- LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-UUSE_UBLIO
- LOCAL_MODULE:=libexfat
- LOCAL_MODULE_TAGS:=eng
- LOCAL_SYSTEM_SHARED_LIBRARIES:=libclibcutils
- include$(BUILD_STATIC_LIBRARY)
- include$(CLEAR_VARS)
- LOCAL_SRC_FILES:=\
- fuse/main.c
- LOCAL_C_INCLUDES:=$(LOCAL_PATH)/libexfatsystem/libfuse/include
- LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DUSE_UBLIO
- LOCAL_MODULE:=exfat
- LOCAL_MODULE_TAGS:=eng
- LOCAL_SYSTEM_SHARED_LIBRARIES:=libc
- LOCAL_STATIC_LIBRARIES:=libfuselibexfat
- include$(BUILD_EXECUTABLE)
6、exfatfsck
这个是用来在挂载 exFAT 分区前检查错误的。
在 system 目录建立 exfatfsck 目录,并将 exfat 源代码中 fsck/main.c 复制到 exfatfsck 目录中。
建立 Android.mk(这里只列出关键的两行):
[plain] view plain copy- LOCAL_SRC_FILES:=\
- main.c
- LOCAL_C_INCLUDES:=$(LOCAL_PATH)/srcsystem/exfat/libexfat
7、mkexfatfs
这个是用来格式化分区为 exFAT 格式的。
在 system 目录下建立 mkexfatfs 目录,并建立子目录 src。将 exfat 源代码中 mkfs 目录下的所有文件复制到 mkexfatfs/src 目录中。
建立 Android.mk(关键部分):
[plain] view plain copy- LOCAL_SRC_FILES:=\
- src/cbm.c\
- src/fat.c\
- src/main.c\
- src/mkexfat.c\
- src/rootdir.c\
- src/uct.c\
- src/uctc.c\
- src/vbr.c
- LOCAL_C_INCLUDES:=$(LOCAL_PATH)/srcsystem/exfat/libexfat
四、修改 vold 代码
CyanogenMod 的 vold 代码包含了 Ntfs.cpp 和 Ntfs.h,但是需要修改
1、修改 Ntfs.cpp
添加全局变量:
[cpp] view plain copy- staticcharMOUNT_NTFS_PATH[]="/system/bin/ntfs-3g";
- staticcharMKNTFS_PATH[]="/system/bin/mkntfs";
- staticcharNTFSFIX_PATH[]="/system/bin/ntfsfix";
check 函数: [cpp] view plain copy
- intNtfs::check(constchar*fsPath){
- boolrw=true;
- if(access(NTFSFIX_PATH,X_OK)){
- SLOGW("Skippingfschecks\n");
- return0;
- }
- intrc=-1;
- do{
- constchar*args[3];
- args[0]=NTFSFIX_PATH;
- args[1]=fsPath;
- args[2]=NULL;
- rc=logwrap(3,args,1);
- switch(rc){
- case0:
- SLOGI("NTFSFilesystemcheckcompletedOK.\n");
- return0;
- case1:
- SLOGI("NTFSFilesystemcheckfailed.\n");
- return0;
- default:
- SLOGE("NTFSFilesystemcheckfailed(unknownexitcode%d).\n",rc);
- errno=EIO;
- return-1;
- }
- }while(0);
- return0;
- }
doMount 函数: [cpp] view plain copy
- intNtfs::doMount(constchar*fsPath,constchar*mountPoint,
- boolro,boolremount,boolexecutable,
- intownerUid,intownerGid,intpermMask,boolcreateLost){
- intrc;
- unsignedlongflags;
- charmountData[255];
- charoptions[255]={};
- constchar*args[6];
- flags=MS_NODEV|MS_NOSUID|MS_DIRSYNC;
- flags|=(executable?0:MS_NOEXEC);
- flags|=(ro?MS_RDONLY:0);
- flags|=(remount?MS_REMOUNT:0);
- //Testing/security,mountrouptonow
- flags|=MS_RDONLY;
- /*
- *Note:Thisisatemporaryhack.Ifthesamplingprofilerisenabled,
- *wemaketheSDcardworld-writablesoanyprocesscanwritesnapshots.
- *
- *TODO:Removethiscodeoncewehaveadropboxinsystem_server.
- */
- charvalue[PROPERTY_VALUE_MAX];
- property_get("persist.sampling_profiler",value,"");
- if(value[0]=='1'){
- SLOGW("TheSDcardisworld-writablebecausethe"
- "'persist.sampling_profiler'systempropertyissetto'1'.");
- permMask=0;
- }
- sprintf(mountData,
- "uid=%d,gid=%d,fmask=%o,dmask=%o",
- ownerUid,ownerGid,permMask,permMask);
- if(!remount){
- SLOGI("Tryingtousentfs-3gprogramtomount%s",fsPath);
- if(ro)
- snprintf(options,sizeof(options),"ro,%s",mountData);
- else
- snprintf(options,sizeof(options),"%s",mountData);
- args[0]=MOUNT_NTFS_PATH;
- args[1]="-o";
- args[2]=options;
- args[3]=fsPath;
- args[4]=mountPoint;
- args[5]=NULL;
- rc=logwrap(6,args,1);
- if(rc==0){
- SLOGI("ntfs-3gexecutedsuccessfully.");
- }else{
- SLOGE("Failedtoexecutentfs-3g.");
- }
- }else{
- rc=mount(fsPath,mountPoint,"fuseblk",flags,mountData);
- }
- if(rc&&errno==EROFS){
- SLOGE("%sappearstobeareadonlyfilesystem-retryingmountRO",fsPath);
- flags|=MS_RDONLY;
- if(!remount){
- SLOGI("Tryingtousentfs-3gprogramtomount%sasread-only",fsPath);
- snprintf(options,sizeof(options),"ro,%s",mountData);
- args[0]=MOUNT_NTFS_PATH;
- args[1]="-o";
- args[2]=options;
- args[3]=fsPath;
- args[4]=mountPoint;
- args[5]=NULL;
- rc=logwrap(6,args,1);
- if(rc==0){
- SLOGI("ntfs-3gexecutedsuccessfullyforread-only.");
- }else{
- SLOGE("Failedtoexecutentfs-3gforread-only.");
- }
- }else{
- rc=mount(fsPath,mountPoint,"fuseblk",flags,mountData);
- }
- }
- returnrc;
- }
format 函数: [cpp] view plain copy
- intNtfs::format(constchar*fsPath,unsignedintnumSectors){
- constchar*args[5];
- charstrNumOfSectors[16]={};
- intrc;
- args[0]=MKNTFS_PATH;
- args[1]="-f";
- args[2]=fsPath;
- if(numSectors){
- snprintf(strNumOfSectors,sizeof(strNumOfSectors),"%u",numSectors);
- args[3]=strNumOfSectors;
- args[4]=NULL;
- rc=logwrap(5,args,1);
- }else{
- args[3]=NULL;
- rc=logwrap(4,args,1);
- }
- if(rc==0){
- SLOGI("FilesystemformattedOK");
- return0;
- }else{
- SLOGE("Formatfailed(unknownexitcode%d)",rc);
- errno=EIO;
- return-1;
- }
- return0;
- }
2、添加 ExFat.h 和 ExFat.cpp
这里请使用 Ntfs.h 和 Ntfs.cpp 作为模板。
关键代码:
[cpp] view plain copy- staticcharMOUNT_EXFAT_PATH[]="/system/bin/exfat";
- staticcharMKFS_EXFAT_PATH[]="/system/bin/mkexfatfs";
- staticcharFSCK_EXFAT_PATH[]="/system/bin/exfatfsck";
- intExFat::check(constchar*fsPath){
- boolrw=true;
- if(access(FSCK_EXFAT_PATH,X_OK)){
- SLOGW("Skippingfschecks\n");
- return0;
- }
- intrc=-1;
- do{
- constchar*args[3];
- args[0]=FSCK_EXFAT_PATH;
- args[1]=fsPath;
- args[2]=NULL;
- rc=logwrap(3,args,1);
- switch(rc){
- case0:
- SLOGI("exFATFilesystemcheckcompletedOK.\n");
- return0;
- case1:
- SLOGI("exFATFilesystemcheckfailed.\n");
- return0;
- default:
- SLOGE("exFATFilesystemcheckfailed(unknownexitcode%d).\n",rc);
- errno=EIO;
- return-1;
- }
- }while(0);
- return0;
- }
- intExFat::doMount(constchar*fsPath,constchar*mountPoint,
- boolro,boolremount,boolexecutable,
- intownerUid,intownerGid,intpermMask,boolcreateLost){
- intrc;
- unsignedlongflags;
- charmountData[255];
- constchar*args[4];
- flags=MS_NODEV|MS_NOSUID|MS_DIRSYNC;
- flags|=(executable?0:MS_NOEXEC);
- flags|=(ro?MS_RDONLY:0);
- flags|=(remount?MS_REMOUNT:0);
- //Testing/security,mountrouptonow
- flags|=MS_RDONLY;
- sprintf(mountData,
- "uid=%d,gid=%d,fmask=%o,dmask=%o",
- ownerUid,ownerGid,permMask,permMask);
- if(!remount){
- SLOGI("Tryingtouseexfatprogramtomount%s",fsPath);
- args[0]=MOUNT_EXFAT_PATH;
- args[1]=fsPath;
- args[2]=mountPoint;
- args[3]=NULL;
- rc=logwrap(4,args,1);
- if(rc==0){
- SLOGI("exfatexecutedsuccessfully.");
- }else{
- SLOGE("Failedtoexecuteexfat.");
- }
- }else{
- rc=mount(fsPath,mountPoint,"fuseblk",flags,mountData);
- }
- returnrc;
- }
- intExFat::format(constchar*fsPath,unsignedintnumSectors){
- constchar*args[3];
- charstrNumOfSectors[16]={};
- intrc;
- args[0]=MKFS_EXFAT_PATH;
- args[1]=fsPath;
- args[2]=NULL;
- rc=logwrap(3,args,1);
- if(rc==0){
- SLOGI("FilesystemformattedOK");
- return0;
- }else{
- SLOGE("Formatfailed(unknownexitcode%d)",rc);
- errno=EIO;
- return-1;
- }
- return0;
- }
3、修改 Volume.cpp
添加#include "Ntfs.h"
找到Volume::mountVol() 函数
找到else if (strcmp(fstype, "ntfs") == 0) 部分,在后面添加以下代码:
[cpp] view plain copy- if(Ntfs::check(devicePath)){
- errno=EIO;
- /*Badness-abortthemount*/
- SLOGE("%sfailedFSchecks(%s)",devicePath,strerror(errno));
- setState(Volume::State_Idle);
- free(fstype);
- return-1;
- }
找到和if (fstype != NULL) 对应的 else 块,在后面添加以下代码: [cpp] view plain copy
- //CheckifthefilesystemisexFAT
- FILE*volf=fopen(devicePath,"rb");
- intbytesRead=0;
- if(volf){
- charfschar[5];
- //ReadthesignatureinthePBR
- fseek(volf,3,SEEK_SET);
- bytesRead=fread(fschar,1,5,volf);
- fclose(volf);
- if(bytesRead==5&&strcmp(fschar,"EXFAT")==0){
- if(ExFat::check(devicePath)){
- errno=EIO;
- /*Badness-abortthemount*/
- SLOGE("%sfailedFSchecks(%s)",devicePath,strerror(errno));
- setState(Volume::State_Idle);
- free(fstype);
- return-1;
- }
- if(ExFat::doMount(devicePath,"/mnt/secure/staging",false,false,false,
- AID_SYSTEM,gid,0702,true)){
- SLOGE("%sfailedtomountviaexFAT(%s)\n",devicePath,strerror(errno));
- continue;
- }else{
- gotomountSuccess;
- }
- }
- }
然后转到 if (fstype != NULL) 的 else 的末尾,在语句块之后,SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint()); 之前添加mountSuccess: 跳转标签。
4、修改 vold 的 Android.mk
天际common_src_files += ExFat.c
五、修改 build/target/product/base.mk
添加
[plain] view plain copy- PRODUCT_PACKAGES+=\
- libfuse\
- ntfs-3g\
- exfat\
- mkntfs\
- ntfsfix\
- mkexfatfs\
- exfatfsck
六、编译
如果不出意外的话,编译之后就可以直接使用了。
更多相关文章
- android EditText设置不可写
- android 使用html5作布局文件: webview跟javascript交互
- android studio调试c/c++代码
- IM-A820L限制GSM,WCDMA上网的原理(其他泛泰机型可参考)7.13
- 锁屏界面
- android(NDK+JNI)---Eclipse+CDT+gdb调试android ndk程序
- Android(安卓)version and Linux Kernel version
- Android(安卓)闹钟管理类的使用
- Android学习篇之Menu的使用