移植exFAT到Android4.2.2

                                                    xinu

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

优点[编辑]

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 XLinux之间的兼容性。
  • 大小最大可为每扇区225字节,最大32 MB。
  • 由于采用了空余空间寻址,空间分配和删除的性能得以改进。
  • 在单一文件夹内支持超过216个文件。
  • 支持访问控制清单(但在Windows Vista SP1中尚未支持)[4]
  • 支持Transaction-Safe FAT文件系统 (TFAT)(在WinCE中可选的功能)。
  • 提供给OEM的可定义参数可以使这个文件系统适应不同特色的设备。
  • 时间戳记能够使用UTC[5]时间而不仅仅是所在时区(从Vista SP2开始)

缺点[编辑]

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

  • 某些设备(如PDADC)将无法使用exFAT格式的存储卡。
  • 使用exFAT的设备将不能用Windows VistaReadyBoost功能。(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/

 




  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值