New: built-in FUSE support by using a 50% stripped down, internal
FUSE library which linked statically into libntfs-3g. Linux uses this one by default. New: the --with-fuse=external configure option makes ntfs-3g to be compiled with an external FUSE library. For non-Linux operating systems this is the default and the only option currently. New: rewritten, backwards compatible build system. New: README file is installed as documentation. New: the --enable-ldscript configure option uses ldscript instead of .so symlink New: the --disable-mtab configure option disables and ignores the usage of /etc/mtab New: added libntfs-3g.pc.in pkg-config and libntfs-3g.script.so.in ldconfig files Change: use 'make install-strip' instead of 'make strip' (Alon Bar-Lev, Miklos Szeredi, Szabolcs Szakacsits)master
parent
1731bcf5af
commit
67997a4d88
28
Makefile.am
28
Makefile.am
|
@ -1,17 +1,23 @@
|
|||
|
||||
SUBDIRS = include libntfs-3g src
|
||||
|
||||
EXTRA_DIST = AUTHORS CREDITS COPYING INSTALL NEWS README autogen.sh
|
||||
AUTOMAKE_OPTIONS = gnu
|
||||
|
||||
MAINTAINERCLEANFILES = configure Makefile.in aclocal.m4 compile depcomp \
|
||||
install-sh ltmain.sh missing config.guess config.sub config.h.in INSTALL
|
||||
EXTRA_DIST = AUTHORS CREDITS COPYING NEWS autogen.sh
|
||||
|
||||
libtool: $(LIBTOOL_DEPS)
|
||||
$(SHELL) ./config.status --recheck
|
||||
MAINTAINERCLEANFILES=\
|
||||
configure \
|
||||
Makefile.in \
|
||||
aclocal.m4 \
|
||||
compile \
|
||||
depcomp \
|
||||
install-sh \
|
||||
ltmain.sh \
|
||||
missing \
|
||||
config.guess \
|
||||
config.sub \
|
||||
config.h.in \
|
||||
config.h.in~ \
|
||||
INSTALL
|
||||
|
||||
strip:
|
||||
(cd src && $(MAKE) strip) || exit 1;
|
||||
SUBDIRS= include libfuse-lite libntfs-3g src
|
||||
|
||||
libs:
|
||||
(cd libntfs-3g && $(MAKE) libs) || exit 1;
|
||||
doc_DATA = README
|
||||
|
|
|
@ -18,5 +18,5 @@
|
|||
exit 1
|
||||
}
|
||||
|
||||
echo Running autoreconf --verbose --install
|
||||
autoreconf --force --verbose --install
|
||||
echo Running autoreconf --verbose --install --force
|
||||
autoreconf --verbose --install --force
|
||||
|
|
382
configure.ac
382
configure.ac
|
@ -3,8 +3,8 @@
|
|||
# compilation.
|
||||
#
|
||||
# Copyright (c) 2000-2006 Anton Altaparmakov
|
||||
# Copyright (c) 2003 Jan Kratochvil
|
||||
# Copyright (c) 2005-2007 Szabolcs Szakacsits
|
||||
# Copyright (C) 2007 Alon Bar-Lev
|
||||
#
|
||||
# This program/include file is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as published
|
||||
|
@ -20,112 +20,137 @@
|
|||
# along with this program (in the main directory of the NTFS-3G
|
||||
# distribution in the file COPYING); if not, write to the Free Software
|
||||
# Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
# Autoconf
|
||||
AC_PREREQ([2.59])
|
||||
AC_INIT([ntfs-3g],[1.1206-BETA],[ntfs-3g-devel@lists.sf.net])
|
||||
LIBNTFS_3G_VERSION=18
|
||||
AC_CONFIG_SRCDIR([src/ntfs-3g.c])
|
||||
|
||||
AC_INIT([ntfs-3g],[1.1120],[ntfs-3g-devel@lists.sf.net])
|
||||
LIBNTFS_3G_VERSION=16:0:0
|
||||
# Environment
|
||||
AC_CANONICAL_HOST
|
||||
AC_CANONICAL_TARGET
|
||||
|
||||
AC_CANONICAL_HOST([])
|
||||
AC_CANONICAL_TARGET([])
|
||||
AC_CONFIG_SRCDIR([config.h.in])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AM_INIT_AUTOMAKE
|
||||
# Automake
|
||||
AM_INIT_AUTOMAKE([${PACKAGE_NAME}], [${PACKAGE_VERSION}])
|
||||
AM_CONFIG_HEADER([config.h])
|
||||
AM_MAINTAINER_MODE
|
||||
AM_ENABLE_SHARED
|
||||
AM_ENABLE_STATIC
|
||||
|
||||
AC_PREFIX_DEFAULT(/usr/local)
|
||||
if test "x$prefix" = "xNONE"; then
|
||||
prefix=$ac_default_prefix
|
||||
ac_configure_args="$ac_configure_args --prefix $prefix"
|
||||
fi
|
||||
|
||||
# Executables should be installed to the root filesystem, otherwise
|
||||
# automounting NTFS volumes can fail during boot if the driver binaries
|
||||
# (ntfs-3g, fuse) are on an unmounted partition.
|
||||
if test "x$exec_prefix" = "xNONE"; then
|
||||
exec_prefix=/
|
||||
ac_configure_args="$ac_configure_args --exec-prefix $exec_prefix"
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE([Setting exec_prefix to $exec_prefix])
|
||||
|
||||
# Command-line options.
|
||||
AC_ARG_ENABLE(debug,
|
||||
AS_HELP_STRING(--enable-debug,enable additional debugging code and
|
||||
output), ,
|
||||
enable_debug=no
|
||||
# Options
|
||||
AC_ARG_ENABLE(
|
||||
[debug],
|
||||
[AC_HELP_STRING([--enable-debug], [enable debugging code and output])],
|
||||
,
|
||||
[enable_debug="no"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(really-static,
|
||||
AS_HELP_STRING(--enable-really-static,create static binaries
|
||||
for the utilities), ,
|
||||
enable_really_static=no
|
||||
)
|
||||
AM_CONDITIONAL(REALLYSTATIC, test "$enable_really_static" = yes)
|
||||
|
||||
AC_ARG_ENABLE(warnings,
|
||||
AS_HELP_STRING(--enable-warnings,enable additional compiler warnings), ,
|
||||
enable_warnings=no
|
||||
AC_ARG_ENABLE(
|
||||
[warnings],
|
||||
[AC_HELP_STRING([--enable-warnings], [enable lots of compiler warnings])],
|
||||
,
|
||||
[enable_warnings="no"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(ldconfig,
|
||||
AS_HELP_STRING(--disable-ldconfig,do not update dynamic linker cache
|
||||
using ldconfig), ,
|
||||
enable_ldconfig=yes
|
||||
AC_ARG_ENABLE(
|
||||
[pedantic],
|
||||
[AC_HELP_STRING([--enable-pedantic], [enable compile pedantic mode])],
|
||||
,
|
||||
[enable_pedantic="no"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(library,
|
||||
AS_HELP_STRING(--disable-library,do not install libntfs-3g but link
|
||||
it into ntfs-3g), ,
|
||||
enable_library=yes
|
||||
AC_ARG_ENABLE(
|
||||
[really-static],
|
||||
[AC_HELP_STRING([--enable-really-static], [create fully static binaries])],
|
||||
,
|
||||
[enable_really_static="no"]
|
||||
)
|
||||
if test "$enable_library" != yes; then
|
||||
enable_shared=no
|
||||
enable_ldconfig=no
|
||||
fi
|
||||
AM_CONDITIONAL([REALLYSTATIC], [test "${enable_really_static}" = "yes"])
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[library],
|
||||
[AC_HELP_STRING([--disable-library], [do not install libntfs-3g but link it into ntfs-3g])],
|
||||
,
|
||||
[enable_library="yes"]
|
||||
)
|
||||
test "${enable_really_static}" = "yes" && enable_library="no"
|
||||
AM_CONDITIONAL(INSTALL_LIBRARY, test "$enable_library" = yes)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[ldconfig],
|
||||
[AC_HELP_STRING([--disable-ldconfig], [do not update dynamic linker cache using ldconfig])],
|
||||
,
|
||||
[enable_ldconfig="yes"]
|
||||
)
|
||||
test "${enable_library}" = "no" && enable_ldconfig="no"
|
||||
# --disable-library will disable to run ldconfig since no point to do so.
|
||||
AM_CONDITIONAL(RUN_LDCONFIG, test "$enable_ldconfig" = yes)
|
||||
|
||||
# Use GNU extensions if available.
|
||||
AC_GNU_SOURCE
|
||||
AC_ARG_ENABLE(
|
||||
[ldscript],
|
||||
[AC_HELP_STRING([--enable-ldscript], [use ldscript instead of .so symlink])],
|
||||
,
|
||||
[enable_ldscript="no"]
|
||||
)
|
||||
|
||||
# Checks for programs.
|
||||
AC_ARG_ENABLE(
|
||||
[mtab],
|
||||
[AC_HELP_STRING([--disable-mtab], [disable and ignore usage of /etc/mtab])],
|
||||
,
|
||||
[enable_mtab="yes"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[device-default-io-ops],
|
||||
[AC_HELP_STRING([--disable-device-default-io-ops], [Install default IO ops])],
|
||||
,
|
||||
[enable_device_default_io_ops="yes"]
|
||||
)
|
||||
|
||||
# Programs
|
||||
AC_GNU_SOURCE
|
||||
AC_PROG_CC
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_PROG_INSTALL
|
||||
AC_PATH_PROG(RM, rm, rm)
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PROG_LN_S
|
||||
AM_PROG_CC_C_O
|
||||
# No need to check for ldconfig if --disable-ldconfig was given
|
||||
if test "$enable_ldconfig" = yes; then
|
||||
AC_PATH_PROG(LDCONFIG, ldconfig, true, [/sbin /usr/sbin $PATH])
|
||||
fi
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PATH_PROG([MV], [mv])
|
||||
AC_PATH_PROG([RM], [rm])
|
||||
AC_PATH_PROG([SED], [sed])
|
||||
|
||||
# Libraries often install their metadata .pc files in directories not searched
|
||||
# by pkg-config. Let's workaround this.
|
||||
export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/lib/pkgconfig:/usr/lib/pkgconfig:/opt/gnome/lib/pkgconfig:/usr/share/pkgconfig:/usr/local/lib/pkgconfig:$prefix/lib/pkgconfig:/opt/gnome/share/pkgconfig:/usr/local/share/pkgconfig
|
||||
# Environment
|
||||
AC_MSG_CHECKING([Windows OS])
|
||||
case "${target}" in
|
||||
*-mingw32*|*-winnt*|*-cygwin*)
|
||||
AC_MSG_RESULT([yes])
|
||||
WINDOWS="yes"
|
||||
AC_DEFINE(
|
||||
[WINDOWS],
|
||||
[1],
|
||||
[Define to 1 if this is a Windows OS]
|
||||
)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT([no])
|
||||
WINDOWS="no"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Enable large file support.
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
case "$target_os" in
|
||||
linux*|darwin*|netbsd*)
|
||||
if test -z "$PKG_CONFIG"; then
|
||||
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
|
||||
fi
|
||||
if test "x$PKG_CONFIG" = "xno" ; then
|
||||
AC_MSG_ERROR([pkg-config wasn't found! Please install from your vendor, or see http://pkg-config.freedesktop.org/wiki/])
|
||||
fi
|
||||
PKG_CHECK_MODULES(FUSE_MODULE, fuse >= 2.6.0,,
|
||||
[
|
||||
AC_MSG_ERROR([FUSE >= 2.6.0 was not found. Either older FUSE is still present, or FUSE is not fully installed (e.g. fuse, libfuse, libfuse2, libfuse-dev, etc packages). Source code: http://fuse.sf.net])
|
||||
]);;
|
||||
AC_MSG_CHECKING([fuse compatibility])
|
||||
case "${target_os}" in
|
||||
linux*)
|
||||
AC_ARG_WITH(
|
||||
[fuse],
|
||||
[AC_HELP_STRING([--with-fuse=<internal|external>], [Select FUSE library: internal or external @<:@default=internal@:>@])],
|
||||
,
|
||||
[with_fuse="internal"]
|
||||
)
|
||||
;;
|
||||
darwin*|netbsd*)
|
||||
with_fuse="external"
|
||||
;;
|
||||
freebsd*)
|
||||
AC_MSG_ERROR([Please see FreeBSD support at http://www.freshports.org/sysutils/fusefs-ntfs])
|
||||
;;
|
||||
|
@ -133,51 +158,56 @@ freebsd*)
|
|||
AC_MSG_ERROR([ntfs-3g can be built only under Linux, FreeBSD, Mac OS X, and NetBSD.])
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([${with_fuse}])
|
||||
|
||||
# Static linking failed because FUSE 2.6.[01] forgot to include -lrt.
|
||||
# However FreeBSD doesn't have one. So, here we go with the code from FUSE.
|
||||
libfuse_libs=
|
||||
LIBS=
|
||||
AC_SEARCH_LIBS(clock_gettime, [rt])
|
||||
libfuse_libs="$libfuse_libs $LIBS"
|
||||
LIBS=
|
||||
AC_SUBST(libfuse_libs)
|
||||
|
||||
FUSE_LIB_PATH=`$PKG_CONFIG --libs-only-L fuse | sed -e 's,/[/]*,/,g' -e 's,[ ]*$,,'`
|
||||
|
||||
# add --with-extra-includes and --with-extra-libs switch to ./configure
|
||||
all_libraries="$all_libraries $USER_LDFLAGS"
|
||||
all_includes="$all_includes $USER_INCLUDES"
|
||||
AC_SUBST(all_includes)
|
||||
AC_SUBST(all_libraries)
|
||||
|
||||
# Add our compiler switches not discarding 'CFLAGS' as they may have been
|
||||
# passed to us by rpmbuild(8).
|
||||
# We add -Wall to enable some compiler warnings.
|
||||
CFLAGS="$CFLAGS -Wall"
|
||||
|
||||
# Add lots of extra warnings if --enable-warnings was specified.
|
||||
if test "$enable_warnings" = "yes"; then
|
||||
CFLAGS="$CFLAGS -W -Wall -Waggregate-return -Wbad-function-cast -Wcast-align -Wcast-qual -Wdisabled-optimization -Wdiv-by-zero -Wfloat-equal -Winline -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wmultichar -Wnested-externs -Wpointer-arith -Wredundant-decls -Wshadow -Wsign-compare -Wstrict-prototypes -Wundef -Wwrite-strings"
|
||||
if test "${enable_ldscript}" = "yes"; then
|
||||
AC_MSG_CHECKING([Output format])
|
||||
OUTPUT_FORMAT="$(${CC} ${CFLAGS} ${LDFLAGS} -Wl,--verbose 2>&1 | ${SED} -n 's/^OUTPUT_FORMAT("\([[^"]]*\)",.*/\1/p')"
|
||||
if test -z "${OUTPUT_FORMAT}"; then
|
||||
AC_MSG_RESULT([None])
|
||||
else
|
||||
AC_MSG_RESULT([${OUTPUT_FORMAT}])
|
||||
OUTPUT_FORMAT="OUTPUT_FORMAT ( ${OUTPUT_FORMAT} )"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Add debugging switches if --enable-debug was specified.
|
||||
if test "$enable_debug" = "yes"; then
|
||||
CFLAGS="$CFLAGS -ggdb3 -DDEBUG"
|
||||
# Libraries
|
||||
if test "${with_fuse}" = "internal"; then
|
||||
AC_CHECK_LIB(
|
||||
[pthread],
|
||||
[pthread_create],
|
||||
[LIBFUSE_LITE_LIBS="${LIBFUSE_LITE_LIBS} -lpthread"],
|
||||
[AC_MSG_ERROR([Cannot find pthread library])]
|
||||
)
|
||||
AC_CHECK_LIB(
|
||||
[rt],
|
||||
[clock_gettime],
|
||||
[LIBFUSE_LITE_LIBS="${LIBFUSE_LITE_LIBS} -lrt"],
|
||||
[AC_MSG_ERROR([Cannot find rt library])]
|
||||
)
|
||||
# required so that we re-compile anything
|
||||
AC_DEFINE(
|
||||
[FUSE_INTERNAL],
|
||||
[1],
|
||||
[Define to 1 if using internal fuse]
|
||||
)
|
||||
else
|
||||
PKG_PROG_PKG_CONFIG
|
||||
test -z "${PKG_CONFIG}" && AC_MSG_ERROR([pkg-config wasn't found! Please install from your vendor, or see http://pkg-config.freedesktop.org/wiki/])
|
||||
# Libraries often install their metadata .pc files in directories
|
||||
# not searched by pkg-config. Let's workaround this.
|
||||
export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/lib/pkgconfig:/usr/lib/pkgconfig:/opt/gnome/lib/pkgconfig:/usr/share/pkgconfig:/usr/local/lib/pkgconfig:$prefix/lib/pkgconfig:/opt/gnome/share/pkgconfig:/usr/local/share/pkgconfig
|
||||
PKG_CHECK_MODULES(
|
||||
[FUSE_MODULE],
|
||||
[fuse >= 2.6.0],
|
||||
,
|
||||
[
|
||||
AC_MSG_ERROR([FUSE >= 2.6.0 was not found. Either older FUSE is still present, or FUSE is not fully installed (e.g. fuse, libfuse, libfuse2, libfuse-dev, etc packages). Source code: http://fuse.sf.net])
|
||||
]
|
||||
)
|
||||
FUSE_LIB_PATH=`$PKG_CONFIG --libs-only-L fuse | sed -e 's,/[/]*,/,g' -e 's,[ ]*$,,'`
|
||||
fi
|
||||
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CPPFLAGS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
AC_SUBST(LIBS)
|
||||
|
||||
AC_SUBST(LIBNTFS_3G_VERSION)
|
||||
AC_SUBST(LIBNTFS_3G_CFLAGS)
|
||||
|
||||
AC_SUBST(AUTODIRS)
|
||||
|
||||
# Checks for libraries.
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \
|
||||
|
@ -190,17 +220,26 @@ AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \
|
|||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_HEADER_STDBOOL
|
||||
AC_C_BIGENDIAN(,
|
||||
[AC_DEFINE([WORDS_LITTLEENDIAN], 1,
|
||||
[Define to 1 if your processor stores words with the least significant
|
||||
byte first (like Intel and VAX, unlike Motorola and SPARC).])]
|
||||
,)
|
||||
AC_C_BIGENDIAN(
|
||||
,
|
||||
[
|
||||
AC_DEFINE(
|
||||
[WORDS_LITTLEENDIAN],
|
||||
[1],
|
||||
[Define to 1 if your processor stores words with the least significant
|
||||
byte first (like Intel and VAX, unlike Motorola and SPARC).]
|
||||
)
|
||||
]
|
||||
,
|
||||
)
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_STRUCT_ST_BLOCKS
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
AC_CHECK_MEMBERS([struct stat.st_atim])
|
||||
AC_CHECK_MEMBERS([struct stat.st_atimespec])
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_GETMNTENT
|
||||
|
@ -210,23 +249,97 @@ AC_FUNC_STAT
|
|||
AC_FUNC_STRFTIME
|
||||
AC_FUNC_UTIME_NULL
|
||||
AC_FUNC_VPRINTF
|
||||
AC_CHECK_FUNCS([atexit basename dup2 fdatasync getopt_long hasmntopt mbsinit \
|
||||
AC_CHECK_FUNCS([ \
|
||||
atexit basename dup2 fdatasync getopt_long hasmntopt mbsinit \
|
||||
memmove memset realpath regcomp setlocale setxattr strcasecmp strchr \
|
||||
strdup strerror strnlen strtol strtoul sysconf utime])
|
||||
strdup strerror strnlen strtol strtoul sysconf utime fork \
|
||||
])
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
# Makefiles to be created by configure.
|
||||
# We add -Wall to enable some compiler warnings.
|
||||
CFLAGS="${CFLAGS} -Wall -fno-strict-aliasing"
|
||||
|
||||
if test "${enable_pedantic}" = "yes"; then
|
||||
enable_warnings="yes"
|
||||
CFLAGS="${CFLAGS} -pedantic"
|
||||
fi
|
||||
|
||||
if test "${enable_warnings}" = "yes"; then
|
||||
CFLAGS="${CFLAGS} -W -Wall -Waggregate-return -Wbad-function-cast -Wcast-align -Wcast-qual -Wdisabled-optimization -Wdiv-by-zero -Wfloat-equal -Winline -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wmultichar -Wnested-externs -Wpointer-arith -Wredundant-decls -Wshadow -Wsign-compare -Wstrict-prototypes -Wundef -Wwrite-strings"
|
||||
fi
|
||||
|
||||
if test "${enable_debug}" = "yes"; then
|
||||
CFLAGS="${CFLAGS} -ggdb3 -DDEBUG"
|
||||
AC_DEFINE(
|
||||
[ENABLE_DEBUG],
|
||||
[1],
|
||||
[Define to 1 if debug should be enabled]
|
||||
)
|
||||
fi
|
||||
|
||||
test "${enable_device_default_io_ops}" = "no" && AC_DEFINE(
|
||||
[NO_NTFS_DEVICE_DEFAULT_IO_OPS],
|
||||
[1],
|
||||
[Don't use default IO ops]
|
||||
)
|
||||
|
||||
if test "${enable_mtab}" = "no"; then
|
||||
AC_DEFINE([IGNORE_MTAB], [1], [Don't update /etc/mtab])
|
||||
fi
|
||||
|
||||
# Settings
|
||||
pkgconfigdir="\$(libdir)/pkgconfig"
|
||||
ntfs3gincludedir="\$(includedir)/ntfs-3g"
|
||||
# Executables should be installed to the root filesystem, otherwise
|
||||
# automounting NTFS volumes can fail during boot if the driver binaries
|
||||
# and their dependencies are on an unmounted partition. Use --exec-prefix
|
||||
# to override this.
|
||||
if test "x${exec_prefix}" = "xNONE"; then
|
||||
rootbindir="/bin"
|
||||
rootsbindir="/sbin"
|
||||
rootlibdir="/lib${libdir##*/lib}"
|
||||
else
|
||||
rootbindir="\$(bindir)"
|
||||
rootsbindir="\$(sbindir)"
|
||||
rootlibdir="\$(libdir)"
|
||||
fi
|
||||
AC_SUBST([pkgconfigdir])
|
||||
AC_SUBST([ntfs3gincludedir])
|
||||
AC_SUBST([rootbindir])
|
||||
AC_SUBST([rootsbindir])
|
||||
AC_SUBST([rootlibdir])
|
||||
AC_SUBST([LIBNTFS_3G_VERSION])
|
||||
AC_SUBST([LIBFUSE_LITE_LIBS])
|
||||
AC_SUBST([OUTPUT_FORMAT])
|
||||
AM_CONDITIONAL([FUSE_INTERNAL], [test "${with_fuse}" = "internal"])
|
||||
AM_CONDITIONAL([GENERATE_LDSCRIPT], [test "${enable_ldscript}" = "yes"])
|
||||
AM_CONDITIONAL([WINDOWS], [test "${WINDOWS}" = "yes"])
|
||||
AM_CONDITIONAL([NTFS_DEVICE_DEFAULT_IO_OPS], [test "${enable_device_default_io_ops}" = "yes"])
|
||||
|
||||
# workaround for <autoconf-2.60
|
||||
if test -z "${docdir}"; then
|
||||
docdir="\$(datarootdir)/doc/\$(PACKAGE_NAME)"
|
||||
AC_SUBST([docdir])
|
||||
fi
|
||||
|
||||
# generate files
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
include/Makefile
|
||||
include/fuse-lite/Makefile
|
||||
include/ntfs-3g/Makefile
|
||||
libfuse-lite/Makefile
|
||||
libntfs-3g/Makefile
|
||||
libntfs-3g/libntfs-3g.pc
|
||||
libntfs-3g/libntfs-3g.script.so
|
||||
src/Makefile
|
||||
src/ntfs-3g.8
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
if test "x$FUSE_LIB_PATH" != "x-L/lib" -a "x$FUSE_LIB_PATH" != "x-L/lib64"; then
|
||||
cat <<EOF
|
||||
if test "${with_fuse}" = "external"; then
|
||||
if ! echo "x$FUSE_LIB_PATH" | grep -- "x-L/lib" > /dev/null; then
|
||||
cat <<EOF
|
||||
****************************************************************************
|
||||
* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING *
|
||||
* The FUSE user space binaries were NOT installed with root directory *
|
||||
|
@ -237,8 +350,9 @@ cat <<EOF
|
|||
* make && sudo make install *
|
||||
* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING *
|
||||
****************************************************************************
|
||||
You can type now 'make' to build ntfs-3g.
|
||||
EOF
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "You can type now 'make' to build ntfs-3g."
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
SUBDIRS = ntfs-3g
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
SUBDIRS = ntfs-3g fuse-lite
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
noinst_HEADERS = \
|
||||
fuse.h \
|
||||
fuse_common.h \
|
||||
fuse_lowlevel.h \
|
||||
fuse_lowlevel_compat.h \
|
||||
fuse_opt.h \
|
||||
fuse_kernel.h
|
|
@ -0,0 +1,657 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#ifndef _FUSE_H_
|
||||
#define _FUSE_H_
|
||||
|
||||
/** @file
|
||||
*
|
||||
* This file defines the library interface of FUSE
|
||||
*/
|
||||
|
||||
#include "fuse_common.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <utime.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------- *
|
||||
* Basic FUSE API *
|
||||
* ----------------------------------------------------------- */
|
||||
|
||||
/** Handle for a FUSE filesystem */
|
||||
struct fuse;
|
||||
|
||||
/** Structure containing a raw command */
|
||||
struct fuse_cmd;
|
||||
|
||||
/** Function to add an entry in a readdir() operation
|
||||
*
|
||||
* @param buf the buffer passed to the readdir() operation
|
||||
* @param name the file name of the directory entry
|
||||
* @param stat file attributes, can be NULL
|
||||
* @param off offset of the next entry or zero
|
||||
* @return 1 if buffer is full, zero otherwise
|
||||
*/
|
||||
typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
|
||||
const struct stat *stbuf, off_t off);
|
||||
|
||||
/**
|
||||
* The file system operations:
|
||||
*
|
||||
* Most of these should work very similarly to the well known UNIX
|
||||
* file system operations. A major exception is that instead of
|
||||
* returning an error in 'errno', the operation should return the
|
||||
* negated error value (-errno) directly.
|
||||
*
|
||||
* All methods are optional, but some are essential for a useful
|
||||
* filesystem (e.g. getattr). Open, flush, release, fsync, opendir,
|
||||
* releasedir, fsyncdir, access, create, ftruncate, fgetattr, lock,
|
||||
* init and destroy are special purpose methods, without which a full
|
||||
* featured filesystem can still be implemented.
|
||||
*/
|
||||
struct fuse_operations {
|
||||
/** Get file attributes.
|
||||
*
|
||||
* Similar to stat(). The 'st_dev' and 'st_blksize' fields are
|
||||
* ignored. The 'st_ino' field is ignored except if the 'use_ino'
|
||||
* mount option is given.
|
||||
*/
|
||||
int (*getattr) (const char *, struct stat *);
|
||||
|
||||
/** Read the target of a symbolic link
|
||||
*
|
||||
* The buffer should be filled with a null terminated string. The
|
||||
* buffer size argument includes the space for the terminating
|
||||
* null character. If the linkname is too long to fit in the
|
||||
* buffer, it should be truncated. The return value should be 0
|
||||
* for success.
|
||||
*/
|
||||
int (*readlink) (const char *, char *, size_t);
|
||||
|
||||
/** Create a file node
|
||||
*
|
||||
* This is called for creation of all non-directory, non-symlink
|
||||
* nodes. If the filesystem defines a create() method, then for
|
||||
* regular files that will be called instead.
|
||||
*/
|
||||
int (*mknod) (const char *, mode_t, dev_t);
|
||||
|
||||
/** Create a directory */
|
||||
int (*mkdir) (const char *, mode_t);
|
||||
|
||||
/** Remove a file */
|
||||
int (*unlink) (const char *);
|
||||
|
||||
/** Remove a directory */
|
||||
int (*rmdir) (const char *);
|
||||
|
||||
/** Create a symbolic link */
|
||||
int (*symlink) (const char *, const char *);
|
||||
|
||||
/** Rename a file */
|
||||
int (*rename) (const char *, const char *);
|
||||
|
||||
/** Create a hard link to a file */
|
||||
int (*link) (const char *, const char *);
|
||||
|
||||
/** Change the permission bits of a file */
|
||||
int (*chmod) (const char *, mode_t);
|
||||
|
||||
/** Change the owner and group of a file */
|
||||
int (*chown) (const char *, uid_t, gid_t);
|
||||
|
||||
/** Change the size of a file */
|
||||
int (*truncate) (const char *, off_t);
|
||||
|
||||
/** Change the access and/or modification times of a file
|
||||
*
|
||||
* Deprecated, use utimens() instead.
|
||||
*/
|
||||
int (*utime) (const char *, struct utimbuf *);
|
||||
|
||||
/** File open operation
|
||||
*
|
||||
* No creation, or truncation flags (O_CREAT, O_EXCL, O_TRUNC)
|
||||
* will be passed to open(). Open should check if the operation
|
||||
* is permitted for the given flags. Optionally open may also
|
||||
* return an arbitrary filehandle in the fuse_file_info structure,
|
||||
* which will be passed to all file operations.
|
||||
*
|
||||
* Changed in version 2.2
|
||||
*/
|
||||
int (*open) (const char *, struct fuse_file_info *);
|
||||
|
||||
/** Read data from an open file
|
||||
*
|
||||
* Read should return exactly the number of bytes requested except
|
||||
* on EOF or error, otherwise the rest of the data will be
|
||||
* substituted with zeroes. An exception to this is when the
|
||||
* 'direct_io' mount option is specified, in which case the return
|
||||
* value of the read system call will reflect the return value of
|
||||
* this operation.
|
||||
*
|
||||
* Changed in version 2.2
|
||||
*/
|
||||
int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
|
||||
|
||||
/** Write data to an open file
|
||||
*
|
||||
* Write should return exactly the number of bytes requested
|
||||
* except on error. An exception to this is when the 'direct_io'
|
||||
* mount option is specified (see read operation).
|
||||
*
|
||||
* Changed in version 2.2
|
||||
*/
|
||||
int (*write) (const char *, const char *, size_t, off_t,
|
||||
struct fuse_file_info *);
|
||||
|
||||
/** Get file system statistics
|
||||
*
|
||||
* The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
|
||||
*
|
||||
* Replaced 'struct statfs' parameter with 'struct statvfs' in
|
||||
* version 2.5
|
||||
*/
|
||||
int (*statfs) (const char *, struct statvfs *);
|
||||
|
||||
/** Possibly flush cached data
|
||||
*
|
||||
* BIG NOTE: This is not equivalent to fsync(). It's not a
|
||||
* request to sync dirty data.
|
||||
*
|
||||
* Flush is called on each close() of a file descriptor. So if a
|
||||
* filesystem wants to return write errors in close() and the file
|
||||
* has cached dirty data, this is a good place to write back data
|
||||
* and return any errors. Since many applications ignore close()
|
||||
* errors this is not always useful.
|
||||
*
|
||||
* NOTE: The flush() method may be called more than once for each
|
||||
* open(). This happens if more than one file descriptor refers
|
||||
* to an opened file due to dup(), dup2() or fork() calls. It is
|
||||
* not possible to determine if a flush is final, so each flush
|
||||
* should be treated equally. Multiple write-flush sequences are
|
||||
* relatively rare, so this shouldn't be a problem.
|
||||
*
|
||||
* Filesystems shouldn't assume that flush will always be called
|
||||
* after some writes, or that if will be called at all.
|
||||
*
|
||||
* Changed in version 2.2
|
||||
*/
|
||||
int (*flush) (const char *, struct fuse_file_info *);
|
||||
|
||||
/** Release an open file
|
||||
*
|
||||
* Release is called when there are no more references to an open
|
||||
* file: all file descriptors are closed and all memory mappings
|
||||
* are unmapped.
|
||||
*
|
||||
* For every open() call there will be exactly one release() call
|
||||
* with the same flags and file descriptor. It is possible to
|
||||
* have a file opened more than once, in which case only the last
|
||||
* release will mean, that no more reads/writes will happen on the
|
||||
* file. The return value of release is ignored.
|
||||
*
|
||||
* Changed in version 2.2
|
||||
*/
|
||||
int (*release) (const char *, struct fuse_file_info *);
|
||||
|
||||
/** Synchronize file contents
|
||||
*
|
||||
* If the datasync parameter is non-zero, then only the user data
|
||||
* should be flushed, not the meta data.
|
||||
*
|
||||
* Changed in version 2.2
|
||||
*/
|
||||
int (*fsync) (const char *, int, struct fuse_file_info *);
|
||||
|
||||
/** Set extended attributes */
|
||||
int (*setxattr) (const char *, const char *, const char *, size_t, int);
|
||||
|
||||
/** Get extended attributes */
|
||||
int (*getxattr) (const char *, const char *, char *, size_t);
|
||||
|
||||
/** List extended attributes */
|
||||
int (*listxattr) (const char *, char *, size_t);
|
||||
|
||||
/** Remove extended attributes */
|
||||
int (*removexattr) (const char *, const char *);
|
||||
|
||||
/** Open directory
|
||||
*
|
||||
* This method should check if the open operation is permitted for
|
||||
* this directory
|
||||
*
|
||||
* Introduced in version 2.3
|
||||
*/
|
||||
int (*opendir) (const char *, struct fuse_file_info *);
|
||||
|
||||
/** Read directory
|
||||
*
|
||||
* The filesystem may choose between two modes of operation:
|
||||
*
|
||||
* 1) The readdir implementation ignores the offset parameter, and
|
||||
* passes zero to the filler function's offset. The filler
|
||||
* function will not return '1' (unless an error happens), so the
|
||||
* whole directory is read in a single readdir operation.
|
||||
*
|
||||
* 2) The readdir implementation keeps track of the offsets of the
|
||||
* directory entries. It uses the offset parameter and always
|
||||
* passes non-zero offset to the filler function. When the buffer
|
||||
* is full (or an error happens) the filler function will return
|
||||
* '1'.
|
||||
*
|
||||
* Introduced in version 2.3
|
||||
*/
|
||||
int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
|
||||
struct fuse_file_info *);
|
||||
|
||||
/** Release directory
|
||||
*
|
||||
* Introduced in version 2.3
|
||||
*/
|
||||
int (*releasedir) (const char *, struct fuse_file_info *);
|
||||
|
||||
/** Synchronize directory contents
|
||||
*
|
||||
* If the datasync parameter is non-zero, then only the user data
|
||||
* should be flushed, not the meta data
|
||||
*
|
||||
* Introduced in version 2.3
|
||||
*/
|
||||
int (*fsyncdir) (const char *, int, struct fuse_file_info *);
|
||||
|
||||
/**
|
||||
* Initialize filesystem
|
||||
*
|
||||
* The return value will passed in the private_data field of
|
||||
* fuse_context to all file operations and as a parameter to the
|
||||
* destroy() method.
|
||||
*
|
||||
* Introduced in version 2.3
|
||||
* Changed in version 2.6
|
||||
*/
|
||||
void *(*init) (struct fuse_conn_info *conn);
|
||||
|
||||
/**
|
||||
* Clean up filesystem
|
||||
*
|
||||
* Called on filesystem exit.
|
||||
*
|
||||
* Introduced in version 2.3
|
||||
*/
|
||||
void (*destroy) (void *);
|
||||
|
||||
/**
|
||||
* Check file access permissions
|
||||
*
|
||||
* This will be called for the access() system call. If the
|
||||
* 'default_permissions' mount option is given, this method is not
|
||||
* called.
|
||||
*
|
||||
* This method is not called under Linux kernel versions 2.4.x
|
||||
*
|
||||
* Introduced in version 2.5
|
||||
*/
|
||||
int (*access) (const char *, int);
|
||||
|
||||
/**
|
||||
* Create and open a file
|
||||
*
|
||||
* If the file does not exist, first create it with the specified
|
||||
* mode, and then open it.
|
||||
*
|
||||
* If this method is not implemented or under Linux kernel
|
||||
* versions earlier than 2.6.15, the mknod() and open() methods
|
||||
* will be called instead.
|
||||
*
|
||||
* Introduced in version 2.5
|
||||
*/
|
||||
int (*create) (const char *, mode_t, struct fuse_file_info *);
|
||||
|
||||
/**
|
||||
* Change the size of an open file
|
||||
*
|
||||
* This method is called instead of the truncate() method if the
|
||||
* truncation was invoked from an ftruncate() system call.
|
||||
*
|
||||
* If this method is not implemented or under Linux kernel
|
||||
* versions earlier than 2.6.15, the truncate() method will be
|
||||
* called instead.
|
||||
*
|
||||
* Introduced in version 2.5
|
||||
*/
|
||||
int (*ftruncate) (const char *, off_t, struct fuse_file_info *);
|
||||
|
||||
/**
|
||||
* Get attributes from an open file
|
||||
*
|
||||
* This method is called instead of the getattr() method if the
|
||||
* file information is available.
|
||||
*
|
||||
* Currently this is only called after the create() method if that
|
||||
* is implemented (see above). Later it may be called for
|
||||
* invocations of fstat() too.
|
||||
*
|
||||
* Introduced in version 2.5
|
||||
*/
|
||||
int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
|
||||
|
||||
/**
|
||||
* Perform POSIX file locking operation
|
||||
*
|
||||
* The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
|
||||
*
|
||||
* For the meaning of fields in 'struct flock' see the man page
|
||||
* for fcntl(2). The l_whence field will always be set to
|
||||
* SEEK_SET.
|
||||
*
|
||||
* For checking lock ownership, the 'fuse_file_info->owner'
|
||||
* argument must be used.
|
||||
*
|
||||
* For F_GETLK operation, the library will first check currently
|
||||
* held locks, and if a conflicting lock is found it will return
|
||||
* information without calling this method. This ensures, that
|
||||
* for local locks the l_pid field is correctly filled in. The
|
||||
* results may not be accurate in case of race conditions and in
|
||||
* the presence of hard links, but it's unlikly that an
|
||||
* application would rely on accurate GETLK results in these
|
||||
* cases. If a conflicting lock is not found, this method will be
|
||||
* called, and the filesystem may fill out l_pid by a meaningful
|
||||
* value, or it may leave this field zero.
|
||||
*
|
||||
* For F_SETLK and F_SETLKW the l_pid field will be set to the pid
|
||||
* of the process performing the locking operation.
|
||||
*
|
||||
* Note: if this method is not implemented, the kernel will still
|
||||
* allow file locking to work locally. Hence it is only
|
||||
* interesting for network filesystems and similar.
|
||||
*
|
||||
* Introduced in version 2.6
|
||||
*/
|
||||
int (*lock) (const char *, struct fuse_file_info *, int cmd,
|
||||
struct flock *);
|
||||
|
||||
/**
|
||||
* Change the access and modification times of a file with
|
||||
* nanosecond resolution
|
||||
*
|
||||
* Introduced in version 2.6
|
||||
*/
|
||||
int (*utimens) (const char *, const struct timespec tv[2]);
|
||||
|
||||
/**
|
||||
* Map block index within file to block index within device
|
||||
*
|
||||
* Note: This makes sense only for block device backed filesystems
|
||||
* mounted with the 'blkdev' option
|
||||
*
|
||||
* Introduced in version 2.6
|
||||
*/
|
||||
int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
|
||||
};
|
||||
|
||||
/** Extra context that may be needed by some filesystems
|
||||
*
|
||||
* The uid, gid and pid fields are not filled in case of a writepage
|
||||
* operation.
|
||||
*/
|
||||
struct fuse_context {
|
||||
/** Pointer to the fuse object */
|
||||
struct fuse *fuse;
|
||||
|
||||
/** User ID of the calling process */
|
||||
uid_t uid;
|
||||
|
||||
/** Group ID of the calling process */
|
||||
gid_t gid;
|
||||
|
||||
/** Thread ID of the calling process */
|
||||
pid_t pid;
|
||||
|
||||
/** Private filesystem data */
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Main function of FUSE.
|
||||
*
|
||||
* This is for the lazy. This is all that has to be called from the
|
||||
* main() function.
|
||||
*
|
||||
* This function does the following:
|
||||
* - parses command line options (-d -s and -h)
|
||||
* - passes relevant mount options to the fuse_mount()
|
||||
* - installs signal handlers for INT, HUP, TERM and PIPE
|
||||
* - registers an exit handler to unmount the filesystem on program exit
|
||||
* - creates a fuse handle
|
||||
* - registers the operations
|
||||
* - calls either the single-threaded or the multi-threaded event loop
|
||||
*
|
||||
* Note: this is currently implemented as a macro.
|
||||
*
|
||||
* @param argc the argument counter passed to the main() function
|
||||
* @param argv the argument vector passed to the main() function
|
||||
* @param op the file system operation
|
||||
* @param user_data user data supplied in the context during the init() method
|
||||
* @return 0 on success, nonzero on failure
|
||||
*/
|
||||
/*
|
||||
int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
|
||||
void *user_data);
|
||||
*/
|
||||
#define fuse_main(argc, argv, op, user_data) \
|
||||
fuse_main_real(argc, argv, op, sizeof(*(op)), user_data)
|
||||
|
||||
/* ----------------------------------------------------------- *
|
||||
* More detailed API *
|
||||
* ----------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Create a new FUSE filesystem.
|
||||
*
|
||||
* @param ch the communication channel
|
||||
* @param args argument vector
|
||||
* @param op the filesystem operations
|
||||
* @param op_size the size of the fuse_operations structure
|
||||
* @param user_data user data supplied in the context during the init() method
|
||||
* @return the created FUSE handle
|
||||
*/
|
||||
struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
|
||||
const struct fuse_operations *op, size_t op_size,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Destroy the FUSE handle.
|
||||
*
|
||||
* The communication channel attached to the handle is also destroyed.
|
||||
*
|
||||
* NOTE: This function does not unmount the filesystem. If this is
|
||||
* needed, call fuse_unmount() before calling this function.
|
||||
*
|
||||
* @param f the FUSE handle
|
||||
*/
|
||||
void fuse_destroy(struct fuse *f);
|
||||
|
||||
/**
|
||||
* FUSE event loop.
|
||||
*
|
||||
* Requests from the kernel are processed, and the appropriate
|
||||
* operations are called.
|
||||
*
|
||||
* @param f the FUSE handle
|
||||
* @return 0 if no error occurred, -1 otherwise
|
||||
*/
|
||||
int fuse_loop(struct fuse *f);
|
||||
|
||||
/**
|
||||
* Exit from event loop
|
||||
*
|
||||
* @param f the FUSE handle
|
||||
*/
|
||||
void fuse_exit(struct fuse *f);
|
||||
|
||||
/**
|
||||
* FUSE event loop with multiple threads
|
||||
*
|
||||
* Requests from the kernel are processed, and the appropriate
|
||||
* operations are called. Request are processed in parallel by
|
||||
* distributing them between multiple threads.
|
||||
*
|
||||
* Calling this function requires the pthreads library to be linked to
|
||||
* the application.
|
||||
*
|
||||
* @param f the FUSE handle
|
||||
* @return 0 if no error occurred, -1 otherwise
|
||||
*/
|
||||
int fuse_loop_mt(struct fuse *f);
|
||||
|
||||
/**
|
||||
* Get the current context
|
||||
*
|
||||
* The context is only valid for the duration of a filesystem
|
||||
* operation, and thus must not be stored and used later.
|
||||
*
|
||||
* @return the context
|
||||
*/
|
||||
struct fuse_context *fuse_get_context(void);
|
||||
|
||||
/**
|
||||
* Check if a request has already been interrupted
|
||||
*
|
||||
* @param req request handle
|
||||
* @return 1 if the request has been interrupted, 0 otherwise
|
||||
*/
|
||||
int fuse_interrupted(void);
|
||||
|
||||
/**
|
||||
* The real main function
|
||||
*
|
||||
* Do not call this directly, use fuse_main()
|
||||
*/
|
||||
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
|
||||
size_t op_size, void *user_data);
|
||||
|
||||
/*
|
||||
* Stacking API
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fuse filesystem object
|
||||
*
|
||||
* This is opaque object represents a filesystem layer
|
||||
*/
|
||||
struct fuse_fs;
|
||||
|
||||
/*
|
||||
* These functions call the relevant filesystem operation, and return
|
||||
* the result.
|
||||
*
|
||||
* If the operation is not defined, they return -ENOSYS, with the
|
||||
* exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir,
|
||||
* fuse_fs_releasedir and fuse_fs_statfs, which return 0.
|
||||
*/
|
||||
|
||||
int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf);
|
||||
int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
|
||||
const char *newpath);
|
||||
int fuse_fs_unlink(struct fuse_fs *fs, const char *path);
|
||||
int fuse_fs_rmdir(struct fuse_fs *fs, const char *path);
|
||||
int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname,
|
||||
const char *path);
|
||||
int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath);
|
||||
int fuse_fs_release(struct fuse_fs *fs, const char *path,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_open(struct fuse_fs *fs, const char *path,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
|
||||
off_t off, struct fuse_file_info *fi);
|
||||
int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
|
||||
size_t size, off_t off, struct fuse_file_info *fi);
|
||||
int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_flush(struct fuse_fs *fs, const char *path,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf);
|
||||
int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
|
||||
fuse_fill_dir_t filler, off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_lock(struct fuse_fs *fs, const char *path,
|
||||
struct fuse_file_info *fi, int cmd, struct flock *lock);
|
||||
int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode);
|
||||
int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid);
|
||||
int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size);
|
||||
int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
|
||||
const struct timespec tv[2]);
|
||||
int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask);
|
||||
int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
|
||||
size_t len);
|
||||
int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
|
||||
dev_t rdev);
|
||||
int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode);
|
||||
int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
|
||||
const char *value, size_t size, int flags);
|
||||
int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
|
||||
char *value, size_t size);
|
||||
int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
|
||||
size_t size);
|
||||
int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
|
||||
const char *name);
|
||||
int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
|
||||
uint64_t *idx);
|
||||
void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn);
|
||||
void fuse_fs_destroy(struct fuse_fs *fs);
|
||||
|
||||
/**
|
||||
* Create a new fuse filesystem object
|
||||
*
|
||||
* This is usually called from the factory of a fuse module to create
|
||||
* a new instance of a filesystem.
|
||||
*
|
||||
* @param op the filesystem operations
|
||||
* @param op_size the size of the fuse_operations structure
|
||||
* @param user_data user data supplied in the context during the init() method
|
||||
* @return a new filesystem object
|
||||
*/
|
||||
struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
|
||||
void *user_data);
|
||||
|
||||
/* ----------------------------------------------------------- *
|
||||
* Advanced API for event handling, don't worry about this... *
|
||||
* ----------------------------------------------------------- */
|
||||
|
||||
/* NOTE: the following functions are deprecated, and will be removed
|
||||
from the 3.0 API. Use the lowlevel session functions instead */
|
||||
|
||||
/** Get session from fuse object */
|
||||
struct fuse_session *fuse_get_session(struct fuse *f);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FUSE_H_ */
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
/** @file */
|
||||
|
||||
#if !defined(_FUSE_H_) && !defined(_FUSE_LOWLEVEL_H_)
|
||||
#error "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h instead."
|
||||
#endif
|
||||
|
||||
#ifndef _FUSE_COMMON_H_
|
||||
#define _FUSE_COMMON_H_
|
||||
|
||||
#include "fuse_opt.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/** Major version of FUSE library interface */
|
||||
#define FUSE_MAJOR_VERSION 2
|
||||
|
||||
/** Minor version of FUSE library interface */
|
||||
#define FUSE_MINOR_VERSION 7
|
||||
|
||||
#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
|
||||
#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
|
||||
|
||||
/* This interface uses 64 bit off_t */
|
||||
#if _FILE_OFFSET_BITS != 64
|
||||
#error Please add -D_FILE_OFFSET_BITS=64 to your compile flags!
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Information about open files
|
||||
*
|
||||
* Changed in version 2.5
|
||||
*/
|
||||
struct fuse_file_info {
|
||||
/** Open flags. Available in open() and release() */
|
||||
int flags;
|
||||
|
||||
/** Old file handle, don't use */
|
||||
unsigned long fh_old;
|
||||
|
||||
/** In case of a write operation indicates if this was caused by a
|
||||
writepage */
|
||||
int writepage;
|
||||
|
||||
/** Can be filled in by open, to use direct I/O on this file.
|
||||
Introduced in version 2.4 */
|
||||
unsigned int direct_io : 1;
|
||||
|
||||
/** Can be filled in by open, to indicate, that cached file data
|
||||
need not be invalidated. Introduced in version 2.4 */
|
||||
unsigned int keep_cache : 1;
|
||||
|
||||
/** Indicates a flush operation. Set in flush operation, also
|
||||
maybe set in highlevel lock operation and lowlevel release
|
||||
operation. Introduced in version 2.6 */
|
||||
unsigned int flush : 1;
|
||||
|
||||
/** Padding. Do not use*/
|
||||
unsigned int padding : 29;
|
||||
|
||||
/** File handle. May be filled in by filesystem in open().
|
||||
Available in all other file operations */
|
||||
uint64_t fh;
|
||||
|
||||
/** Lock owner id. Available in locking operations and flush */
|
||||
uint64_t lock_owner;
|
||||
};
|
||||
|
||||
/**
|
||||
* Connection information, passed to the ->init() method
|
||||
*
|
||||
* Some of the elements are read-write, these can be changed to
|
||||
* indicate the value requested by the filesystem. The requested
|
||||
* value must usually be smaller than the indicated value.
|
||||
*/
|
||||
struct fuse_conn_info {
|
||||
/**
|
||||
* Major version of the protocol (read-only)
|
||||
*/
|
||||
unsigned proto_major;
|
||||
|
||||
/**
|
||||
* Minor version of the protocol (read-only)
|
||||
*/
|
||||
unsigned proto_minor;
|
||||
|
||||
/**
|
||||
* Is asynchronous read supported (read-write)
|
||||
*/
|
||||
unsigned async_read;
|
||||
|
||||
/**
|
||||
* Maximum size of the write buffer
|
||||
*/
|
||||
unsigned max_write;
|
||||
|
||||
/**
|
||||
* Maximum readahead
|
||||
*/
|
||||
unsigned max_readahead;
|
||||
|
||||
/**
|
||||
* For future use.
|
||||
*/
|
||||
unsigned reserved[27];
|
||||
};
|
||||
|
||||
struct fuse_session;
|
||||
struct fuse_chan;
|
||||
|
||||
/**
|
||||
* Create a FUSE mountpoint
|
||||
*
|
||||
* Returns a control file descriptor suitable for passing to
|
||||
* fuse_new()
|
||||
*
|
||||
* @param mountpoint the mount point path
|
||||
* @param args argument vector
|
||||
* @return the communication channel on success, NULL on failure
|
||||
*/
|
||||
struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args);
|
||||
|
||||
/**
|
||||
* Umount a FUSE mountpoint
|
||||
*
|
||||
* @param mountpoint the mount point path
|
||||
* @param ch the communication channel
|
||||
*/
|
||||
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch);
|
||||
|
||||
/**
|
||||
* Parse common options
|
||||
*
|
||||
* The following options are parsed:
|
||||
*
|
||||
* '-f' foreground
|
||||
* '-d' '-odebug' foreground, but keep the debug option
|
||||
* '-s' single threaded
|
||||
* '-h' '--help' help
|
||||
* '-ho' help without header
|
||||
* '-ofsname=..' file system name, if not present, then set to the program
|
||||
* name
|
||||
*
|
||||
* All parameters may be NULL
|
||||
*
|
||||
* @param args argument vector
|
||||
* @param mountpoint the returned mountpoint, should be freed after use
|
||||
* @param multithreaded set to 1 unless the '-s' option is present
|
||||
* @param foreground set to 1 if one of the relevant options is present
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
|
||||
int *multithreaded, int *foreground);
|
||||
|
||||
/**
|
||||
* Go into the background
|
||||
*
|
||||
* @param foreground if true, stay in the foreground
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int fuse_daemonize(int foreground);
|
||||
|
||||
/**
|
||||
* Get the version of the library
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
int fuse_version(void);
|
||||
|
||||
/* ----------------------------------------------------------- *
|
||||
* Signal handling *
|
||||
* ----------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Exit session on HUP, TERM and INT signals and ignore PIPE signal
|
||||
*
|
||||
* Stores session in a global variable. May only be called once per
|
||||
* process until fuse_remove_signal_handlers() is called.
|
||||
*
|
||||
* @param se the session to exit
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int fuse_set_signal_handlers(struct fuse_session *se);
|
||||
|
||||
/**
|
||||
* Restore default signal handlers
|
||||
*
|
||||
* Resets global session. After this fuse_set_signal_handlers() may
|
||||
* be called again.
|
||||
*
|
||||
* @param se the same session as given in fuse_set_signal_handlers()
|
||||
*/
|
||||
void fuse_remove_signal_handlers(struct fuse_session *se);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FUSE_COMMON_H_ */
|
|
@ -0,0 +1,376 @@
|
|||
/*
|
||||
This file defines the kernel interface of FUSE
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU GPL.
|
||||
See the file COPYING.
|
||||
|
||||
This -- and only this -- header file may also be distributed under
|
||||
the terms of the BSD Licence as follows:
|
||||
|
||||
Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
#include <sys/types.h>
|
||||
#define __u64 uint64_t
|
||||
#define __u32 uint32_t
|
||||
#define __s32 int32_t
|
||||
#else
|
||||
#include <asm/types.h>
|
||||
#include <linux/major.h>
|
||||
#endif
|
||||
|
||||
/** Version number of this interface */
|
||||
#define FUSE_KERNEL_VERSION 7
|
||||
|
||||
/** Minor version number of this interface */
|
||||
#define FUSE_KERNEL_MINOR_VERSION 8
|
||||
|
||||
/** The node ID of the root inode */
|
||||
#define FUSE_ROOT_ID 1
|
||||
|
||||
/** The major number of the fuse character device */
|
||||
#define FUSE_MAJOR MISC_MAJOR
|
||||
|
||||
/** The minor number of the fuse character device */
|
||||
#define FUSE_MINOR 229
|
||||
|
||||
/* Make sure all structures are padded to 64bit boundary, so 32bit
|
||||
userspace works under 64bit kernels */
|
||||
|
||||
struct fuse_attr {
|
||||
__u64 ino;
|
||||
__u64 size;
|
||||
__u64 blocks;
|
||||
__u64 atime;
|
||||
__u64 mtime;
|
||||
__u64 ctime;
|
||||
__u32 atimensec;
|
||||
__u32 mtimensec;
|
||||
__u32 ctimensec;
|
||||
__u32 mode;
|
||||
__u32 nlink;
|
||||
__u32 uid;
|
||||
__u32 gid;
|
||||
__u32 rdev;
|
||||
};
|
||||
|
||||
struct fuse_kstatfs {
|
||||
__u64 blocks;
|
||||
__u64 bfree;
|
||||
__u64 bavail;
|
||||
__u64 files;
|
||||
__u64 ffree;
|
||||
__u32 bsize;
|
||||
__u32 namelen;
|
||||
__u32 frsize;
|
||||
__u32 padding;
|
||||
__u32 spare[6];
|
||||
};
|
||||
|
||||
struct fuse_file_lock {
|
||||
__u64 start;
|
||||
__u64 end;
|
||||
__u32 type;
|
||||
__u32 pid; /* tgid */
|
||||
};
|
||||
|
||||
/**
|
||||
* Bitmasks for fuse_setattr_in.valid
|
||||
*/
|
||||
#define FATTR_MODE (1 << 0)
|
||||
#define FATTR_UID (1 << 1)
|
||||
#define FATTR_GID (1 << 2)
|
||||
#define FATTR_SIZE (1 << 3)
|
||||
#define FATTR_ATIME (1 << 4)
|
||||
#define FATTR_MTIME (1 << 5)
|
||||
#define FATTR_FH (1 << 6)
|
||||
|
||||
/**
|
||||
* Flags returned by the OPEN request
|
||||
*
|
||||
* FOPEN_DIRECT_IO: bypass page cache for this open file
|
||||
* FOPEN_KEEP_CACHE: don't invalidate the data cache on open
|
||||
*/
|
||||
#define FOPEN_DIRECT_IO (1 << 0)
|
||||
#define FOPEN_KEEP_CACHE (1 << 1)
|
||||
|
||||
/**
|
||||
* INIT request/reply flags
|
||||
*/
|
||||
#define FUSE_ASYNC_READ (1 << 0)
|
||||
#define FUSE_POSIX_LOCKS (1 << 1)
|
||||
|
||||
/**
|
||||
* Release flags
|
||||
*/
|
||||
#define FUSE_RELEASE_FLUSH (1 << 0)
|
||||
|
||||
enum fuse_opcode {
|
||||
FUSE_LOOKUP = 1,
|
||||
FUSE_FORGET = 2, /* no reply */
|
||||
FUSE_GETATTR = 3,
|
||||
FUSE_SETATTR = 4,
|
||||
FUSE_READLINK = 5,
|
||||
FUSE_SYMLINK = 6,
|
||||
FUSE_MKNOD = 8,
|
||||
FUSE_MKDIR = 9,
|
||||
FUSE_UNLINK = 10,
|
||||
FUSE_RMDIR = 11,
|
||||
FUSE_RENAME = 12,
|
||||
FUSE_LINK = 13,
|
||||
FUSE_OPEN = 14,
|
||||
FUSE_READ = 15,
|
||||
FUSE_WRITE = 16,
|
||||
FUSE_STATFS = 17,
|
||||
FUSE_RELEASE = 18,
|
||||
FUSE_FSYNC = 20,
|
||||
FUSE_SETXATTR = 21,
|
||||
FUSE_GETXATTR = 22,
|
||||
FUSE_LISTXATTR = 23,
|
||||
FUSE_REMOVEXATTR = 24,
|
||||
FUSE_FLUSH = 25,
|
||||
FUSE_INIT = 26,
|
||||
FUSE_OPENDIR = 27,
|
||||
FUSE_READDIR = 28,
|
||||
FUSE_RELEASEDIR = 29,
|
||||
FUSE_FSYNCDIR = 30,
|
||||
FUSE_GETLK = 31,
|
||||
FUSE_SETLK = 32,
|
||||
FUSE_SETLKW = 33,
|
||||
FUSE_ACCESS = 34,
|
||||
FUSE_CREATE = 35,
|
||||
FUSE_INTERRUPT = 36,
|
||||
FUSE_BMAP = 37,
|
||||
FUSE_DESTROY = 38,
|
||||
};
|
||||
|
||||
/* The read buffer is required to be at least 8k, but may be much larger */
|
||||
#define FUSE_MIN_READ_BUFFER 8192
|
||||
|
||||
struct fuse_entry_out {
|
||||
__u64 nodeid; /* Inode ID */
|
||||
__u64 generation; /* Inode generation: nodeid:gen must
|
||||
be unique for the fs's lifetime */
|
||||
__u64 entry_valid; /* Cache timeout for the name */
|
||||
__u64 attr_valid; /* Cache timeout for the attributes */
|
||||
__u32 entry_valid_nsec;
|
||||
__u32 attr_valid_nsec;
|
||||
struct fuse_attr attr;
|
||||
};
|
||||
|
||||
struct fuse_forget_in {
|
||||
__u64 nlookup;
|
||||
};
|
||||
|
||||
struct fuse_attr_out {
|
||||
__u64 attr_valid; /* Cache timeout for the attributes */
|
||||
__u32 attr_valid_nsec;
|
||||
__u32 dummy;
|
||||
struct fuse_attr attr;
|
||||
};
|
||||
|
||||
struct fuse_mknod_in {
|
||||
__u32 mode;
|
||||
__u32 rdev;
|
||||
};
|
||||
|
||||
struct fuse_mkdir_in {
|
||||
__u32 mode;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_rename_in {
|
||||
__u64 newdir;
|
||||
};
|
||||
|
||||
struct fuse_link_in {
|
||||
__u64 oldnodeid;
|
||||
};
|
||||
|
||||
struct fuse_setattr_in {
|
||||
__u32 valid;
|
||||
__u32 padding;
|
||||
__u64 fh;
|
||||
__u64 size;
|
||||
__u64 unused1;
|
||||
__u64 atime;
|
||||
__u64 mtime;
|
||||
__u64 unused2;
|
||||
__u32 atimensec;
|
||||
__u32 mtimensec;
|
||||
__u32 unused3;
|
||||
__u32 mode;
|
||||
__u32 unused4;
|
||||
__u32 uid;
|
||||
__u32 gid;
|
||||
__u32 unused5;
|
||||
};
|
||||
|
||||
struct fuse_open_in {
|
||||
__u32 flags;
|
||||
__u32 mode;
|
||||
};
|
||||
|
||||
struct fuse_open_out {
|
||||
__u64 fh;
|
||||
__u32 open_flags;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_release_in {
|
||||
__u64 fh;
|
||||
__u32 flags;
|
||||
__u32 release_flags;
|
||||
__u64 lock_owner;
|
||||
};
|
||||
|
||||
struct fuse_flush_in {
|
||||
__u64 fh;
|
||||
__u32 unused;
|
||||
__u32 padding;
|
||||
__u64 lock_owner;
|
||||
};
|
||||
|
||||
struct fuse_read_in {
|
||||
__u64 fh;
|
||||
__u64 offset;
|
||||
__u32 size;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_write_in {
|
||||
__u64 fh;
|
||||
__u64 offset;
|
||||
__u32 size;
|
||||
__u32 write_flags;
|
||||
};
|
||||
|
||||
struct fuse_write_out {
|
||||
__u32 size;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
#define FUSE_COMPAT_STATFS_SIZE 48
|
||||
|
||||
struct fuse_statfs_out {
|
||||
struct fuse_kstatfs st;
|
||||
};
|
||||
|
||||
struct fuse_fsync_in {
|
||||
__u64 fh;
|
||||
__u32 fsync_flags;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_setxattr_in {
|
||||
__u32 size;
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
struct fuse_getxattr_in {
|
||||
__u32 size;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_getxattr_out {
|
||||
__u32 size;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_lk_in {
|
||||
__u64 fh;
|
||||
__u64 owner;
|
||||
struct fuse_file_lock lk;
|
||||
};
|
||||
|
||||
struct fuse_lk_out {
|
||||
struct fuse_file_lock lk;
|
||||
};
|
||||
|
||||
struct fuse_access_in {
|
||||
__u32 mask;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_init_in {
|
||||
__u32 major;
|
||||
__u32 minor;
|
||||
__u32 max_readahead;
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
struct fuse_init_out {
|
||||
__u32 major;
|
||||
__u32 minor;
|
||||
__u32 max_readahead;
|
||||
__u32 flags;
|
||||
__u32 unused;
|
||||
__u32 max_write;
|
||||
};
|
||||
|
||||
struct fuse_interrupt_in {
|
||||
__u64 unique;
|
||||
};
|
||||
|
||||
struct fuse_bmap_in {
|
||||
__u64 block;
|
||||
__u32 blocksize;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_bmap_out {
|
||||
__u64 block;
|
||||
};
|
||||
|
||||
struct fuse_in_header {
|
||||
__u32 len;
|
||||
__u32 opcode;
|
||||
__u64 unique;
|
||||
__u64 nodeid;
|
||||
__u32 uid;
|
||||
__u32 gid;
|
||||
__u32 pid;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_out_header {
|
||||
__u32 len;
|
||||
__s32 error;
|
||||
__u64 unique;
|
||||
};
|
||||
|
||||
struct fuse_dirent {
|
||||
__u64 ino;
|
||||
__u64 off;
|
||||
__u32 namelen;
|
||||
__u32 type;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
|
||||
#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
|
||||
#define FUSE_DIRENT_SIZE(d) \
|
||||
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
/* these definitions provide source compatibility to prior versions.
|
||||
Do not include this file directly! */
|
||||
|
||||
size_t fuse_dirent_size(size_t namelen);
|
||||
|
||||
char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
|
||||
off_t off);
|
||||
|
||||
struct fuse_chan *fuse_kern_chan_new(int fd);
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#ifndef _FUSE_OPT_H_
|
||||
#define _FUSE_OPT_H_
|
||||
|
||||
/** @file
|
||||
*
|
||||
* This file defines the option parsing interface of FUSE
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Option description
|
||||
*
|
||||
* This structure describes a single option, and and action associated
|
||||
* with it, in case it matches.
|
||||
*
|
||||
* More than one such match may occur, in which case the action for
|
||||
* each match is executed.
|
||||
*
|
||||
* There are three possible actions in case of a match:
|
||||
*
|
||||
* i) An integer (int or unsigned) variable determined by 'offset' is
|
||||
* set to 'value'
|
||||
*
|
||||
* ii) The processing function is called, with 'value' as the key
|
||||
*
|
||||
* iii) An integer (any) or string (char *) variable determined by
|
||||
* 'offset' is set to the value of an option parameter
|
||||
*
|
||||
* 'offset' should normally be either set to
|
||||
*
|
||||
* - 'offsetof(struct foo, member)' actions i) and iii)
|
||||
*
|
||||
* - -1 action ii)
|
||||
*
|
||||
* The 'offsetof()' macro is defined in the <stddef.h> header.
|
||||
*
|
||||
* The template determines which options match, and also have an
|
||||
* effect on the action. Normally the action is either i) or ii), but
|
||||
* if a format is present in the template, then action iii) is
|
||||
* performed.
|
||||
*
|
||||
* The types of templates are:
|
||||
*
|
||||
* 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only
|
||||
* themselves. Invalid values are "--" and anything beginning
|
||||
* with "-o"
|
||||
*
|
||||
* 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or
|
||||
* the relevant option in a comma separated option list
|
||||
*
|
||||
* 3) "bar=", "--foo=", etc. These are variations of 1) and 2)
|
||||
* which have a parameter
|
||||
*
|
||||
* 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform
|
||||
* action iii).
|
||||
*
|
||||
* 5) "-x ", etc. Matches either "-xparam" or "-x param" as
|
||||
* two separate arguments
|
||||
*
|
||||
* 6) "-x %s", etc. Combination of 4) and 5)
|
||||
*
|
||||
* If the format is "%s", memory is allocated for the string unlike
|
||||
* with scanf().
|
||||
*/
|
||||
struct fuse_opt {
|
||||
/** Matching template and optional parameter formatting */
|
||||
const char *templ;
|
||||
|
||||
/**
|
||||
* Offset of variable within 'data' parameter of fuse_opt_parse()
|
||||
* or -1
|
||||
*/
|
||||
unsigned long offset;
|
||||
|
||||
/**
|
||||
* Value to set the variable to, or to be passed as 'key' to the
|
||||
* processing function. Ignored if template has a format
|
||||
*/
|
||||
int value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Key option. In case of a match, the processing function will be
|
||||
* called with the specified key.
|
||||
*/
|
||||
#define FUSE_OPT_KEY(templ, key) { templ, -1U, key }
|
||||
|
||||
/**
|
||||
* Last option. An array of 'struct fuse_opt' must end with a NULL
|
||||
* template value
|
||||
*/
|
||||
#define FUSE_OPT_END { .templ = NULL }
|
||||
|
||||
/**
|
||||
* Argument list
|
||||
*/
|
||||
struct fuse_args {
|
||||
/** Argument count */
|
||||
int argc;
|
||||
|
||||
/** Argument vector. NULL terminated */
|
||||
char **argv;
|
||||
|
||||
/** Is 'argv' allocated? */
|
||||
int allocated;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializer for 'struct fuse_args'
|
||||
*/
|
||||
#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }
|
||||
|
||||
/**
|
||||
* Key value passed to the processing function if an option did not
|
||||
* match any template
|
||||
*/
|
||||
#define FUSE_OPT_KEY_OPT -1
|
||||
|
||||
/**
|
||||
* Key value passed to the processing function for all non-options
|
||||
*
|
||||
* Non-options are the arguments beginning with a charater other than
|
||||
* '-' or all arguments after the special '--' option
|
||||
*/
|
||||
#define FUSE_OPT_KEY_NONOPT -2
|
||||
|
||||
/**
|
||||
* Special key value for options to keep
|
||||
*
|
||||
* Argument is not passed to processing function, but behave as if the
|
||||
* processing function returned 1
|
||||
*/
|
||||
#define FUSE_OPT_KEY_KEEP -3
|
||||
|
||||
/**
|
||||
* Special key value for options to discard
|
||||
*
|
||||
* Argument is not passed to processing function, but behave as if the
|
||||
* processing function returned zero
|
||||
*/
|
||||
#define FUSE_OPT_KEY_DISCARD -4
|
||||
|
||||
/**
|
||||
* Processing function
|
||||
*
|
||||
* This function is called if
|
||||
* - option did not match any 'struct fuse_opt'
|
||||
* - argument is a non-option
|
||||
* - option did match and offset was set to -1
|
||||
*
|
||||
* The 'arg' parameter will always contain the whole argument or
|
||||
* option including the parameter if exists. A two-argument option
|
||||
* ("-x foo") is always converted to single arguemnt option of the
|
||||
* form "-xfoo" before this function is called.
|
||||
*
|
||||
* Options of the form '-ofoo' are passed to this function without the
|
||||
* '-o' prefix.
|
||||
*
|
||||
* The return value of this function determines whether this argument
|
||||
* is to be inserted into the output argument vector, or discarded.
|
||||
*
|
||||
* @param data is the user data passed to the fuse_opt_parse() function
|
||||
* @param arg is the whole argument or option
|
||||
* @param key determines why the processing function was called
|
||||
* @param outargs the current output argument list
|
||||
* @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept
|
||||
*/
|
||||
typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
|
||||
struct fuse_args *outargs);
|
||||
|
||||
/**
|
||||
* Option parsing function
|
||||
*
|
||||
* If 'args' was returned from a previous call to fuse_opt_parse() or
|
||||
* it was constructed from
|
||||
*
|
||||
* A NULL 'args' is equivalent to an empty argument vector
|
||||
*
|
||||
* A NULL 'opts' is equivalent to an 'opts' array containing a single
|
||||
* end marker
|
||||
*
|
||||
* A NULL 'proc' is equivalent to a processing function always
|
||||
* returning '1'
|
||||
*
|
||||
* @param args is the input and output argument list
|
||||
* @param data is the user data
|
||||
* @param opts is the option description array
|
||||
* @param proc is the processing function
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
int fuse_opt_parse(struct fuse_args *args, void *data,
|
||||
const struct fuse_opt opts[], fuse_opt_proc_t proc);
|
||||
|
||||
/**
|
||||
* Add an option to a comma separated option list
|
||||
*
|
||||
* @param opts is a pointer to an option list, may point to a NULL value
|
||||
* @param opt is the option to add
|
||||
* @return -1 on allocation error, 0 on success
|
||||
*/
|
||||
int fuse_opt_add_opt(char **opts, const char *opt);
|
||||
|
||||
/**
|
||||
* Add an argument to a NULL terminated argument vector
|
||||
*
|
||||
* @param args is the structure containing the current argument list
|
||||
* @param arg is the new argument to add
|
||||
* @return -1 on allocation error, 0 on success
|
||||
*/
|
||||
int fuse_opt_add_arg(struct fuse_args *args, const char *arg);
|
||||
|
||||
/**
|
||||
* Add an argument at the specified position in a NULL terminated
|
||||
* argument vector
|
||||
*
|
||||
* Adds the argument to the N-th position. This is useful for adding
|
||||
* options at the beggining of the array which must not come after the
|
||||
* special '--' option.
|
||||
*
|
||||
* @param args is the structure containing the current argument list
|
||||
* @param pos is the position at which to add the argument
|
||||
* @param arg is the new argument to add
|
||||
* @return -1 on allocation error, 0 on success
|
||||
*/
|
||||
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg);
|
||||
|
||||
/**
|
||||
* Free the contents of argument list
|
||||
*
|
||||
* The structure itself is not freed
|
||||
*
|
||||
* @param args is the structure containing the argument list
|
||||
*/
|
||||
void fuse_opt_free_args(struct fuse_args *args);
|
||||
|
||||
|
||||
/**
|
||||
* Check if an option matches
|
||||
*
|
||||
* @param opts is the option description array
|
||||
* @param opt is the option to match
|
||||
* @return 1 if a match is found, 0 if not
|
||||
*/
|
||||
int fuse_opt_match(const struct fuse_opt opts[], const char *opt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FUSE_OPT_H_ */
|
|
@ -1,35 +1,36 @@
|
|||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
if INSTALL_LIBRARY
|
||||
linux_ntfsincludedir = $(includedir)/ntfs-3g
|
||||
linux_ntfsinclude_HEADERS = \
|
||||
attrib.h \
|
||||
attrlist.h \
|
||||
bitmap.h \
|
||||
bootsect.h \
|
||||
collate.h \
|
||||
compat.h \
|
||||
compress.h \
|
||||
debug.h \
|
||||
device.h \
|
||||
device_io.h \
|
||||
dir.h \
|
||||
endians.h \
|
||||
index.h \
|
||||
inode.h \
|
||||
layout.h \
|
||||
lcnalloc.h \
|
||||
logfile.h \
|
||||
logging.h \
|
||||
mft.h \
|
||||
mst.h \
|
||||
ntfstime.h \
|
||||
runlist.h \
|
||||
security.h \
|
||||
support.h \
|
||||
types.h \
|
||||
unistr.h \
|
||||
version.h \
|
||||
ntfs3ginclude_HEADERS = \
|
||||
attrib.h \
|
||||
attrlist.h \
|
||||
bitmap.h \
|
||||
bootsect.h \
|
||||
collate.h \
|
||||
compat.h \
|
||||
compress.h \
|
||||
debug.h \
|
||||
device.h \
|
||||
device_io.h \
|
||||
dir.h \
|
||||
endians.h \
|
||||
index.h \
|
||||
inode.h \
|
||||
layout.h \
|
||||
lcnalloc.h \
|
||||
logfile.h \
|
||||
logging.h \
|
||||
mft.h \
|
||||
misc.h \
|
||||
mst.h \
|
||||
ntfstime.h \
|
||||
runlist.h \
|
||||
security.h \
|
||||
support.h \
|
||||
types.h \
|
||||
unistr.h \
|
||||
version.h \
|
||||
volume.h
|
||||
endif
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
if FUSE_INTERNAL
|
||||
noinst_LTLIBRARIES = libfuse-lite.la
|
||||
endif
|
||||
|
||||
libfuse_lite_la_CFLAGS= \
|
||||
$(AM_CFLAGS) \
|
||||
-I$(top_srcdir)/include/fuse-lite \
|
||||
-DFUSERMOUNT_DIR=\"$(bindir)\" \
|
||||
-D_REENTRANT \
|
||||
-D_FILE_OFFSET_BITS=64
|
||||
|
||||
libfuse_lite_la_LIBADD = $(LIBFUSE_LITE_LIBS)
|
||||
|
||||
libfuse_lite_la_SOURCES = \
|
||||
fuse.c \
|
||||
fuse_i.h \
|
||||
fuse_kern_chan.c \
|
||||
fuse_loop.c \
|
||||
fuse_loop_mt.c \
|
||||
fuse_lowlevel.c \
|
||||
fuse_misc.h \
|
||||
fuse_mt.c \
|
||||
fuse_opt.c \
|
||||
fuse_session.c \
|
||||
fuse_signals.c \
|
||||
helper.c \
|
||||
mount.c \
|
||||
mount_util.c \
|
||||
mount_util.h
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "fuse.h"
|
||||
|
||||
struct fuse_session;
|
||||
struct fuse_chan;
|
||||
struct fuse_lowlevel_ops;
|
||||
struct fuse_req;
|
||||
|
||||
struct fuse_cmd {
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
struct fuse_chan *ch;
|
||||
};
|
||||
|
||||
struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
|
||||
const struct fuse_operations *op,
|
||||
size_t op_size, void *user_data);
|
||||
|
||||
struct fuse_chan *fuse_kern_chan_new(int fd);
|
||||
|
||||
struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
|
||||
const struct fuse_lowlevel_ops *op,
|
||||
size_t op_size, void *userdata);
|
||||
|
||||
void fuse_kern_unmount(const char *mountpoint, int fd);
|
||||
int fuse_kern_mount(const char *mountpoint, struct fuse_args *args);
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "fuse_lowlevel.h"
|
||||
#include "fuse_kernel.h"
|
||||
#include "fuse_i.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct fuse_chan *ch = *chp;
|
||||
int err;
|
||||
ssize_t res;
|
||||
struct fuse_session *se = fuse_chan_session(ch);
|
||||
assert(se != NULL);
|
||||
|
||||
restart:
|
||||
res = read(fuse_chan_fd(ch), buf, size);
|
||||
err = errno;
|
||||
|
||||
if (fuse_session_exited(se))
|
||||
return 0;
|
||||
if (res == -1) {
|
||||
/* ENOENT means the operation was interrupted, it's safe
|
||||
to restart */
|
||||
if (err == ENOENT)
|
||||
goto restart;
|
||||
|
||||
if (err == ENODEV) {
|
||||
fuse_session_exit(se);
|
||||
return 0;
|
||||
}
|
||||
/* Errors occuring during normal operation: EINTR (read
|
||||
interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
|
||||
umounted) */
|
||||
if (err != EINTR && err != EAGAIN)
|
||||
perror("fuse: reading device");
|
||||
return -err;
|
||||
}
|
||||
if ((size_t) res < sizeof(struct fuse_in_header)) {
|
||||
fprintf(stderr, "short read on fuse device\n");
|
||||
return -EIO;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],
|
||||
size_t count)
|
||||
{
|
||||
if (iov) {
|
||||
ssize_t res = writev(fuse_chan_fd(ch), iov, count);
|
||||
int err = errno;
|
||||
|
||||
if (res == -1) {
|
||||
struct fuse_session *se = fuse_chan_session(ch);
|
||||
|
||||
assert(se != NULL);
|
||||
|
||||
/* ENOENT means the operation was interrupted */
|
||||
if (!fuse_session_exited(se) && err != ENOENT)
|
||||
perror("fuse: writing device");
|
||||
return -err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fuse_kern_chan_destroy(struct fuse_chan *ch)
|
||||
{
|
||||
close(fuse_chan_fd(ch));
|
||||
}
|
||||
|
||||
#define MIN_BUFSIZE 0x21000
|
||||
|
||||
struct fuse_chan *fuse_kern_chan_new(int fd)
|
||||
{
|
||||
struct fuse_chan_ops op = {
|
||||
.receive = fuse_kern_chan_receive,
|
||||
.send = fuse_kern_chan_send,
|
||||
.destroy = fuse_kern_chan_destroy,
|
||||
};
|
||||
size_t bufsize = getpagesize() + 0x1000;
|
||||
bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;
|
||||
return fuse_chan_new(&op, fd, bufsize, NULL);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "fuse_lowlevel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
int fuse_session_loop(struct fuse_session *se)
|
||||
{
|
||||
int res = 0;
|
||||
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
|
||||
size_t bufsize = fuse_chan_bufsize(ch);
|
||||
char *buf = (char *) malloc(bufsize);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "fuse: failed to allocate read buffer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (!fuse_session_exited(se)) {
|
||||
struct fuse_chan *tmpch = ch;
|
||||
res = fuse_chan_recv(&tmpch, buf, bufsize);
|
||||
if (res == -EINTR)
|
||||
continue;
|
||||
if (res <= 0)
|
||||
break;
|
||||
fuse_session_process(se, buf, res, tmpch);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
fuse_session_reset(se);
|
||||
return res < 0 ? -1 : 0;
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#include "fuse_lowlevel.h"
|
||||
#include "fuse_misc.h"
|
||||
#include "fuse_kernel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
struct fuse_worker {
|
||||
struct fuse_worker *prev;
|
||||
struct fuse_worker *next;
|
||||
pthread_t thread_id;
|
||||
size_t bufsize;
|
||||
char *buf;
|
||||
struct fuse_mt *mt;
|
||||
};
|
||||
|
||||
struct fuse_mt {
|
||||
pthread_mutex_t lock;
|
||||
int numworker;
|
||||
int numavail;
|
||||
struct fuse_session *se;
|
||||
struct fuse_chan *prevch;
|
||||
struct fuse_worker main;
|
||||
sem_t finish;
|
||||
int exit;
|
||||
int error;
|
||||
};
|
||||
|
||||
static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next)
|
||||
{
|
||||
struct fuse_worker *prev = next->prev;
|
||||
w->next = next;
|
||||
w->prev = prev;
|
||||
prev->next = w;
|
||||
next->prev = w;
|
||||
}
|
||||
|
||||
static void list_del_worker(struct fuse_worker *w)
|
||||
{
|
||||
struct fuse_worker *prev = w->prev;
|
||||
struct fuse_worker *next = w->next;
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
}
|
||||
|
||||
static int fuse_start_thread(struct fuse_mt *mt);
|
||||
|
||||
static void *fuse_do_work(void *data)
|
||||
{
|
||||
struct fuse_worker *w = (struct fuse_worker *) data;
|
||||
struct fuse_mt *mt = w->mt;
|
||||
|
||||
while (!fuse_session_exited(mt->se)) {
|
||||
int isforget = 0;
|
||||
struct fuse_chan *ch = mt->prevch;
|
||||
int res = fuse_chan_recv(&ch, w->buf, w->bufsize);
|
||||
if (res == -EINTR)
|
||||
continue;
|
||||
if (res <= 0) {
|
||||
if (res < 0) {
|
||||
fuse_session_exit(mt->se);
|
||||
mt->error = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&mt->lock);
|
||||
if (mt->exit) {
|
||||
pthread_mutex_unlock(&mt->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This disgusting hack is needed so that zillions of threads
|
||||
* are not created on a burst of FORGET messages
|
||||
*/
|
||||
if (((struct fuse_in_header *) w->buf)->opcode == FUSE_FORGET)
|
||||
isforget = 1;
|
||||
|
||||
if (!isforget)
|
||||
mt->numavail--;
|
||||
if (mt->numavail == 0)
|
||||
fuse_start_thread(mt);
|
||||
pthread_mutex_unlock(&mt->lock);
|
||||
|
||||
fuse_session_process(mt->se, w->buf, res, ch);
|
||||
|
||||
pthread_mutex_lock(&mt->lock);
|
||||
if (!isforget)
|
||||
mt->numavail++;
|
||||
if (mt->numavail > 10) {
|
||||
if (mt->exit) {
|
||||
pthread_mutex_unlock(&mt->lock);
|
||||
return NULL;
|
||||
}
|
||||
list_del_worker(w);
|
||||
mt->numavail--;
|
||||
mt->numworker--;
|
||||
pthread_mutex_unlock(&mt->lock);
|
||||
|
||||
pthread_detach(w->thread_id);
|
||||
free(w->buf);
|
||||
free(w);
|
||||
return NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&mt->lock);
|
||||
}
|
||||
|
||||
sem_post(&mt->finish);
|
||||
pause();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int fuse_start_thread(struct fuse_mt *mt)
|
||||
{
|
||||
sigset_t oldset;
|
||||
sigset_t newset;
|
||||
int res;
|
||||
struct fuse_worker *w = malloc(sizeof(struct fuse_worker));
|
||||
if (!w) {
|
||||
fprintf(stderr, "fuse: failed to allocate worker structure\n");
|
||||
return -1;
|
||||
}
|
||||
memset(w, 0, sizeof(struct fuse_worker));
|
||||
w->bufsize = fuse_chan_bufsize(mt->prevch);
|
||||
w->buf = malloc(w->bufsize);
|
||||
w->mt = mt;
|
||||
if (!w->buf) {
|
||||
fprintf(stderr, "fuse: failed to allocate read buffer\n");
|
||||
free(w);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Disallow signal reception in worker threads */
|
||||
sigemptyset(&newset);
|
||||
sigaddset(&newset, SIGTERM);
|
||||
sigaddset(&newset, SIGINT);
|
||||
sigaddset(&newset, SIGHUP);
|
||||
sigaddset(&newset, SIGQUIT);
|
||||
pthread_sigmask(SIG_BLOCK, &newset, &oldset);
|
||||
res = pthread_create(&w->thread_id, NULL, fuse_do_work, w);
|
||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "fuse: error creating thread: %s\n", strerror(res));
|
||||
free(w->buf);
|
||||
free(w);
|
||||
return -1;
|
||||
}
|
||||
list_add_worker(w, &mt->main);
|
||||
mt->numavail ++;
|
||||
mt->numworker ++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w)
|
||||
{
|
||||
pthread_join(w->thread_id, NULL);
|
||||
pthread_mutex_lock(&mt->lock);
|
||||
list_del_worker(w);
|
||||
pthread_mutex_unlock(&mt->lock);
|
||||
free(w->buf);
|
||||
free(w);
|
||||
}
|
||||
|
||||
int fuse_session_loop_mt(struct fuse_session *se)
|
||||
{
|
||||
int err;
|
||||
struct fuse_mt mt;
|
||||
struct fuse_worker *w;
|
||||
|
||||
memset(&mt, 0, sizeof(struct fuse_mt));
|
||||
mt.se = se;
|
||||
mt.prevch = fuse_session_next_chan(se, NULL);
|
||||
mt.error = 0;
|
||||
mt.numworker = 0;
|
||||
mt.numavail = 0;
|
||||
mt.main.thread_id = pthread_self();
|
||||
mt.main.prev = mt.main.next = &mt.main;
|
||||
sem_init(&mt.finish, 0, 0);
|
||||
fuse_mutex_init(&mt.lock);
|
||||
|
||||
pthread_mutex_lock(&mt.lock);
|
||||
err = fuse_start_thread(&mt);
|
||||
pthread_mutex_unlock(&mt.lock);
|
||||
if (!err) {
|
||||
/* sem_wait() is interruptible */
|
||||
while (!fuse_session_exited(se))
|
||||
sem_wait(&mt.finish);
|
||||
|
||||
for (w = mt.main.next; w != &mt.main; w = w->next)
|
||||
pthread_cancel(w->thread_id);
|
||||
mt.exit = 1;
|
||||
pthread_mutex_unlock(&mt.lock);
|
||||
|
||||
while (mt.main.next != &mt.main)
|
||||
fuse_join_worker(&mt, mt.main.next);
|
||||
|
||||
err = mt.error;
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&mt.lock);
|
||||
sem_destroy(&mt.finish);
|
||||
fuse_session_reset(se);
|
||||
return err;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#ifndef USE_UCLIBC
|
||||
#define fuse_mutex_init(mut) pthread_mutex_init(mut, NULL)
|
||||
#else
|
||||
static inline void fuse_mutex_init(pthread_mutex_t *mut)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
|
||||
pthread_mutex_init(mut, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRUCT_STAT_ST_ATIM
|
||||
/* Linux */
|
||||
#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec)
|
||||
#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec)
|
||||
#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec)
|
||||
#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atim.tv_nsec = (val)
|
||||
#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtim.tv_nsec = (val)
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
|
||||
/* FreeBSD */
|
||||
#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec)
|
||||
#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec)
|
||||
#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec)
|
||||
#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val)
|
||||
#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val)
|
||||
#else
|
||||
#define ST_ATIM_NSEC(stbuf) 0
|
||||
#define ST_CTIM_NSEC(stbuf) 0
|
||||
#define ST_MTIM_NSEC(stbuf) 0
|
||||
#define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0)
|
||||
#define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0)
|
||||
#endif
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#include "fuse_i.h"
|
||||
#include "fuse_lowlevel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
|
||||
int fuse_loop_mt(struct fuse *f)
|
||||
{
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
|
||||
return fuse_session_loop_mt(fuse_get_session(f));
|
||||
}
|
|
@ -0,0 +1,367 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "fuse_opt.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct fuse_opt_context {
|
||||
void *data;
|
||||
const struct fuse_opt *opt;
|
||||
fuse_opt_proc_t proc;
|
||||
int argctr;
|
||||
int argc;
|
||||
char **argv;
|
||||
struct fuse_args outargs;
|
||||
char *opts;
|
||||
int nonopt;
|
||||
};
|
||||
|
||||
void fuse_opt_free_args(struct fuse_args *args)
|
||||
{
|
||||
if (args) {
|
||||
if (args->argv && args->allocated) {
|
||||
int i;
|
||||
for (i = 0; i < args->argc; i++)
|
||||
free(args->argv[i]);
|
||||
free(args->argv);
|
||||
}
|
||||
args->argc = 0;
|
||||
args->argv = NULL;
|
||||
args->allocated = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int alloc_failed(void)
|
||||
{
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
|
||||
{
|
||||
char **newargv;
|
||||
char *newarg;
|
||||
|
||||
assert(!args->argv || args->allocated);
|
||||
|
||||
newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
|
||||
newarg = newargv ? strdup(arg) : NULL;
|
||||
if (!newargv || !newarg)
|
||||
return alloc_failed();
|
||||
|
||||
args->argv = newargv;
|
||||
args->allocated = 1;
|
||||
args->argv[args->argc++] = newarg;
|
||||
args->argv[args->argc] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
|
||||
{
|
||||
assert(pos <= args->argc);
|
||||
if (fuse_opt_add_arg(args, arg) == -1)
|
||||
return -1;
|
||||
|
||||
if (pos != args->argc - 1) {
|
||||
char *newarg = args->argv[args->argc - 1];
|
||||
memmove(&args->argv[pos + 1], &args->argv[pos],
|
||||
sizeof(char *) * (args->argc - pos - 1));
|
||||
args->argv[pos] = newarg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int next_arg(struct fuse_opt_context *ctx, const char *opt)
|
||||
{
|
||||
if (ctx->argctr + 1 >= ctx->argc) {
|
||||
fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
|
||||
return -1;
|
||||
}
|
||||
ctx->argctr++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_arg(struct fuse_opt_context *ctx, const char *arg)
|
||||
{
|
||||
return fuse_opt_add_arg(&ctx->outargs, arg);
|
||||
}
|
||||
|
||||
int fuse_opt_add_opt(char **opts, const char *opt)
|
||||
{
|
||||
char *newopts;
|
||||
if (!*opts)
|
||||
newopts = strdup(opt);
|
||||
else {
|
||||
unsigned oldlen = strlen(*opts);
|
||||
newopts = realloc(*opts, oldlen + 1 + strlen(opt) + 1);
|
||||
if (newopts) {
|
||||
newopts[oldlen] = ',';
|
||||
strcpy(newopts + oldlen + 1, opt);
|
||||
}
|
||||
}
|
||||
if (!newopts)
|
||||
return alloc_failed();
|
||||
|
||||
*opts = newopts;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_opt(struct fuse_opt_context *ctx, const char *opt)
|
||||
{
|
||||
return fuse_opt_add_opt(&ctx->opts, opt);
|
||||
}
|
||||
|
||||
static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
|
||||
int iso)
|
||||
{
|
||||
if (key == FUSE_OPT_KEY_DISCARD)
|
||||
return 0;
|
||||
|
||||
if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
|
||||
int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
|
||||
if (res == -1 || !res)
|
||||
return res;
|
||||
}
|
||||
if (iso)
|
||||
return add_opt(ctx, arg);
|
||||
else
|
||||
return add_arg(ctx, arg);
|
||||
}
|
||||
|
||||
static int match_template(const char *t, const char *arg, unsigned *sepp)
|
||||
{
|
||||
int arglen = strlen(arg);
|
||||
const char *sep = strchr(t, '=');
|
||||
sep = sep ? sep : strchr(t, ' ');
|
||||
if (sep && (!sep[1] || sep[1] == '%')) {
|
||||
int tlen = sep - t;
|
||||
if (sep[0] == '=')
|
||||
tlen ++;
|
||||
if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
|
||||
*sepp = sep - t;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (strcmp(t, arg) == 0) {
|
||||
*sepp = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
|
||||
const char *arg, unsigned *sepp)
|
||||
{
|
||||
for (; opt && opt->templ; opt++)
|
||||
if (match_template(opt->templ, arg, sepp))
|
||||
return opt;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
|
||||
{
|
||||
unsigned dummy;
|
||||
return find_opt(opts, opt, &dummy) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int process_opt_param(void *var, const char *format, const char *param,
|
||||
const char *arg)
|
||||
{
|
||||
assert(format[0] == '%');
|
||||
if (format[1] == 's') {
|
||||
char *copy = strdup(param);
|
||||
if (!copy)
|
||||
return alloc_failed();
|
||||
|
||||
*(char **) var = copy;
|
||||
} else {
|
||||
if (sscanf(param, format, var) != 1) {
|
||||
fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_opt(struct fuse_opt_context *ctx,
|
||||
const struct fuse_opt *opt, unsigned sep,
|
||||
const char *arg, int iso)
|
||||
{
|
||||
if (opt->offset == -1U) {
|
||||
if (call_proc(ctx, arg, opt->value, iso) == -1)
|
||||
return -1;
|
||||
} else {
|
||||
void *var = ctx->data + opt->offset;
|
||||
if (sep && opt->templ[sep + 1]) {
|
||||
const char *param = arg + sep;
|
||||
if (opt->templ[sep] == '=')
|
||||
param ++;
|
||||
if (process_opt_param(var, opt->templ + sep + 1,
|
||||
param, arg) == -1)
|
||||
return -1;
|
||||
} else
|
||||
*(int *)var = opt->value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_opt_sep_arg(struct fuse_opt_context *ctx,
|
||||
const struct fuse_opt *opt, unsigned sep,
|
||||
const char *arg, int iso)
|
||||
{
|
||||
int res;
|
||||
char *newarg;
|
||||
char *param;
|
||||
|
||||
if (next_arg(ctx, arg) == -1)
|
||||
return -1;
|
||||
|
||||
param = ctx->argv[ctx->argctr];
|
||||
newarg = malloc(sep + strlen(param) + 1);
|
||||
if (!newarg)
|
||||
return alloc_failed();
|
||||
|
||||
memcpy(newarg, arg, sep);
|
||||
strcpy(newarg + sep, param);
|
||||
res = process_opt(ctx, opt, sep, newarg, iso);
|
||||
free(newarg);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
|
||||
{
|
||||
unsigned sep;
|
||||
const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
|
||||
if (opt) {
|
||||
for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
|
||||
int res;
|
||||
if (sep && opt->templ[sep] == ' ' && !arg[sep])
|
||||
res = process_opt_sep_arg(ctx, opt, sep, arg, iso);
|
||||
else
|
||||
res = process_opt(ctx, opt, sep, arg, iso);
|
||||
if (res == -1)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else
|
||||
return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
|
||||
}
|
||||
|
||||
static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
|
||||
{
|
||||
char *sep;
|
||||
|
||||
do {
|
||||
int res;
|
||||
sep = strchr(opts, ',');
|
||||
if (sep)
|
||||
*sep = '\0';
|
||||
res = process_gopt(ctx, opts, 1);
|
||||
if (res == -1)
|
||||
return -1;
|
||||
opts = sep + 1;
|
||||
} while (sep);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
|
||||
{
|
||||
int res;
|
||||
char *copy;
|
||||
const char *sep = strchr(opts, ',');
|
||||
if (!sep)
|
||||
return process_gopt(ctx, opts, 1);
|
||||
|
||||
copy = strdup(opts);
|
||||
if (!copy) {
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
res = process_real_option_group(ctx, copy);
|
||||
free(copy);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int process_one(struct fuse_opt_context *ctx, const char *arg)
|
||||
{
|
||||
if (ctx->nonopt || arg[0] != '-')
|
||||
return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
|
||||
else if (arg[1] == 'o') {
|
||||
if (arg[2])
|
||||
return process_option_group(ctx, arg + 2);
|
||||
else {
|
||||
if (next_arg(ctx, arg) == -1)
|
||||
return -1;
|
||||
|
||||
return process_option_group(ctx, ctx->argv[ctx->argctr]);
|
||||
}
|
||||
} else if (arg[1] == '-' && !arg[2]) {
|
||||
if (add_arg(ctx, arg) == -1)
|
||||
return -1;
|
||||
ctx->nonopt = ctx->outargs.argc;
|
||||
return 0;
|
||||
} else
|
||||
return process_gopt(ctx, arg, 0);
|
||||
}
|
||||
|
||||
static int opt_parse(struct fuse_opt_context *ctx)
|
||||
{
|
||||
if (ctx->argc) {
|
||||
if (add_arg(ctx, ctx->argv[0]) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
|
||||
if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
|
||||
return -1;
|
||||
|
||||
if (ctx->opts) {
|
||||
if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
|
||||
fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
|
||||
return -1;
|
||||
}
|
||||
if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) {
|
||||
free(ctx->outargs.argv[ctx->outargs.argc - 1]);
|
||||
ctx->outargs.argv[--ctx->outargs.argc] = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_opt_parse(struct fuse_args *args, void *data,
|
||||
const struct fuse_opt opts[], fuse_opt_proc_t proc)
|
||||
{
|
||||
int res;
|
||||
struct fuse_opt_context ctx = {
|
||||
.data = data,
|
||||
.opt = opts,
|
||||
.proc = proc,
|
||||
};
|
||||
|
||||
if (!args || !args->argv || !args->argc)
|
||||
return 0;
|
||||
|
||||
ctx.argc = args->argc;
|
||||
ctx.argv = args->argv;
|
||||
|
||||
res = opt_parse(&ctx);
|
||||
if (res != -1) {
|
||||
struct fuse_args tmp = *args;
|
||||
*args = ctx.outargs;
|
||||
ctx.outargs = tmp;
|
||||
}
|
||||
free(ctx.opts);
|
||||
fuse_opt_free_args(&ctx.outargs);
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "fuse_lowlevel.h"
|
||||
#include "fuse_lowlevel_compat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct fuse_session {
|
||||
struct fuse_session_ops op;
|
||||
|
||||
void *data;
|
||||
|
||||
volatile int exited;
|
||||
|
||||
struct fuse_chan *ch;
|
||||
};
|
||||
|
||||
struct fuse_chan {
|
||||
struct fuse_chan_ops op;
|
||||
|
||||
struct fuse_session *se;
|
||||
|
||||
int fd;
|
||||
|
||||
size_t bufsize;
|
||||
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data)
|
||||
{
|
||||
struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se));
|
||||
if (se == NULL) {
|
||||
fprintf(stderr, "fuse: failed to allocate session\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(se, 0, sizeof(*se));
|
||||
se->op = *op;
|
||||
se->data = data;
|
||||
|
||||
return se;
|
||||
}
|
||||
|
||||
void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch)
|
||||
{
|
||||
assert(se->ch == NULL);
|
||||
assert(ch->se == NULL);
|
||||
se->ch = ch;
|
||||
ch->se = se;
|
||||
}
|
||||
|
||||
void fuse_session_remove_chan(struct fuse_chan *ch)
|
||||
{
|
||||
struct fuse_session *se = ch->se;
|
||||
if (se) {
|
||||
assert(se->ch == ch);
|
||||
se->ch = NULL;
|
||||
ch->se = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct fuse_chan *fuse_session_next_chan(struct fuse_session *se,
|
||||
struct fuse_chan *ch)
|
||||
{
|
||||
assert(ch == NULL || ch == se->ch);
|
||||
if (ch == NULL)
|
||||
return se->ch;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
|
||||
struct fuse_chan *ch)
|
||||
{
|
||||
se->op.process(se->data, buf, len, ch);
|
||||
}
|
||||
|
||||
void fuse_session_destroy(struct fuse_session *se)
|
||||
{
|
||||
if (se->op.destroy)
|
||||
se->op.destroy(se->data);
|
||||
if (se->ch != NULL)
|
||||
fuse_chan_destroy(se->ch);
|
||||
free(se);
|
||||
}
|
||||
|
||||
void fuse_session_exit(struct fuse_session *se)
|
||||
{
|
||||
if (se->op.exit)
|
||||
se->op.exit(se->data, 1);
|
||||
se->exited = 1;
|
||||
}
|
||||
|
||||
void fuse_session_reset(struct fuse_session *se)
|
||||
{
|
||||
if (se->op.exit)
|
||||
se->op.exit(se->data, 0);
|
||||
se->exited = 0;
|
||||
}
|
||||
|
||||
int fuse_session_exited(struct fuse_session *se)
|
||||
{
|
||||
if (se->op.exited)
|
||||
return se->op.exited(se->data);
|
||||
else
|
||||
return se->exited;
|
||||
}
|
||||
|
||||
static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd,
|
||||
size_t bufsize, void *data)
|
||||
{
|
||||
struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
|
||||
if (ch == NULL) {
|
||||
fprintf(stderr, "fuse: failed to allocate channel\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(ch, 0, sizeof(*ch));
|
||||
ch->op = *op;
|
||||
ch->fd = fd;
|
||||
ch->bufsize = bufsize;
|
||||
ch->data = data;
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
|
||||
size_t bufsize, void *data)
|
||||
{
|
||||
return fuse_chan_new_common(op, fd, bufsize, data);
|
||||
}
|
||||
|
||||
int fuse_chan_fd(struct fuse_chan *ch)
|
||||
{
|
||||
return ch->fd;
|
||||
}
|
||||
|
||||
size_t fuse_chan_bufsize(struct fuse_chan *ch)
|
||||
{
|
||||
return ch->bufsize;
|
||||
}
|
||||
|
||||
void *fuse_chan_data(struct fuse_chan *ch)
|
||||
{
|
||||
return ch->data;
|
||||
}
|
||||
|
||||
struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
|
||||
{
|
||||
return ch->se;
|
||||
}
|
||||
|
||||
int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size)
|
||||
{
|
||||
struct fuse_chan *ch = *chp;
|
||||
return ch->op.receive(chp, buf, size);
|
||||
}
|
||||
|
||||
int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count)
|
||||
{
|
||||
return ch->op.send(ch, iov, count);
|
||||
}
|
||||
|
||||
void fuse_chan_destroy(struct fuse_chan *ch)
|
||||
{
|
||||
fuse_session_remove_chan(ch);
|
||||
if (ch->op.destroy)
|
||||
ch->op.destroy(ch);
|
||||
free(ch);
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "fuse_lowlevel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
static struct fuse_session *fuse_instance;
|
||||
|
||||
static void exit_handler(int sig)
|
||||
{
|
||||
(void) sig;
|
||||
if (fuse_instance)
|
||||
fuse_session_exit(fuse_instance);
|
||||
}
|
||||
|
||||
static int set_one_signal_handler(int sig, void (*handler)(int))
|
||||
{
|
||||
struct sigaction sa;
|
||||
struct sigaction old_sa;
|
||||
|
||||
memset(&sa, 0, sizeof(struct sigaction));
|
||||
sa.sa_handler = handler;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
|
||||
if (sigaction(sig, NULL, &old_sa) == -1) {
|
||||
perror("fuse: cannot get old signal handler");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (old_sa.sa_handler == SIG_DFL &&
|
||||
sigaction(sig, &sa, NULL) == -1) {
|
||||
perror("fuse: cannot set signal handler");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_set_signal_handlers(struct fuse_session *se)
|
||||
{
|
||||
if (set_one_signal_handler(SIGHUP, exit_handler) == -1 ||
|
||||
set_one_signal_handler(SIGINT, exit_handler) == -1 ||
|
||||
set_one_signal_handler(SIGTERM, exit_handler) == -1 ||
|
||||
set_one_signal_handler(SIGPIPE, SIG_IGN) == -1)
|
||||
return -1;
|
||||
|
||||
fuse_instance = se;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fuse_remove_signal_handlers(struct fuse_session *se)
|
||||
{
|
||||
if (fuse_instance != se)
|
||||
fprintf(stderr,
|
||||
"fuse: fuse_remove_signal_handlers: unknown session\n");
|
||||
else
|
||||
fuse_instance = NULL;
|
||||
|
||||
set_one_signal_handler(SIGHUP, SIG_DFL);
|
||||
set_one_signal_handler(SIGINT, SIG_DFL);
|
||||
set_one_signal_handler(SIGTERM, SIG_DFL);
|
||||
set_one_signal_handler(SIGPIPE, SIG_DFL);
|
||||
}
|
||||
|
|
@ -0,0 +1,337 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "fuse_i.h"
|
||||
#include "fuse_opt.h"
|
||||
#include "fuse_lowlevel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
enum {
|
||||
KEY_HELP,
|
||||
KEY_HELP_NOHEADER,
|
||||
KEY_VERSION,
|
||||
};
|
||||
|
||||
struct helper_opts {
|
||||
int singlethread;
|
||||
int foreground;
|
||||
int nodefault_subtype;
|
||||
char *mountpoint;
|
||||
};
|
||||
|
||||
#define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 }
|
||||
|
||||
static const struct fuse_opt fuse_helper_opts[] = {
|
||||
FUSE_HELPER_OPT("-d", foreground),
|
||||
FUSE_HELPER_OPT("debug", foreground),
|
||||
FUSE_HELPER_OPT("-f", foreground),
|
||||
FUSE_HELPER_OPT("-s", singlethread),
|
||||
FUSE_HELPER_OPT("fsname=", nodefault_subtype),
|
||||
FUSE_HELPER_OPT("subtype=", nodefault_subtype),
|
||||
|
||||
FUSE_OPT_KEY("-h", KEY_HELP),
|
||||
FUSE_OPT_KEY("--help", KEY_HELP),
|
||||
FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER),
|
||||
FUSE_OPT_KEY("-V", KEY_VERSION),
|
||||
FUSE_OPT_KEY("--version", KEY_VERSION),
|
||||
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_OPT_END
|
||||
};
|
||||
|
||||
static void usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s mountpoint [options]\n\n", progname);
|
||||
fprintf(stderr,
|
||||
"general options:\n"
|
||||
" -o opt,[opt...] mount options\n"
|
||||
" -h --help print help\n"
|
||||
" -V --version print version\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
static void helper_help(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"FUSE options:\n"
|
||||
" -d -o debug enable debug output (implies -f)\n"
|
||||
" -f foreground operation\n"
|
||||
" -s disable multi-threaded operation\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
static void helper_version(void)
|
||||
{
|
||||
fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
|
||||
}
|
||||
|
||||
static int fuse_helper_opt_proc(void *data, const char *arg, int key,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
struct helper_opts *hopts = data;
|
||||
|
||||
switch (key) {
|
||||
case KEY_HELP:
|
||||
usage(outargs->argv[0]);
|
||||
/* fall through */
|
||||
|
||||
case KEY_HELP_NOHEADER:
|
||||
helper_help();
|
||||
return fuse_opt_add_arg(outargs, "-h");
|
||||
|
||||
case KEY_VERSION:
|
||||
helper_version();
|
||||
return 1;
|
||||
|
||||
case FUSE_OPT_KEY_NONOPT:
|
||||
if (!hopts->mountpoint) {
|
||||
char mountpoint[PATH_MAX];
|
||||
if (realpath(arg, mountpoint) == NULL) {
|
||||
fprintf(stderr, "fuse: bad mount point `%s': %s\n", arg, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
|
||||
} else {
|
||||
fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int add_default_subtype(const char *progname, struct fuse_args *args)
|
||||
{
|
||||
int res;
|
||||
char *subtype_opt;
|
||||
const char *basename = strrchr(progname, '/');
|
||||
if (basename == NULL)
|
||||
basename = progname;
|
||||
else if (basename[1] != '\0')
|
||||
basename++;
|
||||
|
||||
subtype_opt = (char *) malloc(strlen(basename) + 64);
|
||||
if (subtype_opt == NULL) {
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
sprintf(subtype_opt, "-osubtype=%s", basename);
|
||||
res = fuse_opt_add_arg(args, subtype_opt);
|
||||
free(subtype_opt);
|
||||
return res;
|
||||
}
|
||||
|
||||
int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
|
||||
int *multithreaded, int *foreground)
|
||||
{
|
||||
int res;
|
||||
struct helper_opts hopts;
|
||||
|
||||
memset(&hopts, 0, sizeof(hopts));
|
||||
res = fuse_opt_parse(args, &hopts, fuse_helper_opts, fuse_helper_opt_proc);
|
||||
if (res == -1)
|
||||
return -1;
|
||||
|
||||
if (!hopts.nodefault_subtype) {
|
||||
res = add_default_subtype(args->argv[0], args);
|
||||
if (res == -1)
|
||||
goto err;
|
||||
}
|
||||
if (mountpoint)
|
||||
*mountpoint = hopts.mountpoint;
|
||||
else
|
||||
free(hopts.mountpoint);
|
||||
|
||||
if (multithreaded)
|
||||
*multithreaded = !hopts.singlethread;
|
||||
if (foreground)
|
||||
*foreground = hopts.foreground;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free(hopts.mountpoint);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fuse_daemonize(int foreground)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!foreground) {
|
||||
res = daemon(0, 0);
|
||||
if (res == -1) {
|
||||
perror("fuse: failed to daemonize program\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fuse_chan *fuse_mount_common(const char *mountpoint,
|
||||
struct fuse_args *args)
|
||||
{
|
||||
struct fuse_chan *ch;
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
|
||||
* would ensue.
|
||||
*/
|
||||
do {
|
||||
fd = open("/dev/null", O_RDWR);
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
} while (fd >= 0 && fd <= 2);
|
||||
|
||||
fd = fuse_kern_mount(mountpoint, args);
|
||||
if (fd == -1)
|
||||
return NULL;
|
||||
|
||||
ch = fuse_kern_chan_new(fd);
|
||||
if (!ch)
|
||||
fuse_kern_unmount(mountpoint, fd);
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args)
|
||||
{
|
||||
return fuse_mount_common(mountpoint, args);
|
||||
}
|
||||
|
||||
static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch)
|
||||
{
|
||||
int fd = ch ? fuse_chan_fd(ch) : -1;
|
||||
fuse_kern_unmount(mountpoint, fd);
|
||||
fuse_chan_destroy(ch);
|
||||
}
|
||||
|
||||
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
|
||||
{
|
||||
fuse_unmount_common(mountpoint, ch);
|
||||
}
|
||||
|
||||
static struct fuse *fuse_setup_common(int argc, char *argv[],
|
||||
const struct fuse_operations *op,
|
||||
size_t op_size,
|
||||
char **mountpoint,
|
||||
int *multithreaded,
|
||||
int *fd,
|
||||
void *user_data)
|
||||
{
|
||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||
struct fuse_chan *ch;
|
||||
struct fuse *fuse;
|
||||
int foreground;
|
||||
int res;
|
||||
|
||||
res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground);
|
||||
if (res == -1)
|
||||
return NULL;
|
||||
|
||||
ch = fuse_mount_common(*mountpoint, &args);
|
||||
if (!ch) {
|
||||
fuse_opt_free_args(&args);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
fuse = fuse_new_common(ch, &args, op, op_size, user_data);
|
||||
fuse_opt_free_args(&args);
|
||||
if (fuse == NULL)
|
||||
goto err_unmount;
|
||||
|
||||
res = fuse_daemonize(foreground);
|
||||
if (res == -1)
|
||||
goto err_unmount;
|
||||
|
||||
res = fuse_set_signal_handlers(fuse_get_session(fuse));
|
||||
if (res == -1)
|
||||
goto err_unmount;
|
||||
|
||||
if (fd)
|
||||
*fd = fuse_chan_fd(ch);
|
||||
|
||||
return fuse;
|
||||
|
||||
err_unmount:
|
||||
fuse_unmount_common(*mountpoint, ch);
|
||||
if (fuse)
|
||||
fuse_destroy(fuse);
|
||||
err_free:
|
||||
free(*mountpoint);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
|
||||
{
|
||||
struct fuse_session *se = fuse_get_session(fuse);
|
||||
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
|
||||
fuse_remove_signal_handlers(se);
|
||||
fuse_unmount_common(mountpoint, ch);
|
||||
fuse_destroy(fuse);
|
||||
free(mountpoint);
|
||||
}
|
||||
|
||||
static int fuse_main_common(int argc, char *argv[],
|
||||
const struct fuse_operations *op, size_t op_size,
|
||||
void *user_data)
|
||||
{
|
||||
struct fuse *fuse;
|
||||
char *mountpoint;
|
||||
int multithreaded;
|
||||
int res;
|
||||
|
||||
fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
|
||||
&multithreaded, NULL, user_data);
|
||||
if (fuse == NULL)
|
||||
return 1;
|
||||
|
||||
if (multithreaded)
|
||||
res = fuse_loop_mt(fuse);
|
||||
else
|
||||
res = fuse_loop(fuse);
|
||||
|
||||
fuse_teardown_common(fuse, mountpoint);
|
||||
if (res == -1)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
|
||||
size_t op_size, void *user_data)
|
||||
{
|
||||
return fuse_main_common(argc, argv, op, op_size, user_data);
|
||||
}
|
||||
|
||||
#undef fuse_main
|
||||
int fuse_main(void);
|
||||
int fuse_main(void)
|
||||
{
|
||||
fprintf(stderr, "fuse_main(): This function does not exist\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fuse_version(void)
|
||||
{
|
||||
return FUSE_VERSION;
|
||||
}
|
||||
|
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "fuse_i.h"
|
||||
#include "fuse_opt.h"
|
||||
#include "mount_util.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#define FUSERMOUNT_PROG "fusermount"
|
||||
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
|
||||
|
||||
#ifndef HAVE_FORK
|
||||
#define fork() vfork()
|
||||
#endif
|
||||
|
||||
#ifndef MS_DIRSYNC
|
||||
#define MS_DIRSYNC 128
|
||||
#endif
|
||||
|
||||
enum {
|
||||
KEY_KERN_FLAG,
|
||||
KEY_KERN_OPT,
|
||||
KEY_FUSERMOUNT_OPT,
|
||||
KEY_SUBTYPE_OPT,
|
||||
KEY_MTAB_OPT,
|
||||
KEY_ALLOW_ROOT,
|
||||
KEY_RO,
|
||||
KEY_HELP,
|
||||
KEY_VERSION,
|
||||
};
|
||||
|
||||
struct mount_opts {
|
||||
int allow_other;
|
||||
int allow_root;
|
||||
int ishelp;
|
||||
int flags;
|
||||
int nonempty;
|
||||
int blkdev;
|
||||
char *fsname;
|
||||
char *subtype;
|
||||
char *subtype_opt;
|
||||
char *mtab_opts;
|
||||
char *fusermount_opts;
|
||||
char *kernel_opts;
|
||||
};
|
||||
|
||||
#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
|
||||
|
||||
static const struct fuse_opt fuse_mount_opts[] = {
|
||||
FUSE_MOUNT_OPT("allow_other", allow_other),
|
||||
FUSE_MOUNT_OPT("allow_root", allow_root),
|
||||
FUSE_MOUNT_OPT("nonempty", nonempty),
|
||||
FUSE_MOUNT_OPT("blkdev", blkdev),
|
||||
FUSE_MOUNT_OPT("fsname=%s", fsname),
|
||||
FUSE_MOUNT_OPT("subtype=%s", subtype),
|
||||
FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
|
||||
FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT),
|
||||
FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
|
||||
FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
|
||||
FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
|
||||
FUSE_OPT_KEY("large_read", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
|
||||
FUSE_OPT_KEY("-r", KEY_RO),
|
||||
FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("dev", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nodev", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("exec", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("noexec", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("async", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("sync", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("atime", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("-h", KEY_HELP),
|
||||
FUSE_OPT_KEY("--help", KEY_HELP),
|
||||
FUSE_OPT_KEY("-V", KEY_VERSION),
|
||||
FUSE_OPT_KEY("--version", KEY_VERSION),
|
||||
FUSE_OPT_END
|
||||
};
|
||||
|
||||
static void mount_help(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
" -o allow_other allow access to other users\n"
|
||||
" -o allow_root allow access to root\n"
|
||||
" -o nonempty allow mounts over non-empty file/dir\n"
|
||||
" -o default_permissions enable permission checking by kernel\n"
|
||||
" -o fsname=NAME set filesystem name\n"
|
||||
" -o subtype=NAME set filesystem type\n"
|
||||
" -o large_read issue large read requests (2.4 only)\n"
|
||||
" -o max_read=N set maximum size of read requests\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
static void exec_fusermount(const char *argv[])
|
||||
{
|
||||
execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
|
||||
execvp(FUSERMOUNT_PROG, (char **) argv);
|
||||
}
|
||||
|
||||
static void mount_version(void)
|
||||
{
|
||||
int pid = fork();
|
||||
if (!pid) {
|
||||
const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
|
||||
exec_fusermount(argv);
|
||||
_exit(1);
|
||||
} else if (pid != -1)
|
||||
waitpid(pid, NULL, 0);
|
||||
}
|
||||
|
||||
struct mount_flags {
|
||||
const char *opt;
|
||||
unsigned long flag;
|
||||
int on;
|
||||
};
|
||||
|
||||
static struct mount_flags mount_flags[] = {
|
||||
{"rw", MS_RDONLY, 0},
|
||||
{"ro", MS_RDONLY, 1},
|
||||
{"suid", MS_NOSUID, 0},
|
||||
{"nosuid", MS_NOSUID, 1},
|
||||
{"dev", MS_NODEV, 0},
|
||||
{"nodev", MS_NODEV, 1},
|
||||
{"exec", MS_NOEXEC, 0},
|
||||
{"noexec", MS_NOEXEC, 1},
|
||||
{"async", MS_SYNCHRONOUS, 0},
|
||||
{"sync", MS_SYNCHRONOUS, 1},
|
||||
{"atime", MS_NOATIME, 0},
|
||||
{"noatime", MS_NOATIME, 1},
|
||||
{"dirsync", MS_DIRSYNC, 1},
|
||||
{NULL, 0, 0}
|
||||
};
|
||||
|
||||
static void set_mount_flag(const char *s, int *flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; mount_flags[i].opt != NULL; i++) {
|
||||
const char *opt = mount_flags[i].opt;
|
||||
if (strcmp(opt, s) == 0) {
|
||||
if (mount_flags[i].on)
|
||||
*flags |= mount_flags[i].flag;
|
||||
else
|
||||
*flags &= ~mount_flags[i].flag;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "fuse: internal error, can't find mount flag\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
static int fuse_mount_opt_proc(void *data, const char *arg, int key,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
struct mount_opts *mo = data;
|
||||
|
||||
switch (key) {
|
||||
case KEY_ALLOW_ROOT:
|
||||
if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
|
||||
fuse_opt_add_arg(outargs, "-oallow_root") == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
case KEY_RO:
|
||||
arg = "ro";
|
||||
/* fall through */
|
||||
case KEY_KERN_FLAG:
|
||||
set_mount_flag(arg, &mo->flags);
|
||||
return 0;
|
||||
|
||||
case KEY_KERN_OPT:
|
||||
return fuse_opt_add_opt(&mo->kernel_opts, arg);
|
||||
|
||||
case KEY_FUSERMOUNT_OPT:
|
||||
return fuse_opt_add_opt(&mo->fusermount_opts, arg);
|
||||
|
||||
case KEY_SUBTYPE_OPT:
|
||||
return fuse_opt_add_opt(&mo->subtype_opt, arg);
|
||||
|
||||
case KEY_MTAB_OPT:
|
||||
return fuse_opt_add_opt(&mo->mtab_opts, arg);
|
||||
|
||||
case KEY_HELP:
|
||||
mount_help();
|
||||
mo->ishelp = 1;
|
||||
break;
|
||||
|
||||
case KEY_VERSION:
|
||||
mount_version();
|
||||
mo->ishelp = 1;
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* return value:
|
||||
* >= 0 => fd
|
||||
* -1 => error
|
||||
*/
|
||||
static int receive_fd(int fd)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
char buf[1];
|
||||
int rv;
|
||||
size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = 1;
|
||||
|
||||
msg.msg_name = 0;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
/* old BSD implementations should use msg_accrights instead of
|
||||
* msg_control; the interface is different. */
|
||||
msg.msg_control = ccmsg;
|
||||
msg.msg_controllen = sizeof(ccmsg);
|
||||
|
||||
while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
|
||||
if (rv == -1) {
|
||||
perror("recvmsg");
|
||||
return -1;
|
||||
}
|
||||
if(!rv) {
|
||||
/* EOF */
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (!cmsg->cmsg_type == SCM_RIGHTS) {
|
||||
fprintf(stderr, "got control message of unknown type %d\n",
|
||||
cmsg->cmsg_type);
|
||||
return -1;
|
||||
}
|
||||
return *(int*)CMSG_DATA(cmsg);
|
||||
}
|
||||
|
||||
void fuse_kern_unmount(const char *mountpoint, int fd)
|
||||
{
|
||||
int res;
|
||||
int pid;
|
||||
|
||||
if (!mountpoint)
|
||||
return;
|
||||
|
||||
if (fd != -1) {
|
||||
struct pollfd pfd;
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = 0;
|
||||
res = poll(&pfd, 1, 0);
|
||||
/* If file poll returns POLLERR on the device file descriptor,
|
||||
then the filesystem is already unmounted */
|
||||
if (res == 1 && (pfd.revents & POLLERR))
|
||||
return;
|
||||
}
|
||||
|
||||
if (geteuid() == 0) {
|
||||
fuse_mnt_umount("fuse", mountpoint, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
res = umount2(mountpoint, 2);
|
||||
if (res == 0)
|
||||
return;
|
||||
|
||||
pid = fork();
|
||||
if(pid == -1)
|
||||
return;
|
||||
|
||||
if(pid == 0) {
|
||||
const char *argv[] =
|
||||
{ FUSERMOUNT_PROG, "-u", "-q", "-z", "--", mountpoint, NULL };
|
||||
|
||||
exec_fusermount(argv);
|
||||
_exit(1);
|
||||
}
|
||||
waitpid(pid, NULL, 0);
|
||||
}
|
||||
|
||||
static int fuse_mount_fusermount(const char *mountpoint, const char *opts,
|
||||
int quiet)
|
||||
{
|
||||
int fds[2], pid;
|
||||
int res;
|
||||
int rv;
|
||||
|
||||
if (!mountpoint) {
|
||||
fprintf(stderr, "fuse: missing mountpoint\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
|
||||
if(res == -1) {
|
||||
perror("fuse: socketpair() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if(pid == -1) {
|
||||
perror("fuse: fork() failed");
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pid == 0) {
|
||||
char env[10];
|
||||
const char *argv[32];
|
||||
int a = 0;
|
||||
|
||||
if (quiet) {
|
||||
int fd = open("/dev/null", O_RDONLY);
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
}
|
||||
|
||||
argv[a++] = FUSERMOUNT_PROG;
|
||||
if (opts) {
|
||||
argv[a++] = "-o";
|
||||
argv[a++] = opts;
|
||||
}
|
||||
argv[a++] = "--";
|
||||
argv[a++] = mountpoint;
|
||||
argv[a++] = NULL;
|
||||
|
||||
close(fds[1]);
|
||||
fcntl(fds[0], F_SETFD, 0);
|
||||
snprintf(env, sizeof(env), "%i", fds[0]);
|
||||
setenv(FUSE_COMMFD_ENV, env, 1);
|
||||
exec_fusermount(argv);
|
||||
perror("fuse: failed to exec fusermount");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
close(fds[0]);
|
||||
rv = receive_fd(fds[1]);
|
||||
close(fds[1]);
|
||||
waitpid(pid, NULL, 0); /* bury zombie */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
|
||||
const char *mnt_opts)
|
||||
{
|
||||
char tmp[128];
|
||||
const char *devname = "/dev/fuse";
|
||||
char *source = NULL;
|
||||
char *type = NULL;
|
||||
struct stat stbuf;
|
||||
int fd;
|
||||
int res;
|
||||
|
||||
if (!mnt) {
|
||||
fprintf(stderr, "fuse: missing mountpoint\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = lstat(mnt, &stbuf);
|
||||
if (res == -1) {
|
||||
fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",
|
||||
mnt, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!mo->nonempty) {
|
||||
res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, stbuf.st_size);
|
||||
if (res == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open(devname, O_RDWR);
|
||||
if (fd == -1) {
|
||||
if (errno == ENODEV || errno == ENOENT)
|
||||
fprintf(stderr,
|
||||
"fuse: device not found, try 'modprobe fuse' first\n");
|
||||
else
|
||||
fprintf(stderr, "fuse: failed to open %s: %s\n", devname,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd,
|
||||
stbuf.st_mode & S_IFMT, getuid(), getgid());
|
||||
|
||||
res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
|
||||
if (res == -1)
|
||||
goto out_close;
|
||||
|
||||
source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
|
||||
(mo->subtype ? strlen(mo->subtype) : 0) +
|
||||
strlen(devname) + 32);
|
||||
|
||||
type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
|
||||
if (!type || !source) {
|
||||
fprintf(stderr, "fuse: failed to allocate memory\n");
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
|
||||
if (mo->subtype) {
|
||||
strcat(type, ".");
|
||||
strcat(type, mo->subtype);
|
||||
}
|
||||
strcpy(source,
|
||||
mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
|
||||
|
||||
res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
|
||||
if (res == -1 && errno == ENODEV && mo->subtype) {
|
||||
/* Probably missing subtype support */
|
||||
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
|
||||
if (mo->fsname) {
|
||||
if (!mo->blkdev)
|
||||
sprintf(source, "%s#%s", mo->subtype, mo->fsname);
|
||||
} else {
|
||||
strcpy(source, type);
|
||||
}
|
||||
res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
|
||||
}
|
||||
if (res == -1) {
|
||||
/*
|
||||
* Maybe kernel doesn't support unprivileged mounts, in this
|
||||
* case try falling back to fusermount
|
||||
*/
|
||||
if (errno == EPERM) {
|
||||
res = -2;
|
||||
} else {
|
||||
int errno_save = errno;
|
||||
if (mo->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
|
||||
fprintf(stderr, "fuse: 'fuseblk' support missing\n");
|
||||
else
|
||||
fprintf(stderr, "fuse: mount failed: %s\n",
|
||||
strerror(errno_save));
|
||||
}
|
||||
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (geteuid() == 0) {
|
||||
char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
|
||||
res = -1;
|
||||
if (!newmnt)
|
||||
goto out_umount;
|
||||
|
||||
res = fuse_mnt_add_mount("fuse", source, newmnt, type, mnt_opts);
|
||||
free(newmnt);
|
||||
if (res == -1)
|
||||
goto out_umount;
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
out_umount:
|
||||
umount2(mnt, 2); /* lazy umount */
|
||||
out_close:
|
||||
free(type);
|
||||
free(source);
|
||||
close(fd);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int get_mnt_flag_opts(char **mnt_optsp, int flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
|
||||
return -1;
|
||||
|
||||
for (i = 0; mount_flags[i].opt != NULL; i++) {
|
||||
if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
|
||||
fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
|
||||
{
|
||||
struct mount_opts mo;
|
||||
int res = -1;
|
||||
char *mnt_opts = NULL;
|
||||
|
||||
memset(&mo, 0, sizeof(mo));
|
||||
mo.flags = MS_NOSUID | MS_NODEV;
|
||||
|
||||
if (args &&
|
||||
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
|
||||
return -1;
|
||||
|
||||
if (mo.allow_other && mo.allow_root) {
|
||||
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
|
||||
goto out;
|
||||
}
|
||||
res = 0;
|
||||
if (mo.ishelp)
|
||||
goto out;
|
||||
|
||||
res = -1;
|
||||
if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
|
||||
goto out;
|
||||
if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
|
||||
goto out;
|
||||
if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
|
||||
goto out;
|
||||
|
||||
res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
|
||||
if (res == -2) {
|
||||
if (mo.fusermount_opts &&
|
||||
fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
|
||||
goto out;
|
||||
|
||||
if (mo.subtype) {
|
||||
char *tmp_opts = NULL;
|
||||
|
||||
res = -1;
|
||||
if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
|
||||
fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {
|
||||
free(tmp_opts);
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = fuse_mount_fusermount(mountpoint, tmp_opts, 1);
|
||||
free(tmp_opts);
|
||||
if (res == -1)
|
||||
res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
|
||||
} else {
|
||||
res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
|
||||
}
|
||||
}
|
||||
out:
|
||||
free(mnt_opts);
|
||||
free(mo.fsname);
|
||||
free(mo.subtype);
|
||||
free(mo.fusermount_opts);
|
||||
free(mo.subtype_opt);
|
||||
free(mo.kernel_opts);
|
||||
free(mo.mtab_opts);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#include "mount_util.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <mntent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
static int mtab_needs_update(const char *mnt)
|
||||
{
|
||||
struct stat stbuf;
|
||||
|
||||
/* If mtab is within new mount, don't touch it */
|
||||
if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
|
||||
_PATH_MOUNTED[strlen(mnt)] == '/')
|
||||
return 0;
|
||||
|
||||
if (lstat(_PATH_MOUNTED, &stbuf) != -1 && S_ISLNK(stbuf.st_mode))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fuse_mnt_add_mount(const char *progname, const char *fsname,
|
||||
const char *mnt, const char *type, const char *opts)
|
||||
{
|
||||
int res;
|
||||
int status;
|
||||
|
||||
if (!mtab_needs_update(mnt))
|
||||
return 0;
|
||||
|
||||
res = fork();
|
||||
if (res == -1) {
|
||||
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (res == 0) {
|
||||
char templ[] = "/tmp/fusermountXXXXXX";
|
||||
char *tmp;
|
||||
|
||||
setuid(geteuid());
|
||||
|
||||
/*
|
||||
* hide in a directory, where mount isn't able to resolve
|
||||
* fsname as a valid path
|
||||
*/
|
||||
tmp = mkdtemp(templ);
|
||||
if (!tmp) {
|
||||
fprintf(stderr, "%s: failed to create temporary directory\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
if (chdir(tmp)) {
|
||||
fprintf(stderr, "%s: failed to chdir to %s: %s\n",
|
||||
progname, tmp, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
rmdir(tmp);
|
||||
execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts,
|
||||
fsname, mnt, NULL);
|
||||
fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", progname,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
res = waitpid(res, &status, 0);
|
||||
if (res == -1) {
|
||||
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (status != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
|
||||
{
|
||||
int res;
|
||||
int status;
|
||||
|
||||
if (!mtab_needs_update(mnt)) {
|
||||
res = umount2(mnt, lazy ? 2 : 0);
|
||||
if (res == -1)
|
||||
fprintf(stderr, "%s: failed to unmount %s: %s\n", progname,
|
||||
mnt, strerror(errno));
|
||||
return res;
|
||||
}
|
||||
|
||||
res = fork();
|
||||
if (res == -1) {
|
||||
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (res == 0) {
|
||||
setuid(geteuid());
|
||||
execl("/bin/umount", "/bin/umount", "-i", mnt, lazy ? "-l" : NULL,
|
||||
NULL);
|
||||
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", progname,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
res = waitpid(res, &status, 0);
|
||||
if (res == -1) {
|
||||
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (status != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *fuse_mnt_resolve_path(const char *progname, const char *orig)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
char *copy;
|
||||
char *dst;
|
||||
char *end;
|
||||
char *lastcomp;
|
||||
const char *toresolv;
|
||||
|
||||
if (!orig[0]) {
|
||||
fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
copy = strdup(orig);
|
||||
if (copy == NULL) {
|
||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
toresolv = copy;
|
||||
lastcomp = NULL;
|
||||
for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
|
||||
if (end[0] != '/') {
|
||||
char *tmp;
|
||||
end[1] = '\0';
|
||||
tmp = strrchr(copy, '/');
|
||||
if (tmp == NULL) {
|
||||
lastcomp = copy;
|
||||
toresolv = ".";
|
||||
} else {
|
||||
lastcomp = tmp + 1;
|
||||
if (tmp == copy)
|
||||
toresolv = "/";
|
||||
}
|
||||
if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
|
||||
lastcomp = NULL;
|
||||
toresolv = copy;
|
||||
}
|
||||
else if (tmp)
|
||||
tmp[0] = '\0';
|
||||
}
|
||||
if (realpath(toresolv, buf) == NULL) {
|
||||
fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
|
||||
strerror(errno));
|
||||
free(copy);
|
||||
return NULL;
|
||||
}
|
||||
if (lastcomp == NULL)
|
||||
dst = strdup(buf);
|
||||
else {
|
||||
dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
|
||||
if (dst) {
|
||||
unsigned buflen = strlen(buf);
|
||||
if (buflen && buf[buflen-1] == '/')
|
||||
sprintf(dst, "%s%s", buf, lastcomp);
|
||||
else
|
||||
sprintf(dst, "%s/%s", buf, lastcomp);
|
||||
}
|
||||
}
|
||||
free(copy);
|
||||
if (dst == NULL)
|
||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||
return dst;
|
||||
}
|
||||
|
||||
int fuse_mnt_check_empty(const char *progname, const char *mnt,
|
||||
mode_t rootmode, off_t rootsize)
|
||||
{
|
||||
int isempty = 1;
|
||||
|
||||
if (S_ISDIR(rootmode)) {
|
||||
struct dirent *ent;
|
||||
DIR *dp = opendir(mnt);
|
||||
if (dp == NULL) {
|
||||
fprintf(stderr, "%s: failed to open mountpoint for reading: %s\n",
|
||||
progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
while ((ent = readdir(dp)) != NULL) {
|
||||
if (strcmp(ent->d_name, ".") != 0 &&
|
||||
strcmp(ent->d_name, "..") != 0) {
|
||||
isempty = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
} else if (rootsize)
|
||||
isempty = 0;
|
||||
|
||||
if (!isempty) {
|
||||
fprintf(stderr, "%s: mountpoint is not empty\n", progname);
|
||||
fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_mnt_check_fuseblk(void)
|
||||
{
|
||||
char buf[256];
|
||||
FILE *f = fopen("/proc/filesystems", "r");
|
||||
if (!f)
|
||||
return 1;
|
||||
|
||||
while (fgets(buf, sizeof(buf), f))
|
||||
if (strstr(buf, "fuseblk\n")) {
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
int fuse_mnt_add_mount(const char *progname, const char *fsname,
|
||||
const char *mnt, const char *type, const char *opts);
|
||||
int fuse_mnt_umount(const char *progname, const char *mnt, int lazy);
|
||||
char *fuse_mnt_resolve_path(const char *progname, const char *orig);
|
||||
int fuse_mnt_check_empty(const char *progname, const char *mnt,
|
||||
mode_t rootmode, off_t rootsize);
|
||||
int fuse_mnt_check_fuseblk(void);
|
|
@ -1,70 +1,75 @@
|
|||
#
|
||||
# Before making a release, the LTVERSION string should be modified.
|
||||
# The string is of the form CURRENT:REVISION:AGE.
|
||||
#
|
||||
# CURRENT (C)
|
||||
# The most recent interface number that this library implements.
|
||||
#
|
||||
# REVISION (R)
|
||||
# The implementation number that this library implements.
|
||||
#
|
||||
# AGE (A)
|
||||
# The difference between the newest and oldest interfaces that this
|
||||
# library implements. In other works, the library implements all the
|
||||
# interface numbers in the range from number 'CURRENT - AGE' to
|
||||
# 'CURRENT'.
|
||||
#
|
||||
# This means that:
|
||||
#
|
||||
# - If interfaces have been changed or added, but binary compatibility has
|
||||
# been preserved, change to C+1:0:A+1
|
||||
#
|
||||
# - If binary compatibility has been broken (eg removed or changed
|
||||
# interfaces) change to C+1:0:0
|
||||
#
|
||||
# - If the interface is the same as the previous version, change to C:R+1:A
|
||||
#
|
||||
|
||||
linux_ntfsincludedir = -I$(top_srcdir)/include/ntfs-3g
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
if INSTALL_LIBRARY
|
||||
lib_LTLIBRARIES = libntfs-3g.la
|
||||
rootlib_LTLIBRARIES=#Create directory
|
||||
lib_LTLIBRARIES = libntfs-3g.la
|
||||
pkgconfig_DATA = libntfs-3g.pc
|
||||
else
|
||||
noinst_LTLIBRARIES = libntfs-3g.la
|
||||
endif
|
||||
|
||||
libntfs_3g_la_LDFLAGS = -version-number $(LIBNTFS_3G_VERSION)
|
||||
libntfs_3g_la_CFLAGS = $(LIBNTFS_3G_CFLAGS)
|
||||
libntfs_3g_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g
|
||||
|
||||
libntfs_3g_la_LDFLAGS = -version-info $(LIBNTFS_3G_VERSION) -no-undefined
|
||||
|
||||
if FUSE_INTERNAL
|
||||
libntfs_3g_la_LIBADD = $(top_srcdir)/libfuse-lite/libfuse-lite.la
|
||||
endif
|
||||
|
||||
libntfs_3g_la_SOURCES = \
|
||||
attrib.c \
|
||||
attrlist.c \
|
||||
bitmap.c \
|
||||
bootsect.c \
|
||||
collate.c \
|
||||
compat.c \
|
||||
compress.c \
|
||||
debug.c \
|
||||
device.c \
|
||||
device_io.c \
|
||||
dir.c \
|
||||
index.c \
|
||||
inode.c \
|
||||
lcnalloc.c \
|
||||
logfile.c \
|
||||
logging.c \
|
||||
mft.c \
|
||||
misc.c \
|
||||
mst.c \
|
||||
runlist.c \
|
||||
security.c \
|
||||
unistr.c \
|
||||
version.c \
|
||||
attrib.c \
|
||||
attrlist.c \
|
||||
bitmap.c \
|
||||
bootsect.c \
|
||||
collate.c \
|
||||
compat.c \
|
||||
compress.c \
|
||||
debug.c \
|
||||
device.c \
|
||||
dir.c \
|
||||
index.c \
|
||||
inode.c \
|
||||
lcnalloc.c \
|
||||
logfile.c \
|
||||
logging.c \
|
||||
mft.c \
|
||||
misc.c \
|
||||
mst.c \
|
||||
runlist.c \
|
||||
security.c \
|
||||
unistr.c \
|
||||
version.c \
|
||||
volume.c
|
||||
|
||||
AM_CPPFLAGS = $(linux_ntfsincludedir) $(all_includes)
|
||||
if NTFS_DEVICE_DEFAULT_IO_OPS
|
||||
if WINDOWS
|
||||
libntfs_3g_la_SOURCES += win32_io.c
|
||||
else
|
||||
libntfs_3g_la_SOURCES += unix_io.c
|
||||
endif
|
||||
endif
|
||||
|
||||
EXTRA_DIST = unix_io.c
|
||||
# We may need to move .so files to root
|
||||
# And create ldscript or symbolic link from /usr
|
||||
install-exec-hook: install-rootlibLTLIBRARIES
|
||||
if INSTALL_LIBRARY
|
||||
if [ "$(rootlibdir)" != "$(libdir)" ]; then \
|
||||
$(MV) -f "$(DESTDIR)/$(libdir)"/libntfs-3g.so* "$(DESTDIR)/$(rootlibdir)"; \
|
||||
fi
|
||||
if GENERATE_LDSCRIPT
|
||||
if [ "$(rootlibdir)" != "$(libdir)" ]; then \
|
||||
$(install_sh_PROGRAM) "libntfs-3g.script.so" "$(DESTDIR)/$(libdir)/libntfs-3g.so"; \
|
||||
fi
|
||||
else
|
||||
if [ "$(rootlibdir)" != "$(libdir)" ]; then \
|
||||
$(LN_S) "$(rootlibdir)/libntfs-3g.so" "$(DESTDIR)/$(libdir)/libntfs-3g.so"; \
|
||||
fi
|
||||
endif
|
||||
endif
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
uninstall-local:
|
||||
if INSTALL_LIBRARY
|
||||
$(RM) -f "$(DESTDIR)/$(rootlibdir)"/libntfs-3g.so*
|
||||
endif
|
||||
|
||||
libs: $(lib_LTLIBRARIES)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libntfs-3g
|
||||
Description: NTFS-3G Read/Write Driver Library
|
||||
Version: @PACKAGE_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs: @LIBFUSE_LITE_LIBS@ -L${libdir} -lntfs-3g
|
|
@ -0,0 +1,2 @@
|
|||
@OUTPUT_FORMAT@
|
||||
GROUP ( @rootlibdir@/libntfs-3g.so )
|
|
@ -1,39 +1,37 @@
|
|||
|
||||
MAINTAINERCLEANFILES=\
|
||||
Makefile.in
|
||||
|
||||
rootbin_PROGRAMS=\
|
||||
ntfs-3g
|
||||
rootsbin_DATA=#Create directory
|
||||
man_MANS=\
|
||||
ntfs-3g.8
|
||||
|
||||
ntfs_3g_LDADD =\
|
||||
$(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
if REALLYSTATIC
|
||||
AM_LIBS = $(top_builddir)/libntfs-3g/.libs/libntfs-3g.a
|
||||
AM_LFLAGS = -static
|
||||
STATIC_LINK = $(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
|
||||
else
|
||||
AM_LIBS = $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
AM_LFLAGS = $(all_libraries)
|
||||
LIBTOOL_LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
|
||||
ntfs_3g_LDFLAGS=\
|
||||
$(AM_LDFLAGS) \
|
||||
-all-static
|
||||
endif
|
||||
ntfs_3g_CFLAGS=\
|
||||
$(AM_CFLAGS) \
|
||||
-DFUSE_USE_VERSION=26 \
|
||||
-I$(top_srcdir)/include/ntfs-3g
|
||||
ntfs_3g_SOURCES=\
|
||||
ntfs-3g.c \
|
||||
utils.c \
|
||||
utils.h
|
||||
if FUSE_INTERNAL
|
||||
ntfs_3g_CFLAGS+=\
|
||||
-I$(top_srcdir)/include/fuse-lite
|
||||
else
|
||||
ntfs_3g_CFLAGS+=\
|
||||
$(FUSE_MODULE_CFLAGS)
|
||||
ntfs_3g_LDADD+=\
|
||||
$(FUSE_MODULE_LIBS)
|
||||
endif
|
||||
|
||||
# Workaround to make REALLYSTATIC work with automake 1.5.
|
||||
LINK=$(STATIC_LINK) $(LIBTOOL_LINK)
|
||||
|
||||
man_MANS = ntfs-3g.8
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
linux_ntfsincludedir = -I$(top_srcdir)/include/ntfs
|
||||
|
||||
bin_PROGRAMS = ntfs-3g
|
||||
|
||||
# Set the include path.
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include/ntfs-3g $(all_includes)
|
||||
|
||||
ntfs_3g_SOURCES = ntfs-3g.c utils.c utils.h
|
||||
ntfs_3g_LDADD = $(AM_LIBS) $(FUSE_MODULE_LIBS) $(libfuse_libs)
|
||||
ntfs_3g_LDFLAGS = $(AM_LFLAGS)
|
||||
ntfs_3g_CFLAGS = $(FUSE_MODULE_CFLAGS) -DFUSE_USE_VERSION=26
|
||||
|
||||
# Extra targets
|
||||
|
||||
strip: $(bin_PROGRAMS)
|
||||
$(STRIP) $^
|
||||
|
||||
libs:
|
||||
(cd ../libntfs-3g && $(MAKE) libs) || exit 1;
|
||||
|
||||
if RUN_LDCONFIG
|
||||
install-exec-hook:
|
||||
|
@ -41,14 +39,13 @@ install-exec-hook:
|
|||
endif
|
||||
|
||||
install-exec-local:
|
||||
$(INSTALL) -d $(DESTDIR)/sbin
|
||||
$(LN_S) -f $(bindir)/ntfs-3g $(DESTDIR)/sbin/mount.ntfs-3g
|
||||
$(INSTALL) -d "$(DESTDIR)$(rootsbindir)"
|
||||
$(LN_S) -f "$(rootbindir)/ntfs-3g" "$(DESTDIR)$(rootsbindir)/mount.ntfs-3g"
|
||||
|
||||
install-data-local:
|
||||
$(INSTALL) -d $(DESTDIR)$(man8dir)
|
||||
$(LN_S) -f ntfs-3g.8 $(DESTDIR)$(man8dir)/mount.ntfs-3g.8
|
||||
$(INSTALL) -d "$(DESTDIR)$(man8dir)"
|
||||
$(LN_S) -f ntfs-3g.8 "$(DESTDIR)$(man8dir)/mount.ntfs-3g.8"
|
||||
|
||||
uninstall-local:
|
||||
$(RM) -f $(DESTDIR)/sbin/mount.ntfs-3g
|
||||
$(RM) -f $(DESTDIR)$(man8dir)/mount.ntfs-3g.8
|
||||
|
||||
$(RM) -f "$(DESTDIR)$(rootsbindir)/mount.ntfs-3g"
|
||||
$(RM) -f "$(DESTDIR)$(man8dir)/mount.ntfs-3g.8"
|
||||
|
|
Loading…
Reference in New Issue