前段时候做android下文件系统的支持,android本身vold里面只实现了fat的支持,对其它格式的支持没有实现,关于ntfs的支持,linux对于其只支持读,不可写,后面网上找到了ntfs-3g驱动,在ununtu上装上后,确实可以实现挂载,而且挂载的分区是可读写的,所以 后面就想着移植到android上来,不过由于android 下的libc是glibc的一个子集,在移植过程中发现要实现libc没有但uclib有的一些函数,所以稍微有蹼麻烦,不过最后还是移植成功了.
1、首先就是要编写android.mk:
#
#
# Copyright 2008 Wind RiverSystems
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
libfuse-lite/fuse.clibfuse-lite/fusermount.c libfuse-lite/fuse_kern_chan.clibfuse-lite/fuse_loop.c \
libfuse-lite/fuse_lowlevel.clibfuse-lite/fuse_opt.c libfuse-lite/fuse_session.c libfuse-lite/fuse_signals.c\
libfuse-lite/helper.clibfuse-lite/mount.c libfuse-lite/mount_util.c
LOCAL_C_INCLUDES :=$(LOCAL_PATH)/include/fuse-lite
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 :=libc libcutils
include $(BUILD_STATIC_LIBRARY)
###################################################################
## For stage2, we have tomake libntfs-3g
###################################################################
include $(CLEAR_VARS)
LOCAL_SRC_FILES :=libntfs-3g/acls.c libntfs-3g/attrib.clibntfs-3g/attrlist.c libntfs-3g/bitmap.c\
libntfs-3g/bootsect.clibntfs-3g/cache.c libntfs-3g/collate.c libntfs-3g/compat.clibntfs-3g/compress.c \
libntfs-3g/debug.clibntfs-3g/device.c libntfs-3g/dir.c libntfs-3g/efs.c libntfs-3g/index.clibntfs-3g/inode.c\
libntfs-3g/lcnalloc.clibntfs-3g/logfile.c libntfs-3g/logging.c libntfs-3g/mft.c libntfs-3g/misc.clibntfs-3g/mst.c\
libntfs-3g/object_id.clibntfs-3g/reparse.c libntfs-3g/runlist.c libntfs-3g/security.clibntfs-3g/unistr.c\
libntfs-3g/unix_io.clibntfs-3g/volume.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/fuse-lite $(LOCAL_PATH)/include/ntfs-3g
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 :=libc libcutils
include $(BUILD_STATIC_LIBRARY)
###################################################################
## For stage3, we make ntfs-3g
###################################################################
include $(CLEAR_VARS)
LOCAL_SRC_FILES := src/ntfs-3g.csrc/ntfs-3g_common.c
#src/secaudit.csrc/ntfs-3g_common.c src/ntfs-3g.probe.c src/lowntfs-3g.c
LOCAL_C_INCLUDES :=$(LOCAL_PATH)/include/fuse-lite $(LOCAL_PATH)/include/ntfs-3g \
$(LOCAL_PATH)/src
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)
2、修改源码:
添加:
#define MOUNTED"/etc/mtab"
#define _PATH_MOUNTED"/etc/mtab"
取消以下宏的定义:
//#defineHAVE_ENDIAN_H 1
//#defineHAVE_SETXATTR 1
//#defineHAVE_SETXATTR 1
//#defineHAVE_STRUCT_STAT_ST_ATIM 1
//#defineHAVE_UTIMENSAT 1
注意这里不要取消 HAVE_SYS_STATVFS_H 的定义,取消的话也可以编译通过,可以挂载文件,也支持写,但当用adb安装文件时会出现异常,因为在这个过程中调用了statfs,这里不注释的话编译会出问题,我们需要自己定义statvfs,然后包进去就可以,可以参照linux的定义:
#ifndef _SYS_STATVFS_H
#define _SYS_STATVFS_H
struct statvfs
{
unsigned long int f_bsize;
unsigned long int f_frsize;
unsigned long int f_blocks;
unsigned long int f_bfree;
unsigned long int f_bavail;
unsigned long int f_files;
unsigned long int f_ffree;
unsigned long int f_favail;
unsigned long int f_fsid;
unsigned long int f_flag;
unsigned long int f_namemax;
int __f_spare[6];
};
struct statvfs64
{
unsigned long int f_bsize;
unsigned long int f_frsize;
unsigned long int f_blocks;
unsigned long int f_bfree;
unsigned long int f_bavail;
unsigned long int f_files;
unsigned long int f_ffree;
unsigned long int f_favail;
unsigned long int f_fsid;
unsigned long int f_flag;
unsigned long int f_namemax;
int __f_spare[6];
};
#endif
接下来删除重复定义:
struct timespec {
time_t tv_sec;
long tv_nsec;
}
fusermount.c添加:
static int mount_fuse(const char*mnt, const char *opts);
int fusermount(int unmount, intquiet, int lazy, const char *opts,
const char *origmnt)
{
int res = -1;
char *mnt;
mode_t old_umask;
mnt = fuse_mnt_resolve_path(progname, origmnt);
if (mnt == NULL)
return-1;
old_umask = umask(033);
if (unmount) {
if(restore_privs())
goto out;
if (geteuid() == 0)
res = fuse_mnt_umount(progname,mnt, lazy);
else {
res = umount2(mnt, lazy ? 2 : 0);
if (res == -1 && !quiet)
fprintf(stderr, "444%s:failed to unmount %s: %s\n", progname,
mnt, strerror(errno));
}
if(drop_privs())
res = -1;
} else
res = mount_fuse(mnt, opts);
out:
umask(old_umask);
free(mnt);
return res;
}
struct mntent *getmntent_r (FILE*filep,struct mntent *mnt, char *buff, int bufsize)
{
staticconst char sep[] = " /t/n";
char*cp, *ptrptr;
if(!filep || !mnt || !buff)
returnNULL;
/*Loop on the file, skipping comment lines. - FvK 03/07/93 */
while((cp = fgets(buff, bufsize, filep)) != NULL)
{
if(buff[0] == '#' || buff[0] == '/n')
continue;
break;
}
/*At the EOF, the buffer should be unchanged. We should
*check the return value from fgets ().
*/
if(cp == NULL)
returnNULL;
ptrptr= 0;
mnt->mnt_fsname= strtok_r(buff, sep, &ptrptr);
if(mnt->mnt_fsname == NULL)
returnNULL;
mnt->mnt_dir= strtok_r(NULL, sep, &ptrptr);
if(mnt->mnt_dir == NULL)
returnNULL;
mnt->mnt_type= strtok_r(NULL, sep, &ptrptr);
if(mnt->mnt_type == NULL)
returnNULL;
mnt->mnt_opts= strtok_r(NULL, sep, &ptrptr);
if(mnt->mnt_opts == NULL)
mnt->mnt_opts= "";
cp= strtok_r(NULL, sep, &ptrptr);
mnt->mnt_freq= (cp != NULL) ? atoi(cp) : 0;
cp= strtok_r(NULL, sep, &ptrptr);
mnt->mnt_passno= (cp != NULL) ? atoi(cp) : 0;
returnmnt;
}
struct mntent *getmntent(FILE *filep)
{
structmntent *tmp;
staticchar *buff = NULL;
staticstruct mntent mnt;
if(!buff)
{
buff= malloc(BUFSIZ);
if(!buff)
abort();
}
tmp= getmntent_r(filep, &mnt, buff, BUFSIZ);
return(tmp);
}
int addmntent(FILE * filep, conststruct mntent *mnt)
{
if(fseek(filep, 0, SEEK_END) < 0)
return1;
return(fprintf (filep, "%s %s %s %s %d %d/n", mnt->mnt_fsname,mnt->mnt_dir,
mnt->mnt_type, mnt->mnt_opts,mnt->mnt_freq, mnt->mnt_passno) < 0 ? 1 : 0);
}
char *hasmntopt(const structmntent *mnt, const char *opt)
{
returnstrstr(mnt->mnt_opts, opt);
}
FILE *setmntent(const char *name,const char *mode)
{
returnfopen(name, mode);
}
int endmntent(FILE * filep)
{
if(filep != NULL)
fclose(filep);
return1;
}
static int try_open(const char *dev, char **devp)中修改如下 :(我做的时候出现打不开设备,好像是权限不够):
// if (restore_privs())
// return -1;
fd = open(dev, O_RDWR);
// if (drop_privs())
// return -1;
libntfs-3g 目录
acls.c 删除 #include"secaudit.h"
security.c 的 ntfs_get_perm() 用#if0 #endif屏蔽ntfs_allowed_access()直接return1
ntfs-3g_common.c中去掉#ifdef HAVE_SETXATTR 和#endif
ntfs-3g.c中添加#define linux 1
经过这些修改后,应该可以编过了,编过之后 ,先mount一个4G以下的u盘试试,如果不行的话看下是否需要配置内核fuse支持
<*> FUSE (Filesystem in Userspace) support
看下这个选项是否选 上了
以上都正常的话,4G以下应该是可以mount 上去的
接下来就是4G以上的u盘了,挂载4G以上的u盘,可能会出现
Failed to read last sector (7454096): Invalid argument
HINTS: Either the volume is a RAID/LDM but it wasn'tsetup yet,
or it was not setup correctly (e.g. by notusing mdadm --build ...),
or a wrong device is tried to be mounted,
or the partition table is corrupt (partitionis smaller than NTFS),
or the NTFS boot sector is corrupt (NTFSsize is not valid).
ignore this error.
这个错误,这个是因为调用的lseek有问题,这里调用的是android重新封装的一个seek,但这个是针对32位系统的,off的参数类型是off_t 是32位的,应该使用lseek64,同样 数据的读写也存在同样的问题,所以进行了以下修改:
android源码目录bionic/libc/unistd下面修改:
pread.c添加
off_t pread64(int fd, void *buf,size_t nbytes, loff_t offset)
{
return __pread64(fd, buf, nbytes, offset);
}
pwrite.c添加
loff_t pwrite64(int fd, void*buf, size_t nbytes, loff_t offset)
{
return __pwrite64(fd, buf, nbytes, offset);
}
unistd.h添加
extern loff_t pwrite64(int , void*, size_t , loff_t );
extern loff_t pread64(int , void*, size_t , loff_t )
ntfs-3g源码修改:
static s64 ntfs_device_unix_io_seek(struct ntfs_device *dev, s64 offset,
中lseek改为lseek64
同理修改pread64 pwrite64
修改之后 重新编译ntfs-3g 和libc,测试了下,可以正常的挂载大于4G的ntfs 格式的u盘了,再挂载不了的话,也只能应该是RP有问题了。。。具体代码可以到下面链接下载:
http://download.csdn.net/detail/new_abc/4226894