+1.2.4 (2016-06-03)
+
+* Fixed wrong files names hashes when upper case table is compressed.
+* Man pages are now installed by default.
+* Commas and backslashes in device names are now escaped.
+
1.2.3 (2015-12-19)
* Fixed clusters loss when file renaming replaces target.
# Automake source.
#
# Free exFAT implementation.
-# Copyright (C) 2010-2015 Andrew Nayenko
+# Copyright (C) 2010-2016 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
# Automake source.
#
# Free exFAT implementation.
-# Copyright (C) 2010-2015 Andrew Nayenko
+# Copyright (C) 2010-2016 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
* GNU/Linux
* Mac OS X 10.5 or later
-* FreeBSD
* OpenBSD
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.
Compiling
---------
-To build this project under GNU/Linux you need to install the following packages:
+To build this project on GNU/Linux you need to install the following packages:
-* pkg-config
+* [pkg-config][7]
* fuse-devel (or libfuse-dev)
-* gcc
-* make
+* [gcc][8]
+* [make][9]
+
+On Mac OS X:
+
+* pkg-config
+* [OSXFUSE][10]
+* [Xcode][11] (legacy versions include autotools but their versions are too old)
+
+On OpenBSD:
+
Get the source code, change directory and compile:
- ./configure --prefix=/usr
+ ./configure
make
-Then install driver and utilities:
+Then install driver and utilities (from root):
- sudo make install
+ make install
-You can remove them using this command:
+You can remove them using this command (from root):
- sudo make uninstall
+ make uninstall
Mounting
--------
-Modern GNU/Linux distributions will mount exFAT volumes automatically—util-linux-ng 2.18 (was renamed to util-linux in 2.19) is required for this. Anyway, you can mount manually (you will need root privileges):
+Modern GNU/Linux distributions (with [util-linux][12] 2.18 or later) will mount exFAT volumes automatically. Anyway, you can mount manually (from root):
- sudo mount.exfat-fuse /dev/sdXn /mnt/exfat
+ mount.exfat-fuse /dev/spec /mnt/exfat
-where /dev/sdXn is the partition special file, /mnt/exfat is a mountpoint.
+where /dev/spec is the [device file][13], /mnt/exfat is a mountpoint.
Feedback
--------
If you have any questions, issues, suggestions, bug reports, etc. please create an [issue][3]. Pull requests are also welcome!
-[1]: http://en.wikipedia.org/wiki/ExFAT
-[2]: http://en.wikipedia.org/wiki/Filesystem_in_Userspace
+[1]: https://en.wikipedia.org/wiki/ExFAT
+[2]: https://en.wikipedia.org/wiki/Filesystem_in_Userspace
[3]: https://github.com/relan/exfat/issues
+[7]: http://www.freedesktop.org/wiki/Software/pkg-config/
+[8]: https://gcc.gnu.org/
+[9]: https://www.gnu.org/software/make/
+[10]: https://osxfuse.github.io/
+[11]: https://en.wikipedia.org/wiki/Xcode
+[12]: https://www.kernel.org/pub/linux/utils/util-linux/
+[13]: https://en.wikipedia.org/wiki/Device_file
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for Free exFAT implementation 1.2.3.
+# Generated by GNU Autoconf 2.69 for Free exFAT implementation 1.2.4.
#
# Report bugs to <relan@users.noreply.github.com>.
#
# Identity of this package.
PACKAGE_NAME='Free exFAT implementation'
PACKAGE_TARNAME='fuse-exfat'
-PACKAGE_VERSION='1.2.3'
-PACKAGE_STRING='Free exFAT implementation 1.2.3'
+PACKAGE_VERSION='1.2.4'
+PACKAGE_STRING='Free exFAT implementation 1.2.4'
PACKAGE_BUGREPORT='relan@users.noreply.github.com'
PACKAGE_URL='https://github.com/relan/exfat'
# 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.3 to adapt to many kinds of systems.
+\`configure' configures Free exFAT implementation 1.2.4 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of Free exFAT implementation 1.2.3:";;
+ short | recursive ) echo "Configuration of Free exFAT implementation 1.2.4:";;
esac
cat <<\_ACEOF
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-Free exFAT implementation configure 1.2.3
+Free exFAT implementation configure 1.2.4
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
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.3, which was
+It was created by Free exFAT implementation $as_me 1.2.4, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
# Define the identity of the package.
PACKAGE='fuse-exfat'
- VERSION='1.2.3'
+ VERSION='1.2.4'
cat >>confdefs.h <<_ACEOF
# 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.3, which was
+This file was extended by Free exFAT implementation $as_me 1.2.4, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
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.3
+Free exFAT implementation config.status 1.2.4
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
# Autoconf source.
#
# Free exFAT implementation.
-# Copyright (C) 2010-2015 Andrew Nayenko
+# Copyright (C) 2010-2016 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
#
AC_INIT([Free exFAT implementation],
- [1.2.3],
+ [1.2.4],
[relan@users.noreply.github.com],
[fuse-exfat],
[https://github.com/relan/exfat])
-AM_INIT_AUTOMAKE([1.11.2 -Wall -Werror foreign subdir-objects no-installman])
+AM_INIT_AUTOMAKE([1.11.2 -Wall -Werror foreign subdir-objects])
AC_PROG_CC
AC_PROG_CC_C99
AC_PROG_RANLIB
# Automake source.
#
# Free exFAT implementation.
-# Copyright (C) 2010-2015 Andrew Nayenko
+# Copyright (C) 2010-2016 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
# Automake source.
#
# Free exFAT implementation.
-# Copyright (C) 2010-2015 Andrew Nayenko
+# Copyright (C) 2010-2016 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
CONFIG_HEADER = $(top_builddir)/libexfat/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
-am__installdirs = "$(DESTDIR)$(sbindir)"
+am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)"
PROGRAMS = $(sbin_PROGRAMS)
am_mount_exfat_fuse_OBJECTS = mount_exfat_fuse-main.$(OBJEXT)
mount_exfat_fuse_OBJECTS = $(am_mount_exfat_fuse_OBJECTS)
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='mount_exfat_fuse-main.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mount_exfat_fuse_CPPFLAGS) $(CPPFLAGS) $(mount_exfat_fuse_CFLAGS) $(CFLAGS) -c -o mount_exfat_fuse-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi`
-
install-man8: $(dist_man8_MANS)
@$(NORMAL_INSTALL)
@list1='$(dist_man8_MANS)'; \
done
check-am: all-am
check: check-am
-all-am: Makefile $(PROGRAMS)
+all-am: Makefile $(PROGRAMS) $(MANS)
installdirs:
- for dir in "$(DESTDIR)$(sbindir)"; do \
+ for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
info-am:
-install-data-am:
+install-data-am: install-man
install-dvi: install-dvi-am
ps-am:
-uninstall-am: uninstall-sbinPROGRAMS
+uninstall-am: uninstall-man uninstall-sbinPROGRAMS
@$(NORMAL_INSTALL)
$(MAKE) $(AM_MAKEFLAGS) uninstall-hook
uninstall-man: uninstall-man8
FUSE-based exFAT implementation. Requires FUSE 2.6 or later.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
return options;
}
+static void escape(char* escaped, const char* orig)
+{
+ do
+ {
+ if (*orig == ',' || *orig == '\\')
+ *escaped++ = '\\';
+ }
+ while ((*escaped++ = *orig++));
+}
+
+static char* add_fsname_option(char* options, const char* spec)
+{
+ /* escaped string cannot be more than twice as big as the original one */
+ char* escaped = malloc(strlen(spec) * 2 + 1);
+
+ if (escaped == NULL)
+ {
+ free(options);
+ exfat_error("failed to allocate escaped string for %s", spec);
+ return NULL;
+ }
+
+ /* on some platforms (e.g. Android, Solaris) device names can contain
+ commas */
+ escape(escaped, spec);
+ options = add_option(options, "fsname", escaped);
+ free(escaped);
+ return options;
+}
+
static char* add_user_option(char* options)
{
struct passwd* pw;
static char* add_fuse_options(char* options, const char* spec)
{
- options = add_option(options, "fsname", spec);
+ options = add_fsname_option(options, spec);
if (options == NULL)
return NULL;
options = add_user_option(options);
break;
case 'V':
free(mount_options);
- puts("Copyright (C) 2010-2015 Andrew Nayenko");
+ puts("Copyright (C) 2010-2016 Andrew Nayenko");
return 0;
case 'v':
break;
-.\" Copyright (C) 2010-2015 Andrew Nayenko
+.\" Copyright (C) 2010-2016 Andrew Nayenko
.\"
.TH EXFAT-FUSE 8 "July 2010"
.SH NAME
# Automake source.
#
# Free exFAT implementation.
-# Copyright (C) 2010-2015 Andrew Nayenko
+# Copyright (C) 2010-2016 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
# Automake source.
#
# Free exFAT implementation.
-# Copyright (C) 2010-2015 Andrew Nayenko
+# Copyright (C) 2010-2016 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
Endianness stuff. exFAT uses little-endian byte order.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
exFAT file system implementation library.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
showstopper.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
implementation.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
{
struct exfat_dev* dev;
struct exfat_super_block* sb;
- le16_t* upcase;
- size_t upcase_chars;
+ uint16_t* upcase;
struct exfat_node* root;
struct
{
Definitions of structures and constants used in exFAT file system.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
PACKED;
STATIC_ASSERT(sizeof(struct exfat_entry_bitmap) == 32);
+#define EXFAT_UPCASE_CHARS 0x10000
+
struct exfat_entry_upcase /* upper case translation table */
{
uint8_t type; /* EXFAT_ENTRY_UPCASE */
exFAT file system implementation library.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
#include <sys/ioctl.h>
#endif
#include <sys/mount.h>
-#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 int open_ro(const char* spec)
{
struct exfat_dev* dev;
struct stat stbuf;
-#ifdef USE_UBLIO
- struct ublio_param up;
-#endif
dev = malloc(sizeof(struct exfat_dev));
if (dev == NULL)
}
}
-#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;
}
{
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));
{
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));
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,
exFAT file system implementation library.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
exFAT file system implementation library.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
static int compare_char(struct exfat* ef, uint16_t a, uint16_t b)
{
- if (a >= ef->upcase_chars || b >= ef->upcase_chars)
- return (int) a - (int) b;
-
- return (int) le16_to_cpu(ef->upcase[a]) - (int) le16_to_cpu(ef->upcase[b]);
+ return (int) ef->upcase[a] - (int) ef->upcase[b];
}
static int compare_name(struct exfat* ef, const le16_t* a, const le16_t* b)
exFAT file system implementation library.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
ef->sb = NULL;
free(ef->upcase);
ef->upcase = NULL;
- ef->upcase_chars = 0;
}
exFAT file system implementation library.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
return true;
}
+static void decompress_upcase(uint16_t* output, const le16_t* source,
+ size_t size)
+{
+ size_t si;
+ size_t oi;
+
+ for (oi = 0; oi < EXFAT_UPCASE_CHARS; oi++)
+ output[oi] = oi;
+
+ for (si = 0, oi = 0; si < size && oi < EXFAT_UPCASE_CHARS; si++)
+ {
+ uint16_t ch = le16_to_cpu(source[si]);
+
+ if (ch == 0xffff && si + 1 < size) /* indicates a run */
+ oi += le16_to_cpu(source[++si]);
+ else
+ output[oi++] = ch;
+ }
+}
+
/*
* Reads one entry in directory at position pointed by iterator and fills
* node structure.
uint16_t reference_checksum = 0;
uint16_t actual_checksum = 0;
uint64_t valid_size = 0;
+ uint64_t upcase_size = 0;
+ le16_t* upcase_comp = NULL;
*node = NULL;
le32_to_cpu(upcase->start_cluster));
goto error;
}
- if (le64_to_cpu(upcase->size) == 0 ||
- le64_to_cpu(upcase->size) > 0xffff * sizeof(uint16_t) ||
- le64_to_cpu(upcase->size) % sizeof(uint16_t) != 0)
+ upcase_size = le64_to_cpu(upcase->size);
+ if (upcase_size == 0 ||
+ upcase_size > EXFAT_UPCASE_CHARS * sizeof(uint16_t) ||
+ upcase_size % sizeof(uint16_t) != 0)
{
exfat_error("bad upcase table size (%"PRIu64" bytes)",
- le64_to_cpu(upcase->size));
+ upcase_size);
goto error;
}
- ef->upcase = malloc(le64_to_cpu(upcase->size));
- if (ef->upcase == NULL)
+ upcase_comp = malloc(upcase_size);
+ if (upcase_comp == NULL)
{
exfat_error("failed to allocate upcase table (%"PRIu64" bytes)",
- le64_to_cpu(upcase->size));
+ upcase_size);
rc = -ENOMEM;
goto error;
}
- ef->upcase_chars = le64_to_cpu(upcase->size) / sizeof(le16_t);
- if (exfat_pread(ef->dev, ef->upcase, le64_to_cpu(upcase->size),
+ /* read compressed upcase table */
+ if (exfat_pread(ef->dev, upcase_comp, upcase_size,
exfat_c2o(ef, le32_to_cpu(upcase->start_cluster))) < 0)
{
+ free(upcase_comp);
exfat_error("failed to read upper case table "
"(%"PRIu64" bytes starting at cluster %#x)",
- le64_to_cpu(upcase->size),
+ upcase_size,
le32_to_cpu(upcase->start_cluster));
goto error;
}
+
+ /* decompress upcase table */
+ ef->upcase = calloc(EXFAT_UPCASE_CHARS, sizeof(uint16_t));
+ if (ef->upcase == NULL)
+ {
+ free(upcase_comp);
+ exfat_error("failed to allocate decompressed upcase table");
+ rc = -ENOMEM;
+ goto error;
+ }
+ decompress_upcase(ef->upcase, upcase_comp,
+ upcase_size / sizeof(uint16_t));
+ free(upcase_comp);
break;
case EXFAT_ENTRY_BITMAP:
same kernel can use different libc implementations.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
exFAT file system implementation library.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
exFAT file system implementation library.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
exFAT file system implementation library.
Free exFAT implementation.
- Copyright (C) 2010-2015 Andrew Nayenko
+ Copyright (C) 2010-2016 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
uint16_t c = le16_to_cpu(name[i]);
/* convert to upper case */
- if (c < ef->upcase_chars)
- c = le16_to_cpu(ef->upcase[c]);
+ c = ef->upcase[c];
hash = ((hash << 15) | (hash >> 1)) + (c & 0xff);
hash = ((hash << 15) | (hash >> 1)) + (c >> 8);