]> git.sven.stormbind.net Git - sven/fuse-exfat.git/commitdiff
New upstream version 1.3.0 upstream/1.3.0
authorSven Hoexter <sven@stormbind.net>
Wed, 31 Oct 2018 21:17:38 +0000 (22:17 +0100)
committerSven Hoexter <sven@stormbind.net>
Wed, 31 Oct 2018 21:17:38 +0000 (22:17 +0100)
18 files changed:
ChangeLog
Makefile.in
README
configure
configure.ac
fuse/Makefile.in
fuse/main.c
fuse/mount.exfat-fuse.8
libexfat/Makefile.am
libexfat/Makefile.in
libexfat/config.h.in
libexfat/exfat.h
libexfat/io.c
libexfat/log.c
libexfat/mount.c
libexfat/node.c
libexfat/platform.h
libexfat/repair.c [new file with mode: 0644]

index 8bff070de12ba13b4447086b2467319b892c9b4f..9e20bf53f0c66486a286d5527ad600f9fcca24cb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+1.3.0 (2018-09-15)
+
+* exfatfsck can now repair some errors.
+* Added experimental Android support for exfat-utils [liminghao, LongPingWEI,
+Pablo Mendez Hernandez, Pierre-Hugues Husson].
+* Cleaned up FUSE code preparing for FUSE 3 support.
+* Removed OpenBSD support as it does not handle -o option in fuse_main().
+* Re-introduced FreeBSD support [Oleksii Samorukov].
+* Fixed DragonFly BSD support [Tomohiro Kusumi].
+* dirent->d_type in now filled on readdir() [Mark Browning].
+
 1.2.8 (2018-02-03)
 
 * Fixed new files or directories creation in the root directory: ensure there
index fedf2baded7fb93a330e524c5cee2b9968859725..60823f6e09896e8dce5f18fbf03b2dd96ee838e3 100644 (file)
@@ -269,6 +269,8 @@ RANLIB = @RANLIB@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+UBLIO_CFLAGS = @UBLIO_CFLAGS@
+UBLIO_LIBS = @UBLIO_LIBS@
 VERSION = @VERSION@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
diff --git a/README b/README
index 500d72234ab2037b78c908b71f7b07ccf0bf8640..2b98bbce3c1cf7fe7298d41ed7ef881a311059f7 100644 (file)
--- a/README
+++ b/README
@@ -7,7 +7,7 @@ Supported operating systems:
 
 * GNU/Linux
 * Mac OS X 10.5 or later
-* OpenBSD
+* FreeBSD
 
 Most GNU/Linux distributions already have fuse-exfat and exfat-utils in their repositories, so you can just install and use them. The next chapter describes how to compile them from source.
 
index 11c45fb6c746ffc76259e2c75846f3519bcc3541..7132f5c2da3b7a99cfbefab1363835a32a475139 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for Free exFAT implementation 1.2.8.
+# Generated by GNU Autoconf 2.69 for Free exFAT implementation 1.3.0.
 #
 # Report bugs to <relan@users.noreply.github.com>.
 #
@@ -579,8 +579,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='Free exFAT implementation'
 PACKAGE_TARNAME='fuse-exfat'
-PACKAGE_VERSION='1.2.8'
-PACKAGE_STRING='Free exFAT implementation 1.2.8'
+PACKAGE_VERSION='1.3.0'
+PACKAGE_STRING='Free exFAT implementation 1.3.0'
 PACKAGE_BUGREPORT='relan@users.noreply.github.com'
 PACKAGE_URL='https://github.com/relan/exfat'
 
@@ -590,6 +590,8 @@ LTLIBOBJS
 LIBOBJS
 FUSE_LIBS
 FUSE_CFLAGS
+UBLIO_LIBS
+UBLIO_CFLAGS
 PKG_CONFIG_LIBDIR
 PKG_CONFIG_PATH
 PKG_CONFIG
@@ -696,6 +698,8 @@ CPPFLAGS
 PKG_CONFIG
 PKG_CONFIG_PATH
 PKG_CONFIG_LIBDIR
+UBLIO_CFLAGS
+UBLIO_LIBS
 FUSE_CFLAGS
 FUSE_LIBS'
 
@@ -1238,7 +1242,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures Free exFAT implementation 1.2.8 to adapt to many kinds of systems.
+\`configure' configures Free exFAT implementation 1.3.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1304,7 +1308,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Free exFAT implementation 1.2.8:";;
+     short | recursive ) echo "Configuration of Free exFAT implementation 1.3.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1333,6 +1337,9 @@ Some influential environment variables:
               directories to add to pkg-config's search path
   PKG_CONFIG_LIBDIR
               path overriding pkg-config's built-in search path
+  UBLIO_CFLAGS
+              C compiler flags for UBLIO, overriding pkg-config
+  UBLIO_LIBS  linker flags for UBLIO, overriding pkg-config
   FUSE_CFLAGS C compiler flags for FUSE, overriding pkg-config
   FUSE_LIBS   linker flags for FUSE, overriding pkg-config
 
@@ -1403,7 +1410,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Free exFAT implementation configure 1.2.8
+Free exFAT implementation configure 1.3.0
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1458,7 +1465,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by Free exFAT implementation $as_me 1.2.8, which was
+It was created by Free exFAT implementation $as_me 1.3.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2321,7 +2328,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='fuse-exfat'
- VERSION='1.2.8'
+ VERSION='1.3.0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -4215,6 +4222,83 @@ $as_echo "no" >&6; }
        fi
 fi
 
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for UBLIO" >&5
+$as_echo_n "checking for UBLIO... " >&6; }
+
+if test -n "$UBLIO_CFLAGS"; then
+    pkg_cv_UBLIO_CFLAGS="$UBLIO_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libublio\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libublio") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_UBLIO_CFLAGS=`$PKG_CONFIG --cflags "libublio" 2>/dev/null`
+                     test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$UBLIO_LIBS"; then
+    pkg_cv_UBLIO_LIBS="$UBLIO_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libublio\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libublio") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_UBLIO_LIBS=`$PKG_CONFIG --libs "libublio" 2>/dev/null`
+                     test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+               UBLIO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libublio" 2>&1`
+        else
+               UBLIO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libublio" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$UBLIO_PKG_ERRORS" >&5
+
+       :
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       :
+else
+       UBLIO_CFLAGS=$pkg_cv_UBLIO_CFLAGS
+       UBLIO_LIBS=$pkg_cv_UBLIO_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+  CFLAGS="$CFLAGS $UBLIO_CFLAGS"
+  LIBS="$LIBS $UBLIO_LIBS"
+
+$as_echo "#define USE_UBLIO 1" >>confdefs.h
+
+
+fi
+
 pkg_failed=no
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FUSE" >&5
 $as_echo_n "checking for FUSE... " >&6; }
@@ -4839,7 +4923,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by Free exFAT implementation $as_me 1.2.8, which was
+This file was extended by Free exFAT implementation $as_me 1.3.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -4906,7 +4990,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-Free exFAT implementation config.status 1.2.8
+Free exFAT implementation config.status 1.3.0
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index d0626cbf19c4958d3d49646b624004da28ba180a..d7fc1417be95bee8cd4c71cb0b76f19e454f3bca 100644 (file)
@@ -21,7 +21,7 @@
 #
 
 AC_INIT([Free exFAT implementation],
-       [1.2.8],
+       [1.3.0],
        [relan@users.noreply.github.com],
        [fuse-exfat],
        [https://github.com/relan/exfat])
@@ -31,6 +31,12 @@ AC_PROG_CC_C99
 AC_PROG_RANLIB
 AM_PROG_AR
 AC_SYS_LARGEFILE
+PKG_CHECK_MODULES([UBLIO], [libublio], [
+  CFLAGS="$CFLAGS $UBLIO_CFLAGS"
+  LIBS="$LIBS $UBLIO_LIBS"
+  AC_DEFINE([USE_UBLIO], [1],
+    [Define if block devices are not supported.])
+], [:])
 PKG_CHECK_MODULES([FUSE], [fuse])
 AC_CONFIG_HEADERS([libexfat/config.h])
 AC_CONFIG_FILES([
index 78994264f0323a5e08b80615dd8a421e9fa824ee..d463750e114995cb612f0895d5870d281b25f93c 100644 (file)
@@ -267,6 +267,8 @@ RANLIB = @RANLIB@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+UBLIO_CFLAGS = @UBLIO_CFLAGS@
+UBLIO_LIBS = @UBLIO_LIBS@
 VERSION = @VERSION@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
index e5e25d9499f2c253b28fba9d4ce52d607808ae79..c645390d3f3b5594122ece7ae05192151967670e 100644 (file)
@@ -42,9 +42,6 @@
        #error FUSE 2.6 or later is required
 #endif
 
-const char* default_options = "ro_fallback,allow_other,blkdev,big_writes,"
-               "default_permissions";
-
 struct exfat ef;
 
 static struct exfat_node* get_node(const struct fuse_file_info* fi)
@@ -105,6 +102,7 @@ static int fuse_exfat_readdir(const char* path, void* buffer,
        struct exfat_iterator it;
        int rc;
        char name[EXFAT_UTF8_NAME_BUFFER_MAX];
+       struct stat stbuf;
 
        exfat_debug("[%s] %s", __func__, path);
 
@@ -134,7 +132,8 @@ static int fuse_exfat_readdir(const char* path, void* buffer,
                exfat_debug("[%s] %s: %s, %"PRId64" bytes, cluster 0x%x", __func__,
                                name, node->is_contiguous ? "contiguous" : "fragmented",
                                node->size, node->start_cluster);
-               filler(buffer, name, NULL, 0);
+               exfat_stat(&ef, node, &stbuf);
+               filler(buffer, name, &stbuf, 0);
                exfat_put_node(&ef, node);
        }
        exfat_closedir(&ef, &it);
@@ -447,6 +446,12 @@ static char* add_fsname_option(char* options, const char* spec)
        return options;
 }
 
+static char* add_ro_option(char* options, bool ro)
+{
+       return ro ? add_option(options, "ro", NULL) : options;
+}
+
+#if defined(__linux__) || defined(__FreeBSD__)
 static char* add_user_option(char* options)
 {
        struct passwd* pw;
@@ -463,7 +468,9 @@ static char* add_user_option(char* options)
        }
        return add_option(options, "user", pw->pw_name);
 }
+#endif
 
+#if defined(__linux__)
 static char* add_blksize_option(char* options, long cluster_size)
 {
        long page_size = sysconf(_SC_PAGESIZE);
@@ -475,38 +482,57 @@ static char* add_blksize_option(char* options, long cluster_size)
        snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
        return add_option(options, "blksize", blksize);
 }
+#endif
 
-static char* add_fuse_options(char* options, const char* spec)
+static char* add_fuse_options(char* options, const char* spec, bool ro)
 {
        options = add_fsname_option(options, spec);
        if (options == NULL)
                return NULL;
+       options = add_ro_option(options, ro);
+       if (options == NULL)
+               return NULL;
+#if defined(__linux__) || defined(__FreeBSD__)
        options = add_user_option(options);
        if (options == NULL)
                return NULL;
+#endif
+#if defined(__linux__)
        options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
        if (options == NULL)
                return NULL;
-
+#endif
        return options;
 }
 
+static int fuse_exfat_main(char* mount_options, char* mount_point)
+{
+       char* argv[] = {"exfat", "-s", "-o", mount_options, mount_point, NULL};
+       return fuse_main(sizeof(argv) / sizeof(argv[0]) - 1, argv,
+                       &fuse_exfat_ops, NULL);
+}
+
 int main(int argc, char* argv[])
 {
-       struct fuse_args mount_args = FUSE_ARGS_INIT(0, NULL);
-       struct fuse_args newfs_args = FUSE_ARGS_INIT(0, NULL);
        const char* spec = NULL;
-       const char* mount_point = NULL;
-       char* mount_options;
-       int debug = 0;
-       struct fuse_chan* fc = NULL;
-       struct fuse* fh = NULL;
+       char* mount_point = NULL;
+       char* fuse_options;
+       char* exfat_options;
        int opt;
+       int rc;
 
        printf("FUSE exfat %s\n", VERSION);
 
-       mount_options = strdup(default_options);
-       if (mount_options == NULL)
+       fuse_options = strdup("allow_other,"
+#if defined(__linux__) || defined(__FreeBSD__)
+                       "big_writes,"
+#endif
+#if defined(__linux__)
+                       "blkdev,"
+#endif
+                       "default_permissions");
+       exfat_options = strdup("ro_fallback");
+       if (fuse_options == NULL || exfat_options == NULL)
        {
                exfat_error("failed to allocate options string");
                return 1;
@@ -517,122 +543,65 @@ int main(int argc, char* argv[])
                switch (opt)
                {
                case 'd':
-                       debug = 1;
+                       fuse_options = add_option(fuse_options, "debug", NULL);
+                       if (fuse_options == NULL)
+                       {
+                               free(exfat_options);
+                               return 1;
+                       }
                        break;
                case 'n':
                        break;
                case 'o':
-                       mount_options = add_option(mount_options, optarg, NULL);
-                       if (mount_options == NULL)
+                       exfat_options = add_option(exfat_options, optarg, NULL);
+                       if (exfat_options == NULL)
+                       {
+                               free(fuse_options);
                                return 1;
+                       }
                        break;
                case 'V':
-                       free(mount_options);
+                       free(exfat_options);
+                       free(fuse_options);
                        puts("Copyright (C) 2010-2018  Andrew Nayenko");
                        return 0;
                case 'v':
                        break;
                default:
-                       free(mount_options);
+                       free(exfat_options);
+                       free(fuse_options);
                        usage(argv[0]);
                        break;
                }
        }
        if (argc - optind != 2)
        {
-               free(mount_options);
+               free(exfat_options);
+               free(fuse_options);
                usage(argv[0]);
        }
        spec = argv[optind];
        mount_point = argv[optind + 1];
 
-       if (exfat_mount(&ef, spec, mount_options) != 0)
+       if (exfat_mount(&ef, spec, exfat_options) != 0)
        {
-               free(mount_options);
+               free(exfat_options);
+               free(fuse_options);
                return 1;
        }
 
-       if (ef.ro == -1) /* read-only fallback was used */
-       {
-               mount_options = add_option(mount_options, "ro", NULL);
-               if (mount_options == NULL)
-               {
-                       exfat_unmount(&ef);
-                       return 1;
-               }
-       }
-
-       mount_options = add_fuse_options(mount_options, spec);
-       if (mount_options == NULL)
-       {
-               exfat_unmount(&ef);
-               return 1;
-       }
+       free(exfat_options);
 
-       /* create arguments for fuse_mount() */
-       if (fuse_opt_add_arg(&mount_args, "exfat") != 0 ||
-               fuse_opt_add_arg(&mount_args, "-o") != 0 ||
-               fuse_opt_add_arg(&mount_args, mount_options) != 0)
+       fuse_options = add_fuse_options(fuse_options, spec, ef.ro != 0);
+       if (fuse_options == NULL)
        {
                exfat_unmount(&ef);
-               free(mount_options);
                return 1;
        }
 
-       free(mount_options);
+       /* let FUSE do all its wizardry */
+       rc = fuse_exfat_main(fuse_options, mount_point);
 
-       /* create FUSE mount point */
-       fc = fuse_mount(mount_point, &mount_args);
-       fuse_opt_free_args(&mount_args);
-       if (fc == NULL)
-       {
-               exfat_unmount(&ef);
-               return 1;
-       }
-
-       /* create arguments for fuse_new() */
-       if (fuse_opt_add_arg(&newfs_args, "") != 0 ||
-               (debug && fuse_opt_add_arg(&newfs_args, "-d") != 0))
-       {
-               fuse_unmount(mount_point, fc);
-               exfat_unmount(&ef);
-               return 1;
-       }
-
-       /* create new FUSE file system */
-       fh = fuse_new(fc, &newfs_args, &fuse_exfat_ops,
-                       sizeof(struct fuse_operations), NULL);
-       fuse_opt_free_args(&newfs_args);
-       if (fh == NULL)
-       {
-               fuse_unmount(mount_point, fc);
-               exfat_unmount(&ef);
-               return 1;
-       }
-
-       /* exit session on HUP, TERM and INT signals and ignore PIPE signal */
-       if (fuse_set_signal_handlers(fuse_get_session(fh)) != 0)
-       {
-               fuse_unmount(mount_point, fc);
-               fuse_destroy(fh);
-               exfat_unmount(&ef);
-               exfat_error("failed to set signal handlers");
-               return 1;
-       }
-
-       /* go to background (unless "-d" option is passed) and run FUSE
-          main loop */
-       if (fuse_daemonize(debug) == 0)
-       {
-               if (fuse_loop(fh) != 0)
-                       exfat_error("FUSE loop failure");
-       }
-       else
-               exfat_error("failed to daemonize");
-
-       fuse_remove_signal_handlers(fuse_get_session(fh));
-       /* note that fuse_unmount() must be called BEFORE fuse_destroy() */
-       fuse_unmount(mount_point, fc);
-       fuse_destroy(fh);
-       return 0;
+       free(fuse_options);
+       return rc;
 }
index 602ddc9867ec2ba6a382a286f0647c653ab34fb8..e0925b2345e528c71e3722a61bea511f310dc0f0 100644 (file)
@@ -1,6 +1,6 @@
 .\" Copyright (C) 2010-2016  Andrew Nayenko
 .\"
-.TH EXFAT-FUSE 8 "July 2010"
+.TH EXFAT-FUSE 8 "November 2015"
 .SH NAME
 mount.exfat-fuse \- mount an exFAT file system
 .SH SYNOPSIS
index 4ec9df5c93fe89a27263e3ed2e959995bd734a55..d639e13b799b2d2b0599044fa0a97b5a9baea191 100644 (file)
@@ -33,6 +33,7 @@ libexfat_a_SOURCES = \
        mount.c \
        node.c \
        platform.h \
+       repair.c \
        time.c \
        utf.c \
        utils.c
index d039dfea38edcc4a187ffabbe9e50b92918959a8..9c443235b53de481b0cd3eba86b901aa95ce9eaf 100644 (file)
@@ -127,8 +127,8 @@ am__v_AR_1 =
 libexfat_a_AR = $(AR) $(ARFLAGS)
 libexfat_a_LIBADD =
 am_libexfat_a_OBJECTS = cluster.$(OBJEXT) io.$(OBJEXT) log.$(OBJEXT) \
-       lookup.$(OBJEXT) mount.$(OBJEXT) node.$(OBJEXT) time.$(OBJEXT) \
-       utf.$(OBJEXT) utils.$(OBJEXT)
+       lookup.$(OBJEXT) mount.$(OBJEXT) node.$(OBJEXT) \
+       repair.$(OBJEXT) time.$(OBJEXT) utf.$(OBJEXT) utils.$(OBJEXT)
 libexfat_a_OBJECTS = $(am_libexfat_a_OBJECTS)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -236,6 +236,8 @@ RANLIB = @RANLIB@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+UBLIO_CFLAGS = @UBLIO_CFLAGS@
+UBLIO_LIBS = @UBLIO_LIBS@
 VERSION = @VERSION@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
@@ -293,6 +295,7 @@ libexfat_a_SOURCES = \
        mount.c \
        node.c \
        platform.h \
+       repair.c \
        time.c \
        utf.c \
        utils.c
@@ -367,6 +370,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lookup.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mount.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repair.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utf.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@
index d096cd307d649e5ab2b147dc931acd6c2dc6136e..c3312ab6a2a7f4820d72486dc3925e7968cee670 100644 (file)
@@ -21,6 +21,9 @@
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
+/* Define if block devices are not supported. */
+#undef USE_UBLIO
+
 /* Version number of package */
 #undef VERSION
 
index e0d33e24ddb109783b235f65c882f591fd781a93..2342be4f531a5b0c489e81ee0710186b6a00dab2 100644 (file)
 #ifndef EXFAT_H_INCLUDED
 #define EXFAT_H_INCLUDED
 
+#ifndef ANDROID
+/* Android.bp is used instead of autotools when targeting Android */
 #include "config.h"
+#endif
 #include "compiler.h"
 #include "exfatfs.h"
 #include <stdio.h>
@@ -61,6 +64,9 @@
 #define BMAP_CLR(bitmap, index) \
        ((bitmap)[BMAP_BLOCK(index)] &= ~BMAP_MASK(index))
 
+#define EXFAT_REPAIR(hook, ef, ...) \
+       (exfat_ask_to_fix(ef) && exfat_fix_ ## hook(ef, __VA_ARGS__))
+
 /* The size of off_t type must be 64 bits. File systems larger than 2 GB will
    be corrupted with 32-bit off_t. */
 STATIC_ASSERT(sizeof(off_t) == 8);
@@ -119,6 +125,7 @@ struct exfat
        gid_t gid;
        int ro;
        bool noatime;
+       enum { EXFAT_REPAIR_NO, EXFAT_REPAIR_ASK, EXFAT_REPAIR_YES } repair;
 };
 
 /* in-core nodes iterator */
@@ -135,6 +142,7 @@ struct exfat_human_bytes
 };
 
 extern int exfat_errors;
+extern int exfat_errors_fixed;
 
 void exfat_bug(const char* format, ...) PRINTF NORETURN;
 void exfat_error(const char* format, ...) PRINTF;
@@ -225,4 +233,12 @@ void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
                uint8_t* centisec);
 void exfat_tzset(void);
 
+bool exfat_ask_to_fix(const struct exfat* ef);
+bool exfat_fix_invalid_vbr_checksum(const struct exfat* ef, void* sector,
+               uint32_t vbr_checksum);
+bool exfat_fix_invalid_node_checksum(const struct exfat* ef,
+               struct exfat_node* node);
+bool exfat_fix_unknown_entry(struct exfat* ef, struct exfat_node* dir,
+               const struct exfat_entry* entry, off_t offset);
+
 #endif /* ifndef EXFAT_H_INCLUDED */
index bae0cf15a1412dfdac2c67b4085d35aa56361bc6..bc92c7cf9eab396eb465b93400cff7fc448a778b 100644 (file)
 #elif __linux__
 #include <sys/mount.h>
 #endif
+#ifdef USE_UBLIO
+#include <sys/uio.h>
+#include <ublio.h>
+#endif
 
 struct exfat_dev
 {
        int fd;
        enum exfat_mode mode;
        off_t size; /* in bytes */
+#ifdef USE_UBLIO
+       off_t pos;
+       ublio_filehandle_t ufh;
+#endif
 };
 
 static bool is_open(int fd)
@@ -80,6 +88,9 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
 {
        struct exfat_dev* dev;
        struct stat stbuf;
+#ifdef USE_UBLIO
+       struct ublio_param up;
+#endif
 
        /* The system allocates file descriptors sequentially. If we have been
           started with stdin (0), stdout (1) or stderr (2) closed, the system
@@ -235,6 +246,24 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
                }
        }
 
+#ifdef USE_UBLIO
+       memset(&up, 0, sizeof(struct ublio_param));
+       up.up_blocksize = 256 * 1024;
+       up.up_items = 64;
+       up.up_grace = 32;
+       up.up_priv = &dev->fd;
+
+       dev->pos = 0;
+       dev->ufh = ublio_open(&up);
+       if (dev->ufh == NULL)
+       {
+               close(dev->fd);
+               free(dev);
+               exfat_error("failed to initialize ublio");
+               return NULL;
+       }
+#endif
+
        return dev;
 }
 
@@ -242,6 +271,13 @@ int exfat_close(struct exfat_dev* dev)
 {
        int rc = 0;
 
+#ifdef USE_UBLIO
+       if (ublio_close(dev->ufh) != 0)
+       {
+               exfat_error("failed to close ublio");
+               rc = -EIO;
+       }
+#endif
        if (close(dev->fd) != 0)
        {
                exfat_error("failed to close device: %s", strerror(errno));
@@ -255,6 +291,13 @@ int exfat_fsync(struct exfat_dev* dev)
 {
        int rc = 0;
 
+#ifdef USE_UBLIO
+       if (ublio_fsync(dev->ufh) != 0)
+       {
+               exfat_error("ublio fsync failed");
+               rc = -EIO;
+       }
+#endif
        if (fsync(dev->fd) != 0)
        {
                exfat_error("fsync failed: %s", strerror(errno));
@@ -275,29 +318,56 @@ off_t exfat_get_size(const struct exfat_dev* dev)
 
 off_t exfat_seek(struct exfat_dev* dev, off_t offset, int whence)
 {
+#ifdef USE_UBLIO
+       /* XXX SEEK_CUR will be handled incorrectly */
+       return dev->pos = lseek(dev->fd, offset, whence);
+#else
        return lseek(dev->fd, offset, whence);
+#endif
 }
 
 ssize_t exfat_read(struct exfat_dev* dev, void* buffer, size_t size)
 {
+#ifdef USE_UBLIO
+       ssize_t result = ublio_pread(dev->ufh, buffer, size, dev->pos);
+       if (result >= 0)
+               dev->pos += size;
+       return result;
+#else
        return read(dev->fd, buffer, size);
+#endif
 }
 
 ssize_t exfat_write(struct exfat_dev* dev, const void* buffer, size_t size)
 {
+#ifdef USE_UBLIO
+       ssize_t result = ublio_pwrite(dev->ufh, buffer, size, dev->pos);
+       if (result >= 0)
+               dev->pos += size;
+       return result;
+#else
        return write(dev->fd, buffer, size);
+#endif
 }
 
 ssize_t exfat_pread(struct exfat_dev* dev, void* buffer, size_t size,
                off_t offset)
 {
+#ifdef USE_UBLIO
+       return ublio_pread(dev->ufh, buffer, size, offset);
+#else
        return pread(dev->fd, buffer, size, offset);
+#endif
 }
 
 ssize_t exfat_pwrite(struct exfat_dev* dev, const void* buffer, size_t size,
                off_t offset)
 {
+#ifdef USE_UBLIO
+       return ublio_pwrite(dev->ufh, buffer, size, offset);
+#else
        return pwrite(dev->fd, buffer, size, offset);
+#endif
 }
 
 ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
index d62bf757128eea39d5a1f53f3b6d3da1c28561f4..f29f74b1d68c22f7702532a5bb933ea8709edc3b 100644 (file)
 
 #include "exfat.h"
 #include <stdarg.h>
+#ifdef __ANDROID__
+#include <android/log.h>
+#else
 #include <syslog.h>
+#endif
 #include <unistd.h>
 
 int exfat_errors;
@@ -43,8 +47,12 @@ void exfat_bug(const char* format, ...)
        va_end(ap);
        fputs(".\n", stderr);
 
+#ifdef __ANDROID__
+       __android_log_vprint(ANDROID_LOG_FATAL, PACKAGE, format, aq);
+#else
        if (!isatty(STDERR_FILENO))
                vsyslog(LOG_CRIT, format, aq);
+#endif
        va_end(aq);
 
        abort();
@@ -67,8 +75,12 @@ void exfat_error(const char* format, ...)
        va_end(ap);
        fputs(".\n", stderr);
 
+#ifdef __ANDROID__
+       __android_log_vprint(ANDROID_LOG_ERROR, PACKAGE, format, aq);
+#else
        if (!isatty(STDERR_FILENO))
                vsyslog(LOG_ERR, format, aq);
+#endif
        va_end(aq);
 }
 
@@ -89,8 +101,12 @@ void exfat_warn(const char* format, ...)
        va_end(ap);
        fputs(".\n", stderr);
 
+#ifdef __ANDROID__
+       __android_log_vprint(ANDROID_LOG_WARN, PACKAGE, format, aq);
+#else
        if (!isatty(STDERR_FILENO))
                vsyslog(LOG_WARNING, format, aq);
+#endif
        va_end(aq);
 }
 
index 3b18b122e43ea087ebf401b014d3bf3f509ccc29..4284aee676fd43105363eafd4bc7e5063f4fb45e 100644 (file)
@@ -103,15 +103,28 @@ static void parse_options(struct exfat* ef, const char* options)
        ef->gid = get_int_option(options, "gid", 10, getegid());
 
        ef->noatime = match_option(options, "noatime");
+
+       switch (get_int_option(options, "repair", 10, 0))
+       {
+       case 1:
+               ef->repair = EXFAT_REPAIR_ASK;
+               break;
+       case 2:
+               ef->repair = EXFAT_REPAIR_YES;
+               break;
+       default:
+               ef->repair = EXFAT_REPAIR_NO;
+               break;
+       }
 }
 
-static bool verify_vbr_checksum(struct exfat_dev* dev, void* sector,
-               off_t sector_size)
+static bool verify_vbr_checksum(const struct exfat* ef, void* sector)
 {
+       off_t sector_size = SECTOR_SIZE(*ef->sb);
        uint32_t vbr_checksum;
        int i;
 
-       if (exfat_pread(dev, sector, sector_size, 0) < 0)
+       if (exfat_pread(ef->dev, sector, sector_size, 0) < 0)
        {
                exfat_error("failed to read boot sector");
                return false;
@@ -119,7 +132,7 @@ static bool verify_vbr_checksum(struct exfat_dev* dev, void* sector,
        vbr_checksum = exfat_vbr_start_checksum(sector, sector_size);
        for (i = 1; i < 11; i++)
        {
-               if (exfat_pread(dev, sector, sector_size, i * sector_size) < 0)
+               if (exfat_pread(ef->dev, sector, sector_size, i * sector_size) < 0)
                {
                        exfat_error("failed to read VBR sector");
                        return false;
@@ -127,7 +140,7 @@ static bool verify_vbr_checksum(struct exfat_dev* dev, void* sector,
                vbr_checksum = exfat_vbr_add_checksum(sector, sector_size,
                                vbr_checksum);
        }
-       if (exfat_pread(dev, sector, sector_size, i * sector_size) < 0)
+       if (exfat_pread(ef->dev, sector, sector_size, i * sector_size) < 0)
        {
                exfat_error("failed to read VBR checksum sector");
                return false;
@@ -137,7 +150,8 @@ static bool verify_vbr_checksum(struct exfat_dev* dev, void* sector,
                {
                        exfat_error("invalid VBR checksum 0x%x (expected 0x%x)",
                                        le32_to_cpu(((const le32_t*) sector)[i]), vbr_checksum);
-                       return false;
+                       if (!EXFAT_REPAIR(invalid_vbr_checksum, ef, sector, vbr_checksum))
+                               return false;
                }
        return true;
 }
@@ -252,7 +266,7 @@ int exfat_mount(struct exfat* ef, const char* spec, const char* options)
                return -ENOMEM;
        }
        /* use zero_cluster as a temporary buffer for VBR checksum verification */
-       if (!verify_vbr_checksum(ef->dev, ef->zero_cluster, SECTOR_SIZE(*ef->sb)))
+       if (!verify_vbr_checksum(ef, ef->zero_cluster))
        {
                exfat_free(ef);
                return -EIO;
index 1ccb1c9eda0d41ddb70f64496563cd9f5e3a1472..ab1d7d6d04c7d36831c34c20dda7b0c5a4fade6e 100644 (file)
@@ -223,7 +223,8 @@ static bool check_node(const struct exfat* ef, struct exfat_node* node,
                exfat_get_name(node, buffer);
                exfat_error("'%s' has invalid checksum (%#hx != %#hx)", buffer,
                                le16_to_cpu(actual_checksum), le16_to_cpu(meta1->checksum));
-               ret = false;
+               if (!EXFAT_REPAIR(invalid_node_checksum, ef, node))
+                       ret = false;
        }
 
        /*
@@ -516,7 +517,8 @@ static int readdir(struct exfat* ef, struct exfat_node* parent,
                                break; /* deleted entry, ignore it */
 
                        exfat_error("unknown entry type %#hhx", entry.type);
-                       return -EIO;
+                       if (!EXFAT_REPAIR(unknown_entry, ef, parent, &entry, *offset))
+                               return -EIO;
                }
                *offset += sizeof(entry);
        }
index e10c46bb6363a791dd6b643157e633c97e4ce738..9ab3155d36bafc823f60a93d00679e1fa8a686c5 100644 (file)
@@ -46,7 +46,7 @@
 #define EXFAT_LITTLE_ENDIAN LITTLE_ENDIAN
 #define EXFAT_BIG_ENDIAN BIG_ENDIAN
 
-#elif defined(__FreeBSD__) || defined(__DragonFlyBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
 
 #include <sys/endian.h>
 #define exfat_bswap16(x) bswap16(x)
diff --git a/libexfat/repair.c b/libexfat/repair.c
new file mode 100644 (file)
index 0000000..237ab3a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+       repair.c (09.03.17)
+       exFAT file system implementation library.
+
+       Free exFAT implementation.
+       Copyright (C) 2010-2018  Andrew Nayenko
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation, either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License along
+       with this program; if not, write to the Free Software Foundation, Inc.,
+       51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "exfat.h"
+#include <strings.h>
+
+int exfat_errors_fixed;
+
+bool exfat_ask_to_fix(const struct exfat* ef)
+{
+       const char* question = "Fix (Y/N)?";
+       char answer[8];
+       bool yeah, nope;
+
+       switch (ef->repair)
+       {
+       case EXFAT_REPAIR_NO:
+               return false;
+       case EXFAT_REPAIR_YES:
+               printf("%s %s", question, "Y\n");
+               return true;
+       case EXFAT_REPAIR_ASK:
+               do
+               {
+                       printf("%s ", question);
+                       fflush(stdout);
+                       if (fgets(answer, sizeof(answer), stdin))
+                       {
+                               yeah = strcasecmp(answer, "Y\n") == 0;
+                               nope = strcasecmp(answer, "N\n") == 0;
+                       }
+                       else
+                       {
+                               yeah = false;
+                               nope = true;
+                       }
+               }
+               while (!yeah && !nope);
+               return yeah;
+       }
+       exfat_bug("invalid repair option value: %d", ef->repair);
+}
+
+bool exfat_fix_invalid_vbr_checksum(const struct exfat* ef, void* sector,
+               uint32_t vbr_checksum)
+{
+       size_t i;
+       off_t sector_size = SECTOR_SIZE(*ef->sb);
+
+       for (i = 0; i < sector_size / sizeof(vbr_checksum); i++)
+               ((le32_t*) sector)[i] = cpu_to_le32(vbr_checksum);
+       if (exfat_pwrite(ef->dev, sector, sector_size, 11 * sector_size) < 0)
+       {
+               exfat_error("failed to write correct VBR checksum");
+               return false;
+       }
+       exfat_errors_fixed++;
+       return true;
+}
+
+bool exfat_fix_invalid_node_checksum(const struct exfat* ef,
+               struct exfat_node* node)
+{
+       /* checksum will be rewritten by exfat_flush_node() */
+       node->is_dirty = true;
+
+       exfat_errors_fixed++;
+       return true;
+}
+
+bool exfat_fix_unknown_entry(struct exfat* ef, struct exfat_node* dir,
+               const struct exfat_entry* entry, off_t offset)
+{
+       struct exfat_entry deleted = *entry;
+
+       deleted.type &= ~EXFAT_ENTRY_VALID;
+       if (exfat_generic_pwrite(ef, dir, &deleted, sizeof(struct exfat_entry),
+                       offset) != sizeof(struct exfat_entry))
+               return false;
+
+       exfat_errors_fixed++;
+       return true;
+}