移植exFAT到Android4.2.2

来源:互联网 发布:最新淘宝装修教程视频 编辑:程序博客网 时间:2024/04/29 11:04

                                                    xinu

exFATExtended File Allocation Table),又名FAT64,是一种较适合于闪存的文件系统,最先从微软的Windows Embedded CE 6.0引入这种文件系统,后又延伸到Windows Vista Service Pack 1操作系统中[3]。由于NTFS文件系统的一些数据格式规定所限,对快存存储器而言exFAT显得更具优势。

目录

  [隐藏] 
  • 1 优点
  • 2 缺点
  • 3 参见
  • 4 参考资料
  • 5 外部链接

优点[编辑]

exFAT相较于之前FAT文件系统的优势在于:

  • 可拓展至更大磁盘大小,理论上64ZiB,推荐最大512TiB,相较32位限制的FAT32分区的的2TB(每扇区512字节)。
  • 理论的文件大小限制为264 - 1字节(16 exbibytes - 1),而 FAT32 文件系统中单一文件限制大小为232 - 1字节(4 GiB)。
  • 对于单文件超过4 GB的跨系统用户来说,exFAT很好地提供了Windows(XP需要SP2和更新)、Mac OS X和Linux之间的兼容性。
  • 簇大小最大可为每扇区225字节,最大32 MB。
  • 由于采用了空余空间寻址,空间分配和删除的性能得以改进。
  • 在单一文件夹内支持超过216个文件。
  • 支持访问控制清单(但在Windows Vista SP1中尚未支持)[4]
  • 支持Transaction-Safe FAT文件系统 (TFAT)(在WinCE中可选的功能)。
  • 提供给OEM的可定义参数可以使这个文件系统适应不同特色的设备。
  • 时间戳记能够使用UTC[5]时间而不仅仅是所在时区(从Vista SP2开始)

缺点[编辑]

exFAT比过去的FAT文件系统的劣势在于:

  • 某些设备(如PDA、DC)将无法使用exFAT格式的存储卡。
  • 使用exFAT的设备将不能用Windows Vista的ReadyBoost功能。(Windows 7中的新的exFAT系统支持ReadyBoost)[6]
  • 授权方式不明确。夏普、RIM[7]分别和微软达成了exFAT授权协议。存在专利费。微软曾经为FAT的一部分申请专利[8]
  • Windows XP SP3之前的Windows暂时不支持exFAT,Windows XP可以安装修改更新KB955704来支持exFAT[9],Linux操作系统需要通过未完成的exfat工具支持exFAT[10],Mac OS X可通过升级至10.6.5来全面支持exFAT[11]
 



最近在Android上测试64GB的TF卡支持情况,发现在Windows平台上默认会把卡格式化为exFAT,而不是以前的FAT32或NTFS,故而引发了我对该文件系统的了解。

在Linux内核中不支持exFAT文件系统,需要像对ntfs(移植可查阅“参考网址”相关内容)支持一样使用fuse,即用户态文件系统,那什么是exFAT和fuse呢?

1.exFAT

exFAT(Extended FileAllocation Table),又名FAT64,是一种特别适合于闪存文件系统,可支持单个文件超过4GB的大小。

2.fuse

用户空间文件系统(Filesystem in Userspace,简称FUSE)是操作系统中的概念,指完全在用户态实现的文件系统。目前Linux通过内核模块对此进行支持。

上面两个名词的详细资料请查阅“参考网址”相关内容。

了解完了相关内容,那如何移植呢?下面是移植过程:

1.准备工作

a.exFAT源码

使用svn co http://exfat.googlecode.com/svn/trunk/exfat-read-only命令下载整份exfat源码到当前的exfat-read-only目录中,现在的(2013年07月24日的版本为1.0.0)。

b.fuse源码

从https://code.google.com/p/exfat/wiki/HOWTO了解到还需要fuse-devel或libfuse-dev,故而从http://sourceforge.net/projects/fuse/files/fuse-2.X/2.9.3/下载最新的fuse-2.9.3.tar.gz文件。

2.移植步骤

a.设置内核的配置:CONFIG_FUSE_FS=y;(会创建/dev/fuse结点)

b.在Android源码目录下的external目录下创建exfat-fuse目录,交将上面通过svn下载的exFAT代码复制到该目录下,并将fuse-2.9.3.tar.gz文件解压后将其文件也复制到该目录下,进入到exfat-fuse目录,执行./configure命令,会创建include/config.h等文件;

c.在exfat-fuse目录下创建Android.mk文件,内容如下:

  LOCAL_PATH:= $(call my-dir)

 

 

include $(CLEAR_VARS)

 

SRCPATH := lib

 

LOCAL_CFLAGS  :=-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26

LOCAL_MODULE_TAGS := optional

 

LOCAL_MODULE    :=libfuse_exfat

 

LOCAL_SRC_FILES := $(SRCPATH)/buffer.c

LOCAL_SRC_FILES += $(SRCPATH)/cuse_lowlevel.c

LOCAL_SRC_FILES += $(SRCPATH)/fuse.c

LOCAL_SRC_FILES += $(SRCPATH)/fuse_kern_chan.c

LOCAL_SRC_FILES += $(SRCPATH)/fuse_loop.c

LOCAL_SRC_FILES += $(SRCPATH)/fuse_loop_mt.c

LOCAL_SRC_FILES += $(SRCPATH)/fuse_lowlevel.c

LOCAL_SRC_FILES += $(SRCPATH)/fuse_mt.c

LOCAL_SRC_FILES += $(SRCPATH)/fuse_opt.c

LOCAL_SRC_FILES += $(SRCPATH)/fuse_session.c

LOCAL_SRC_FILES += $(SRCPATH)/fuse_signals.c

LOCAL_SRC_FILES += $(SRCPATH)/helper.c

LOCAL_SRC_FILES += $(SRCPATH)/mount.c

LOCAL_SRC_FILES += $(SRCPATH)/mount_util.c

LOCAL_SRC_FILES += $(SRCPATH)/ulockmgr.c

 

LOCAL_SHARED_LIBRARIES := libdl

LOCAL_PRELINK_MODULE := false

LOCAL_C_INCLUDES := $(LOCAL_PATH)/include

 

include $(BUILD_SHARED_LIBRARY)

 

 

include $(CLEAR_VARS)

 

SRCPATH := libexfat

 

LOCAL_CFLAGS  :=-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26 -D__GLIBC__=1

LOCAL_MODULE_TAGS := optional

 

LOCAL_MODULE    :=libexfat

LOCAL_SRC_FILES := $(SRCPATH)/cluster.c

LOCAL_SRC_FILES += $(SRCPATH)/io.c

LOCAL_SRC_FILES += $(SRCPATH)/log.c

LOCAL_SRC_FILES += $(SRCPATH)/lookup.c

LOCAL_SRC_FILES += $(SRCPATH)/mount.c

LOCAL_SRC_FILES += $(SRCPATH)/node.c

LOCAL_SRC_FILES += $(SRCPATH)/time.c

LOCAL_SRC_FILES += $(SRCPATH)/utf.c

LOCAL_SRC_FILES += $(SRCPATH)/utils.c

 

LOCAL_SHARED_LIBRARIES := libdl libfuse_exfat

LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)

 

include $(CLEAR_VARS)

 

LOCAL_CFLAGS    :=-D_FILE_OFFSET_BITS=64 -D__GLIBC__=1

LOCAL_C_INCLUDES := $(LOCAL_PATH)/libexfat

LOCAL_MODULE    :=dumpexfat

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := dump/main.c

LOCAL_SHARED_LIBRARIES := libexfat

include $(BUILD_EXECUTABLE)

 

include $(CLEAR_VARS)

 

LOCAL_CFLAGS    :=-D_FILE_OFFSET_BITS=64 -D__GLIBC__=1

LOCAL_C_INCLUDES := $(LOCAL_PATH)/libexfat

LOCAL_MODULE    :=fsck.exfat

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := fsck/main.c

LOCAL_SHARED_LIBRARIES := libexfat

include $(BUILD_EXECUTABLE)

 

include $(CLEAR_VARS)

 

LOCAL_CFLAGS    :=-D_FILE_OFFSET_BITS=64 -D__GLIBC__=1

LOCAL_C_INCLUDES := $(LOCAL_PATH)/libexfat

LOCAL_MODULE    :=exfat.label

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := label/main.c

LOCAL_SHARED_LIBRARIES := libexfat

include $(BUILD_EXECUTABLE)

 

include $(CLEAR_VARS)

 

LOCAL_CFLAGS    :=-D_FILE_OFFSET_BITS=64 -D__GLIBC__=1

LOCAL_C_INCLUDES := $(LOCAL_PATH)/libexfat

LOCAL_MODULE    :=mkfs.exfat

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := mkfs/main.c mkfs/cbm.c mkfs/fat.cmkfs/rootdir.c mkfs/uct.c mkfs/vbr.c mkfs/mkexfat.c mkfs/uctc.c

LOCAL_SHARED_LIBRARIES := libexfat

include $(BUILD_EXECUTABLE)

 

include $(CLEAR_VARS)

 

LOCAL_CFLAGS    :=-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26 -D__GLIBC__=1

LOCAL_C_INCLUDES := $(LOCAL_PATH)/include$(LOCAL_PATH)/libexfat

LOCAL_MODULE    :=mount.exfat

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := fuse/main.c

LOCAL_SHARED_LIBRARIES := libfuse_exfat libexfat

include $(BUILD_EXECUTABLE)

d.在相应产品的device.mk文件里添加如下语句:

  PRODUCT_PACKAGES += \

       fsck.exfat mount.exfat mkfs.exfat

 我们现在只需要上面3个工具即可,而添加的Android.mk里还有其他工具,如果也想编译进来,可直接加到该配置项后面。

e.跟库相关配置添加好了,接下来就是编译和处理编译异常了,刚开始编译,出现如下错误:

target thumb C: libfuse_exfat <=external/exfat-fuse/lib/buffer.c

In file included from external/exfat-fuse/lib/buffer.c:12:0:

external/exfat-fuse/lib/fuse_i.h:35:2: error: unknown typename 'pthread_mutex_t'

external/exfat-fuse/lib/fuse_i.h:82:2: error: unknown typename 'pthread_mutex_t'

external/exfat-fuse/lib/fuse_i.h:84:2: error: unknown typename 'pthread_key_t'

external/exfat-fuse/lib/fuse_i.h:130:23: error: unknown typename 'pthread_t'

external/exfat-fuse/lib/buffer.c: In function'fuse_buf_write':

external/exfat-fuse/lib/buffer.c:48:35: warning: pointer oftype 'void *' used in arithmetic [-Wpointer-arith]

external/exfat-fuse/lib/buffer.c:51:34: warning: pointer oftype 'void *' used in arithmetic [-Wpointer-arith]

external/exfat-fuse/lib/buffer.c: In function'fuse_buf_read':

external/exfat-fuse/lib/buffer.c:82:34: warning: pointer oftype 'void *' used in arithmetic [-Wpointer-arith]

external/exfat-fuse/lib/buffer.c:85:33: warning: pointer oftype 'void *' used in arithmetic [-Wpointer-arith]

external/exfat-fuse/lib/buffer.c: In function'fuse_buf_fd_to_fd':

external/exfat-fuse/lib/buffer.c:146:11: warning: comparisonbetween signed and unsigned integer expressions [-Wsign-compare]

external/exfat-fuse/lib/buffer.c: In function'fuse_buf_splice':

external/exfat-fuse/lib/buffer.c:171:19: error:'SPLICE_F_MOVE' undeclared (first use in this function)

external/exfat-fuse/lib/buffer.c:171:19: note: eachundeclared identifier is reported only once for each function it appears in

external/exfat-fuse/lib/buffer.c:173:19: error:'SPLICE_F_NONBLOCK' undeclared (first use in this function)

external/exfat-fuse/lib/buffer.c:185:3: warning: implicitdeclaration of function 'splice' [-Wimplicit-function-declaration]

external/exfat-fuse/lib/buffer.c: In function'fuse_buf_copy_one':

external/exfat-fuse/lib/buffer.c:232:27: warning: pointer oftype 'void *' used in arithmetic [-Wpointer-arith]

external/exfat-fuse/lib/buffer.c:233:27: warning: pointer oftype 'void *' used in arithmetic [-Wpointer-arith]

external/exfat-fuse/lib/buffer.c:236:15: warning: pointer oftype 'void *' used in arithmetic [-Wpointer-arith]

external/exfat-fuse/lib/buffer.c:236:41: warning: pointer oftype 'void *' used in arithmetic [-Wpointer-arith]

external/exfat-fuse/lib/buffer.c: In function'fuse_buf_copy':

external/exfat-fuse/lib/buffer.c:313:11: warning: comparisonbetween signed and unsigned integer expressions [-Wsign-compare]

看到是跟多线程与splice相关的,从相关资料了解到Android的bionic里面对pthread相关函数支持不佳,故而将相应功能先通过宏屏蔽掉:

a).将./include/config.h文件的#define HAVE_SPLICE 1注释掉;

b).修改./lib/fuse_mt.c文件,在fuse_loop_mt_proc函数中,将res = fuse_session_loop_mt(se);一句使用#ifdef __MULTI_THREAD和#endif括起来;

  在同一文件中的fuse_loop_mt函数中,将如下语句也使用上面的宏括起来:

  int res =fuse_start_cleanup_thread(f);

  if (res)

      return -1;

 

  res =fuse_session_loop_mt(fuse_get_session(f));

 fuse_stop_cleanup_thread(f);

  并在该函数的第一句前加上int res = -1;一句。

  修改./lib/cuse_lowlevel.c文件,在cuse_lowlevel_main函数中,将如下语句使用上面的宏括起来:

  if (multithreaded)

      res = fuse_session_loop_mt(se);

  else

  修改./lib/fuse.c文件,使用上面的宏将fuse_start_cleanup_thread和fuse_stop_cleanup_thread两函数(包括函数体)括起来;

  修改./lib/fuse_loop_mt.c文件,使用上面的宏将整个文件内容括起来;

  修改./lib/helper.c文件,在fuse_main_common函数中,将如下语句使用上面的宏括起来:

  if (multithreaded)

         res = fuse_loop_mt(fuse);

else

c).修改./include/fuse_common.h文件,添加#include <pthread.h>定义。

此时再次编译,有如下提示:

external/exfat-fuse/lib/fuse.c: In function'fuse_fs_read_buf':

external/exfat-fuse/lib/fuse.c:1804:40: warning: comparisonbetween signed and unsigned integer expressions [-Wsign-compare]

external/exfat-fuse/lib/fuse.c: In function 'mtime_eq':

external/exfat-fuse/lib/fuse.c:2427:25: warning: comparisonbetween signed and unsigned integer expressions [-Wsign-compare]

external/exfat-fuse/lib/fuse.c:2428:3: error: 'struct statconst' has no member named 'st_mtim'

external/exfat-fuse/lib/fuse.c: In function 'update_stat':

external/exfat-fuse/lib/fuse.c:2455:24: error: 'struct statconst' has no member named 'st_mtim'

external/exfat-fuse/lib/fuse.c: In function'fuse_lib_setattr':

external/exfat-fuse/lib/fuse.c:2810:17: error: 'struct stat'has no member named 'st_atim'

external/exfat-fuse/lib/fuse.c:2815:17: error: 'struct stat'has no member named 'st_mtim'

external/exfat-fuse/lib/fuse.c:2825:20: error: 'struct stat'has no member named 'st_atim'

external/exfat-fuse/lib/fuse.c:2827:20: error: 'struct stat'has no member named 'st_mtim'

没有相应的成员,做如下修改:

a).修改./include/config.h文件,将#define HAVE_STRUCT_STAT_ST_ATIM 1屏蔽掉;

b).修改./lib/fuse.c文件,在fuse_lib_setattr函数中的#ifdef HAVE_UTIMENSAT宏判断里做如下修改:

将tv[0] =attr->st_atim;修改为tv[0].tv_nsec =attr->st_atime;

将tv[1] =attr->st_mtim;修改为tv[1].tv_nsec =attr->st_mtime;

再次编译,出现如下错误:

external/exfat-fuse/lib/mount.c: In function'exec_fusermount':

external/exfat-fuse/lib/mount.c:142:8: error:'FUSERMOUNT_DIR' undeclared (first use in this function)

external/exfat-fuse/lib/mount.c:142:8: note: each undeclaredidentifier is reported only once for each function it appears in

external/exfat-fuse/lib/mount.c:142:23: error: expected ')'before string constant

external/exfat-fuse/lib/mount.c:142:23: error: too fewarguments to function 'execv'

修改./lib/mount.c文件,在合适的位置添加如下语句:

#ifndef FUSERMOUNT_DIR

#define FUSERMOUNT_DIR "/system/bin/bin"

#endif

再次编译,出现如下错误:

external/exfat-fuse/lib/mount_util.c: In function'mtab_needs_update':

external/exfat-fuse/lib/mount_util.c:37:19: error:'_PATH_MOUNTED' undeclared (first use in this function)

external/exfat-fuse/lib/mount_util.c:37:19: note: eachundeclared identifier is reported only once for each function it appears in

修改./lib/mount_util.c文件,在合适的位置添加如下语句:

#ifndef _PATH_MOUNTED

#define _PATH_MOUNTED "/etc/mtab"

#endif

再次编译,出现如下错误提示:

/home/guochongxin/rk/3188/new/SDK4.2.2/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/../lib/gcc/arm-linux-androideabi/4.6.x-google/../../../../arm-linux-androideabi/bin/ld:error: symbol __fuse_process_cmd has undefined version

/home/guochongxin/rk/3188/new/SDK4.2.2/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/../lib/gcc/arm-linux-androideabi/4.6.x-google/../../../../arm-linux-androideabi/bin/ld:error: symbol fuse_lowlevel_new has undefined version FUSE_2.5

/home/guochongxin/rk/3188/new/SDK4.2.2/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/../lib/gcc/arm-linux-androideabi/4.6.x-google/../../../../arm-linux-androideabi/bin/ld:error: symbol fuse_chan_new has undefined version FUSE_2.4

/home/guochongxin/rk/3188/new/SDK4.2.2/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/../lib/gcc/arm-linux-androideabi/4.6.x-google/../../../../arm-linux-androideabi/bin/ld:error: symbol fuse_teardown has undefined version FUSE_2.2

collect2: ld returned 1 exit status

修改lib/fuse_misc.h文件,将#define FUSE_SYMVER(x) __asm__(x)修改为#define FUSE_SYMVER(x)

再次编译,出现如下错误:

In file included fromexternal/exfat-fuse/libexfat/exfat.h:33:0,

                 fromexternal/exfat-fuse/libexfat/cluster.c:23:

external/exfat-fuse/libexfat/compiler.h:28:2: error: #errorC99-compliant compiler is required

修改./libexfat/compiler.h文件,将如下语句屏蔽掉:

#if __STDC_VERSION__ < 199901L

#error C99-compliant compiler is required

#endif

再次编译,此时编译通过了,那么继续接下来的修改吧。

f.相应的库和工具编译好了,剩下上层来调用了,修改vold相关文件来实现:

a).在Android源码的system/vold目录下添加exFat.h和exFat.cpp文件,相应的源码如下:

  exFat.h:

#ifndef _EXFAT_H

#define _EXFAT_H

 

#include <unistd.h>

 

class exFat {

public:

       static intdoMount(const char *fsPath, const char *mountPoint, bool ro, int ownerUid);

       static intunMount(const char *mountPoint);

       static intformat(const char *fsPath, unsigned int numSectors);

};

 

#endif

  exFat.cpp:

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <errno.h>

#include <string.h>

#include <dirent.h>

#include <errno.h>

#include <fcntl.h>

 

#include <sys/types.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/mman.h>

#include <sys/mount.h>

 

#include <linux/kdev_t.h>

 

#define LOG_TAG "Vold"

 

#include <cutils/log.h>

#include <cutils/properties.h>

 

#include "exFat.h"

 

static char EXFAT_PATH[] ="/system/bin/mount.exfat";

 

extern "C" int logwrap(int argc, const char **argv,int background);

extern "C" int mount(const char *, const char *,const char *, unsigned long, const void *);

 

int exFat::doMount(const char *fsPath, const char*mountPoint, bool ro, int ownerUid) {

       int rc = 0;

    do {

              if(!ro){

               const char *args[3];

               args[0] = EXFAT_PATH;

               args[1] = fsPath;

               args[2] = mountPoint;

               rc = logwrap(3, args, 1);

              SLOGI("%s %s %s", EXFAT_PATH, fsPath, mountPoint);

                     if(!rc){

                            SLOGI("MountEXFAT device form %s to %s OK",fsPath,mountPoint);

                             char *lost_path;

                             asprintf(&lost_path,"%s/LOST.DIR", mountPoint);

                             if (access(lost_path,F_OK)) {

                                 /*

                                * Create a LOST.DIR in theroot so we have somewhere to put

                                * lost cluster chains(fsck_msdos doesn't currently do this)

                                */

                                        if (mkdir(lost_path,0755)) {

                                            SLOGE("Unableto create LOST.DIR (%s)", strerror(errno));

                                        }

                             }

                             free(lost_path);

                          return 0;

                     }else{

                            SLOGE("MountEXFAT device form %s to %s failed",fsPath,mountPoint);

                            return -1;

                     }

              }else{

                     constchar *args[5];

               args[0] = EXFAT_PATH;

               args[1] = fsPath;

               args[2] = mountPoint;

               args[3] = "-o";

               args[4] = "ro,uid=1000";

 

               rc = logwrap(5, args, 1);

                     if(!rc){

                            SLOGI("MountEXFAT device form %s to %s OK.(Read-only)",fsPath,mountPoint);

                   return 0;

                     }else{

                            SLOGE("MountEXFAT device form %s to %s failed.(Read-only)",fsPath,mountPoint);

                            return-1;

                     }

              }

    } while (0);

    return rc;

}

 

int exFat::unMount(const char *mountPoint) {

       int rc = 0;

    do {

        const char*args[3];

        args[0] ="umount";

        args[1] =mountPoint;

        args[2] = NULL;

 

        rc = logwrap(2,args, 1);

              if(!rc){

                     SLOGI("unMountEXFAT device %s OK",mountPoint);

            return 0;

              }else{

                     SLOGE("unMountEXFAT device %s failed",mountPoint);

                     return-1;

              }

    } while (0);

    return rc;

}

 

int exFat::format(const char *fsPath, unsigned intnumSectors) {

    return 0;

}

b).修改system/vold/Android.mk文件,在common_src_files量中将exFat.cpp添加进去;

c).修改system/vold/Volume.cpp文件,进行如下修改:

  添加#include"exFat.h"一句;

  修改intVolume::mountVol()函数中的如下语句:

  if(Fat::doMount(devicePath, "/mnt/secure/staging", false, false, false,

               AID_SYSTEM, gid, 0702, true)) {

      SLOGE("%sfailed to mount via VFAT (%s)\n", devicePath, strerror(errno));

      continue;

  }

  为

  if(Fat::doMount(devicePath, "/mnt/secure/staging", false, false, false,

               AID_SYSTEM, gid, 0702, true)) {

      SLOGE("%sfailed to mount via VFAT (%s)\n", devicePath, strerror(errno));

      if(exFat::doMount(devicePath,"/mnt/secure/staging", false, 1000)){

          SLOGE("%s failed to mount via EXFAT(%s)\n", devicePath, strerror(errno));

          continue;

      } 

}

  至此,上层也修改好了,继续编译。

g.编译好后烧录运行,Android跑起来后,插入64GB的exFAT文件系统的TF卡,其中logcat信息中有如下错误提示:

I//system/bin/mount.exfat( 118): FUSE exfat 1.0.0

I//system/bin/mount.exfat( 118): ERROR: failed to get size of `/dev/block/vold/179:1'.

该问题从https://groups.google.com/forum/#!msg/exfat/Iei35MqkRGk/UeGSjnbzgQsJ可得知是一个已知问题,主要是fuse-exfat使用的LFS在Android native中没有提供相应的API函数,根据上面的提示,查找到该提示是在exfat-fuse目录中的./libexfat/io.c文件中的exfat_open处理,该函数会调用到exfat_seek,通过其来获得整个文件的大小,但该函数返回小于0的值,继续跟踪,该函数会调用到lseek函数,从http://fred-zone.blogspot.com/2011/02/io-offset.html了解到可通过两种方法处理,我们Android.mk里面包含了第一种方法,但无法处理,现在直接使用第二种方法来处理:

修改exfat-fuse目录里的./libexfat/io.c文件,添加如下内容:

#define  lseek   lseek64

#define  pread  pread64

#define  pwritepwrite64

#define  fcntl  __fcntl64

并将exfat-fuse目录里的所有.c和.h文件中的off_t替换为off64_t,重新编译烧录后,插上64GB的T卡后,有如下提示:

I//system/bin/mount.exfat( 116): FUSE exfat 1.0.0

I//system/bin/mount.exfat( 116): WARN: volume was not unmounted cleanly.

I/Vold    (  116):  /system/bin/mount.exfat/dev/block/vold/179:1 /mnt/external_sd

I/Vold    (  116): Mount EXFAT device form/dev/block/vold/179:1 to /mnt/external_sd OK

挂载成功了,测试可以读写卡,但拔掉卡后有如下提示:

I/DEBUG   (  119):         becae628  408f0940  [heap]

I/DEBUG   (  119):         becae62c  401b81b4 /system/lib/libc.so

I/DEBUG   (  119):         becae630  400e3602  /system/lib/libexfat.so

I/DEBUG   (  119):         becae634  0001c000 

I/DEBUG   (  119):         becae638  00000252 

I/DEBUG   (  119):         becae63c  401b81b4  /system/lib/libc.so

I/DEBUG   (  119):         becae640  400e3602  /system/lib/libexfat.so

I/DEBUG   (  119):         becae644  4018879c  /system/lib/libc.so (__pthread_clone)

I/DEBUG   (  119):    #01  becae648  883d068a 

I/DEBUG   (  119):          becae64c  400e0457 /system/lib/libexfat.so (exfat_bug+82)

I/DEBUG   (  119):    #02  becae650  becae66c [stack]

I/DEBUG   (  119):         becae654  becae66c  [stack]

I/DEBUG   (  119):         becae658  04d00000 

I/DEBUG   (  119):         becae65c  04d00000 

I/DEBUG   (  119):         becae660  00000000 

I/DEBUG   (  119):         becae664  400e0095  /system/lib/libexfat.so (exfat_pread+36)

I/DEBUG   (  119):         becae668  400e3602  /system/lib/libexfat.so

由此可以看到是libexfat的问题,从打印出来的栈信息,初步判断是exfat_bug涉及到影响,修改./libexfat/exfat.h文件,将如下语句:

void exfat_bug(const char* format, ...) PRINTF NORETURN;

void exfat_error(const char* format, ...) PRINTF;

void exfat_warn(const char* format, ...) PRINTF;

void exfat_debug(const char* format, ...) PRINTF;

替换为

#define exfat_debug(x...)

#define exfat_bug(x...)

#define exfat_warn(x...)

#define exfat_error(x...)   exfat_errors++

再次编译,有如下错误提示:

target thumb C: libexfat <=external/exfat-fuse/libexfat/log.c

external/exfat-fuse/libexfat/log.c:34:1: error: expectedidentifier or '(' before '{' token

external/exfat-fuse/libexfat/log.c:56:6: error: expected '=',',', ';', 'asm' or '__attribute__' before '++' token

external/exfat-fuse/libexfat/log.c:80:1: error: expectedidentifier or '(' before '{' token

external/exfat-fuse/libexfat/log.c:101:1: error: expectedidentifier or '(' before '{' token

修改./libexfat/log.c文件,将#include "exfat.h"屏蔽掉,再次编译,有如下错误提示:

external/exfat-fuse/libexfat/lookup.c: In function'exfat_split':

external/exfat-fuse/libexfat/lookup.c:225:1: error: controlreaches end of non-void function [-Werror=return-type]

cc1: some warnings being treated as errors

修改./libexfat/lookup.c文件,在exfat_split函数最后加上return 0;语句,再次编译,有如下错误提示:

external/exfat-fuse/mkfs/mkexfat.c: In function'get_position':

external/exfat-fuse/mkfs/mkexfat.c:162:1: error: controlreaches end of non-void function [-Werror=return-type]

cc1: some warnings being treated as errors

修改./mkfs/mkexfat.c文件,在get_position函数中最后加上return 0;语句,再次编译,未发现错误,烧录后,插拔TF卡未见明显异常信息。至此,移植告一段落了,待后期使用测试了。

 

 

声明:

上述步骤仅限于个人学习记录,如有错误或更好处理方法,请大家联系我们,互相学习,我们的联系方式如下:

http://blog.sina.com.cn/guochongxin

417651175@qq.com

谢谢!

                                                       阿XIN*的学习班(SLAM)

                                                           2013年07月25日

 




不同文件系统在不同的操作系统上读写一直是件很头大的事,特别是用NTFS/exFAT格式化后的大容量U盘,在Windows和Linux之间共享数据时最为头痛。在这之前也有类似提供Linux平台上exFAT文件系统的支持,但是基于FUSE的,性能或多或少有影响。有的还只能读取不能写入。

exfat-nofuse是从Android的Linux kernel3.0中移植而来,Android的Linux kernel 3.0上的exFAT驱动是第一个Linux“non-FUSE”kerneldriver,支持对exFAT文件系统进行正常在读取和写入操作,并且是由东家微软开发。

exfat-nofuse在Linuxkernel3.8和3.9中通过测试,可需求的同学可以前往github下载。



 

参考网址:http://zh.wikipedia.org/wiki/ExFAT

http://zh.wikipedia.org/wiki/FUSE

http://fuse.sourceforge.net/

http://ask.zol.com.cn/q/26385.html

http://www.baike.com/wiki/exFAT

http://linuxtoy.org/archives/fuse-exfat-1-0.html

http://blog.csdn.net/xiaoqinpeng/article/details/7050182

http://blog.csdn.net/darkengine/article/details/7106207

http://www.cnblogs.com/lihaibo19891007/p/3144228.html

http://src.chromium.org/svn/trunk/src/net/base/file_stream_context_posix.cc

https://android.googlesource.com/platform/frameworks/base/+/1542af35976ce121b8a69812ab8dec7b71a0b283%5E1..1542af35976ce121b8a69812ab8dec7b71a0b283/

 




0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小孩子有购物狂病怎么办 拉杆箱的轮子卡怎么办 想你了怎么办的英文 那现在怎么办 英文怎写 平安证券账号忘了怎么办 发现发票是假的怎么办 公司收到假发票入账了怎么办 手表皮带有汗味怎么办 利客来购物卡丢了怎么办 乐天玛特倒闭卡怎么办 lv皮带买长了怎么办 密袋鼠咬了人怎么办 lv皮带如果长了怎么办 天赐农场公众号进不去了怎么办 苹果删了订阅号怎么办 蚂蚁借呗没有自动扣款怎么办 有对方qq号名字怎么办 腾讯模拟器刺激现场注册上限怎么办 丹阳智慧人社登入密码忘了怎么办? ipad系统被锁了怎么办 电脑管理员账号删了怎么办 自己电脑删文件需要管理员怎么办 苹果电脑管理员密码忘记了怎么办 电脑提示安全设置不允许下载怎么办 微信和ipad同步怎么办 苹果6空间已满怎么办 苹果6内存虚满怎么办 监控主机密码忘了怎么办 加购物车不下单怎么办 绑定qq账号消息不见了怎么办 现在的注册微信怎么办 爱奇艺手机号码被别人绑定了怎么办 手机号码换了支付宝账号怎么办 qq换手机号了怎么办呢 公司被注销了公众号怎么办 qq号被限制查找怎么办 qq号别人查找不到怎么办 qq邮箱已被注册怎么办 微信付款没网络怎么办 天猫买的假货店铺关门了怎么办 鞋小了半码怎么办