fork usmb 20130204 to susmb - susmb - mounting of SMB/CIFS shares via FUSE
 (HTM) git clone git://git.codemadness.org/susmb
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit af92f1402be85b1819f2ba2dda8cae9ff5381b69
 (DIR) parent aa94e132c12faf1a00f547ea4a96b5728612dea6
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Wed,  5 Mar 2025 19:23:52 +0100
       
       fork usmb 20130204 to susmb
       
       Based off git commit aa94e132c12faf1a00f547ea4a96b5728612dea6
       http://repo.or.cz/w/usmb.git/snapshot/aa94e132c12faf1a00f547ea4a96b5728612dea6.tar.gz
       
       See the README for a summary of the most important changes.
       
       Diffstat:
         D .gitignore                          |      10 ----------
         D INSTALL                             |      35 -------------------------------
         R COPYING -> LICENSE                  |       0 
         A Makefile                            |     102 +++++++++++++++++++++++++++++++
         D Makefile.in                         |     134 -------------------------------
         M README                              |     133 ++++++++++++++++++-------------
         D aclocal.m4                          |     155 -------------------------------
         D conffile.c                          |     237 -------------------------------
         D conffile.h                          |      27 ---------------------------
         D config.rng                          |      48 -------------------------------
         D configure.ac                        |      96 -------------------------------
         D debian/Makefile.pkgdeb              |      43 ------------------------------
         D debian/changelog                    |       5 -----
         D debian/compat                       |       1 -
         D debian/control                      |      29 -----------------------------
         D debian/copyright                    |      25 -------------------------
         D debian/rules                        |       3 ---
         D debian/usmb.docs                    |       2 --
         D install-sh                          |     519 -------------------------------
         D options.c                           |     192 -------------------------------
         D options.h                           |      26 --------------------------
         D password.c                          |      86 ------------------------------
         D password.h                          |      24 ------------------------
         D samba30_compat.c                    |      72 -------------------------------
         D samba32_compat.c                    |      40 -------------------------------
         D samba33_compat.c                    |      49 -------------------------------
         D samba3x-compat.h                    |     283 -------------------------------
         A susmb.1                             |      86 ++++++++++++++++++++++++++++++
         A susmb.c                             |    1377 +++++++++++++++++++++++++++++++
         D usmb.1                              |     156 -------------------------------
         D usmb.c                              |     336 -------------------------------
         D usmb.conf                           |      61 -------------------------------
         D usmb.h                              |      43 ------------------------------
         D usmb_dir.c                          |     217 -------------------------------
         D usmb_dir.h                          |      36 -------------------------------
         D usmb_file.c                         |     339 -------------------------------
         D usmb_file.h                         |      43 ------------------------------
         D utils.c                             |     216 -------------------------------
         D utils.h                             |      47 -------------------------------
         D version.c                           |      72 -------------------------------
         D version.h                           |      25 -------------------------
         D version.m4                          |       5 -----
         D xml.c                               |     187 -------------------------------
         D xml.h                               |      34 -------------------------------
       
       44 files changed, 1642 insertions(+), 4014 deletions(-)
       ---
 (DIR) diff --git a/.gitignore b/.gitignore
       @@ -1,10 +0,0 @@
       -Makefile
       -autom4te.cache
       -config.h
       -config.h.in
       -config.log
       -config.status
       -configure
       -config.rng.h
       -usmb
       -*.o
 (DIR) diff --git a/INSTALL b/INSTALL
       @@ -1,35 +0,0 @@
       -usmb - Unprivileged mounting of SMB/CIFS shares via FUSE
       -========================================================
       -
       -Pre-Requisites
       ---------------
       -
       -glib 2.6 or later - www.gtk.org.
       -libxml2 - ftp.gnome.org.
       -FUSE 2.6 or later - fuse.sourgeforge.net.
       -libsmbclient 3.0 (part of Samba) - www.samba.org.
       -
       -You need GNU sed to build usmb.
       -
       -If you aren't using a usmb release tarball (e.g if you're using a development
       -snapshot or a git clone) then you need a recent (post-2.63) version of GNU
       -autoconf to be installed.
       -
       -
       -Installation
       -------------
       -
       -[ -x ./configure ] || autoreconf
       -./configure
       -make
       -make install   # Maybe as root, depending on your installation prefix.
       -
       -If the configure script says "Cannot find libsmbclient" then use
       ---with-samba=xxx to tell it where Samba is installed.
       -
       -
       -Configuration etc.
       -------------------
       -
       -Please see the README.
       -
 (DIR) diff --git a/COPYING b/LICENSE
 (DIR) diff --git a/Makefile b/Makefile
       @@ -0,0 +1,102 @@
       +.POSIX:
       +
       +NAME = susmb
       +VERSION = 0.9
       +
       +# paths
       +PREFIX = /usr/local
       +MANPREFIX = ${PREFIX}/man
       +DOCPREFIX = ${PREFIX}/share/doc/${NAME}
       +
       +# use system flags.
       +SUSMB_CFLAGS = ${CFLAGS}
       +SUSMB_LDFLAGS = ${LDFLAGS}
       +SUSMB_CPPFLAGS = -D_DEFAULT_SOURCE
       +
       +# test: debug
       +#SUSMB_CFLAGS = -O0 -g -ggdb -Wall -Wextra -pedantic -Wformat-security -Winit-self -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
       +
       +# Linux
       +#SUSMB_CFLAGS += -D_GNU_SOURCE
       +# Linux: use libbsd (arc4random, etc).
       +#SUSMB_LDFLAGS += -lbsd
       +
       +# pkg-config --cflags smbclient
       +SMBCLIENT_CFLAGS = -I/usr/local/include/samba-4.0
       +# Linux:
       +#SMBCLIENT_CFLAGS = -I/usr/include/samba-4.0
       +# pkg-config --libs smbclient
       +SMBCLIENT_LDFLAGS = -L/usr/local/lib -lsmbclient
       +# Linux:
       +#SMBCLIENT_LDFLAGS = -lsmbclient
       +
       +# pkg-config --cflags fuse
       +FUSE_CFLAGS = -I/usr/local/include
       +# Linux:
       +#FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
       +
       +# pkg-config --libs fuse
       +FUSE_LDFLAGS = -lfuse
       +# Linux:
       +#FUSE_LDFLAGS = -lfuse -pthread
       +
       +BIN = ${NAME}
       +SCRIPTS =
       +SRC = ${BIN:=.c}
       +HDR =
       +MAN1 = ${BIN:=.1}\
       +        ${SCRIPTS:=.1}
       +DOC = \
       +        LICENSE\
       +        README
       +
       +all: ${BIN}
       +
       +${BIN}: ${@:=.o}
       +
       +OBJ = ${SRC:.c=.o}
       +
       +${OBJ}: ${HDR}
       +
       +.o:
       +        ${CC} -o $@ $< ${SUSMB_LDFLAGS} ${SMBCLIENT_LDFLAGS} ${FUSE_LDFLAGS} ${SUSMB_LDFLAGS}
       +
       +.c.o:
       +        ${CC} -o $@ -c $< ${SUSMB_CPPFLAGS} ${SMBCLIENT_CFLAGS} ${FUSE_CFLAGS} ${SUSMB_CFLAGS} ${SUSMB_CPPFLAGS}
       +
       +dist:
       +        rm -rf "${NAME}-${VERSION}"
       +        mkdir -p "${NAME}-${VERSION}"
       +        cp -f ${MAN1} ${DOC} ${HDR} ${SCRIPTS} \
       +                ${SRC} Makefile "${NAME}-${VERSION}"
       +        # make tarball
       +        tar cf - "${NAME}-${VERSION}" | gzip -c > "${NAME}-${VERSION}.tar.gz"
       +        rm -rf "${NAME}-${VERSION}"
       +
       +clean:
       +        rm -f ${BIN} ${OBJ}
       +
       +install: all
       +        # installing executable files and scripts.
       +        mkdir -p "${DESTDIR}${PREFIX}/bin"
       +        cp -f ${BIN} ${SCRIPTS} "${DESTDIR}${PREFIX}/bin"
       +        for f in ${BIN} ${SCRIPTS}; do chmod 755 "${DESTDIR}${PREFIX}/bin/$$f"; done
       +        # installing example files.
       +        mkdir -p "${DESTDIR}${DOCPREFIX}"
       +        cp -f ${DOC} "${DESTDIR}${DOCPREFIX}"
       +        for d in ${DOC}; do chmod 644 "${DESTDIR}${DOCPREFIX}/$$d"; done
       +        # installing manual pages for general commands: section 1.
       +        mkdir -p "${DESTDIR}${MANPREFIX}/man1"
       +        cp -f ${MAN1} "${DESTDIR}${MANPREFIX}/man1"
       +        for m in ${MAN1}; do chmod 644 "${DESTDIR}${MANPREFIX}/man1/$$m"; done
       +
       +uninstall:
       +        # removing executable files and scripts.
       +        for f in ${BIN} ${SCRIPTS}; do rm -f "${DESTDIR}${PREFIX}/bin/$$f"; done
       +        # removing example files.
       +        for d in ${DOC}; do rm -f "${DESTDIR}${DOCPREFIX}/$$d"; done
       +        -rmdir "${DESTDIR}${DOCPREFIX}"
       +        # removing manual pages.
       +        for m in ${MAN1}; do rm -f "${DESTDIR}${MANPREFIX}/man1/$$m"; done
       +
       +.PHONY: all clean dist install uninstall
 (DIR) diff --git a/Makefile.in b/Makefile.in
       @@ -1,134 +0,0 @@
       -# usmb - mount SMB shares via FUSE and Samba
       -#
       -# @configure_input@
       -#
       -# Copyright (C) 2006-2013 Geoff Johnstone
       -#
       -# This program is free software; you can redistribute it and/or modify
       -# it under the terms of the GNU General Public License version 3 as
       -# published by the Free Software Foundation.
       -#
       -# This program is distributed in the hope that it will be useful,
       -# but WITHOUT ANY WARRANTY; without even the implied warranty of
       -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       -# GNU General Public License for more details.
       -#
       -# You should have received a copy of the GNU General Public License
       -# along with this program.  If not, see <http://www.gnu.org/licenses/>.
       -
       -CC = @CC@
       -
       -prefix = ${DESTDIR}@prefix@
       -exec_prefix = @exec_prefix@
       -bindir = @bindir@
       -datarootdir = @datarootdir@
       -mandir = @mandir@
       -man1dir = $(mandir)/man1
       -
       -CFLAGS = @CFLAGS@ -I@srcdir@ -I@builddir@ -Werror
       -LDFLAGS = @LDFLAGS@
       -LIBS = @LIBS@
       -
       -CFLAGS  += @LIBXML2_CFLAGS@ @GLIB_CFLAGS@ @FUSE_CFLAGS@
       -LIBS  += @LIBXML2_LIBS@ @GLIB_LIBS@ @FUSE_LIBS@
       -
       -SOURCES = conffile.c options.c password.c usmb.c usmb_dir.c usmb_file.c \
       -          utils.c version.c xml.c samba@SAMBA_VERSION@_compat.c
       -OBJECTS = $(SOURCES:.c=.o)
       -
       -PROGRAM = @PACKAGE_NAME@
       -MANPAGE = $(PROGRAM).1
       -
       -
       -all: $(PROGRAM)
       -
       -
       -$(PROGRAM): $(OBJECTS)
       -        $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
       -
       -
       -clean:
       -        $(RM) $(PROGRAM) $(OBJECTS)
       -
       -
       -distclean: clean
       -        $(RM) -r core usmb-*.tar.bz2 usmb-*.tar.gz doc/*.mdzip.bak config.rng.h \
       -           autom4te.cache config.h.in~ config.status config.log config.h \
       -           Makefile
       -
       -
       -allclean: distclean
       -        $(RM) configure config.h.in autom4te.cache
       -
       -
       -install-strip: STRIPFLAGS = -s
       -install install-strip: $(PROGRAM)
       -        @MKDIR_P@ $(bindir) $(man1dir)
       -        @INSTALL@ -m 755 $(STRIPFLAGS) $(PROGRAM) $(bindir)/
       -        @INSTALL@ -m 644 $(MANPAGE) $(man1dir)/
       -
       -
       -uninstall:
       -        $(RM) $(bindir)/$(PROGRAM) $(man1dir)/$(MANPAGE)
       -        rmdir -p $(bindir) $(man1dir)
       -        @echo Please delete ~/.usmb.conf manually.
       -
       -
       -dist: tar
       -
       -
       -PACKAGE = @PACKAGE_NAME@
       -ifeq ($(SNAPSHOT),)
       -  VERSION = @PACKAGE_VERSION@
       -  ARCHIVE = $(VERSION)
       -else
       -  ARCHIVE = $(shell git show $(SNAPSHOT) '--pretty=format:%h' | head -n1 )
       -  VERSION = $(shell date -ud "$(shell git show $(SNAPSHOT) '--pretty=format:%cD' | head -n1 )" "+%Y%m%d%H%M%S")~$(ARCHIVE)
       -endif
       -
       -
       -tar: STAGING=/tmp/usmb-$(VERSION)
       -tar:
       -        mkdir $(STAGING)
       -        git archive $(ARCHIVE) | tar -C $(STAGING) -x -f -
       -        git log > $(STAGING)/Changelog
       -        (cd $(STAGING) && \
       -         autoreconf && \
       -         rm -rf autom4te.cache)
       -        (cd $(STAGING)/.. && \
       -         tar jcf $(PWD)/$(PACKAGE)-$(VERSION).tar.bz2 $(PACKAGE)-$(VERSION) && \
       -         tar zcf $(PWD)/$(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)-$(VERSION))
       -        rm -rf $(STAGING)
       -
       -include debian/Makefile.pkgdeb
       -
       -
       -config.rng.h: @srcdir@/config.rng
       -        @SED@ -e 's/"/\\"/g' -e 's/\(.*\)/  "\1" \\/' \
       -    -e '1istatic const char *rng_$(@:.rng.h=) =' $^ > config.rng.h
       -        echo '  "";' >> config.rng.h
       -
       -
       -%.o: @srcdir@/%.c
       -        $(CC) $(CFLAGS) -c -o $@ $<
       -
       -
       -.PHONY: all debug dist install install-strip uninstall clean distclean tar
       -
       -conffile.o: @srcdir@/conffile.c @srcdir@/utils.h @srcdir@/xml.h \
       -            @builddir@/config.rng.h
       -options.o: @srcdir@/options.c @srcdir@/options.h @srcdir@/utils.h \
       -           @srcdir@/version.h
       -password.o: @srcdir@/password.c @srcdir@/password.h @srcdir@/utils.h
       -usmb.o: @srcdir@/usmb.c @srcdir@/conffile.h @srcdir@/options.h \
       -        @srcdir@/usmb.h @srcdir@/usmb_dir.h @srcdir@/usmb_file.h \
       -                                @srcdir@/utils.h @srcdir@/password.h @srcdir@/version.h \
       -                                @srcdir@/samba3x-compat.h
       -usmb_dir.o: @srcdir@/samba3x-compat.h @srcdir@/usmb_dir.c @srcdir@/usmb_dir.h \
       -            @srcdir@/usmb.h @srcdir@/utils.h
       -usmb_file.o: @srcdir@/samba3x-compat.h @srcdir@/usmb_file.c \
       -             @srcdir@/usmb_file.h @srcdir@/usmb.h @srcdir@/utils.h
       -utils.o: @srcdir@/utils.c @srcdir@/utils.h
       -version.o: @srcdir@/version.c @srcdir@/version.h
       -xml.o: @srcdir@/xml.c @srcdir@/xml.h @srcdir@/utils.h
       -
 (DIR) diff --git a/README b/README
       @@ -1,26 +1,10 @@
       -usmb - Unprivileged mounting of SMB/CIFS shares via FUSE
       -========================================================
       -
       -Acknowledgements
       -----------------
       -
       -Jonathan Schultz (Email <firstname> at imatix.com) provided a patch
       -to fix the display of file modification times.
       -
       -Stijn Hoop (Email <firstname> at sandcat.nl) provided a patch to fix
       -a compilation problem on 64-bit platforms.
       -
       -Nigel Smith (Email me at <firstname>.<surname>.name) contributed the
       -port to Samba 3.2.
       -
       -Michal Suchanek (Email hramrach at centrum dot cz) contributed the
       -Debian packaging and the initial implementation of ~-expansion.
       -
       +susmb - Unprivileged mounting of SMB/CIFS shares via FUSE
       +=========================================================
        
        Introduction
        ------------
        
       -usmb lets you mount SMB/CIFS shares via FUSE, in the vein of the Map Network
       +susmb lets you mount SMB/CIFS shares via FUSE, in the vein of the Map Network
        Drive functionality in Windows.
        
        The two existing FUSE filesystems that I know of (SMB for FUSE and fusesmb)
       @@ -46,56 +30,93 @@ in/out of the user process' context. Mitigating factors are:
        4. The client filesystem code can be upgraded/fixed without kernel changes.
        
        
       -Pre-Requisites and Installation
       --------------------------------
       -
       -Please see INSTALL.
       -
       +Dependencies
       +------------
        
       -Configuration
       --------------
       +- FUSE 2.6 or later (and probably <3).
       +- libsmbclient 4.20+ (part of Samba) - www.samba.org (samba 3.3+ required).
        
       -You need an XML configuration file - ${HOME}/.usmb.conf by default. There's an
       -example in usmb.conf.
        
       -There are two main elements: credentials and mounts.
       +Installation
       +------------
        
       -Credentials:
       +make
       +make install   # Maybe as root, depending on your installation prefix.
        
       -  <credentials id="some_id">
       -    <domain>mydomain</domain>
       -    <username>username</username>
       -    <password>password</password>
       -  </credentials>
        
       -Each credentials element gives authentication details. You can have multiple
       -credentials elements; each must have a distinct id attribute. If you omit
       -the <password> element then usmb will prompt you for a password.
       +Configuration and usage
       +-----------------------
        
       -A mount element describes an SMB share:
       +See the man page.
        
       -  <mount id="mount_id" credentials="some_id">
       -    <server>1.2.3.4</server>
       -    <share>sharename</share>
       -    <mountpoint>/tmp/share</mountpoint>
       -  </mount>
        
       -The credentials attribute identifies the id of the credentials element that
       -provides authentication details for the share. The server, share and
       -mountpoint should be self-explanatory. The id is given on the usmb command
       -line to identify the SMB share to mount.
       +Acknowledgements
       +----------------
        
       -You can specify multiple mount elements; each must have a distinct id
       -(though credentials and mount IDs can be the same).
       +Geoff Johnstone, the main author of the original usmb program.
        
       -The whole file is wrapped in a <usmbconfig> element.
       +Jonathan Schultz (Email <firstname> at imatix.com) provided a patch
       +to fix the display of file modification times.
        
       +Stijn Hoop (Email <firstname> at sandcat.nl) provided a patch to fix
       +a compilation problem on 64-bit platforms.
        
       -Usage
       ------
       +Nigel Smith (Email me at <firstname>.<surname>.name) contributed the
       +port to Samba 3.2.
        
       -$ usmb [options] mount_ID
       +Michal Suchanek (Email hramrach at centrum dot cz) contributed the
       +Debian packaging and the initial implementation of ~-expansion.
        
       -Use usmb --help for a list of options.
       -Mount IDs are defined in the configuration file.
        
       +Changes
       +-------
       +
       +This is a fork of usmb 20130204
       +http://repo.or.cz/w/usmb.git/snapshot/aa94e132c12faf1a00f547ea4a96b5728612dea6.tar.gz
       +(git commit aa94e132c12faf1a00f547ea4a96b5728612dea6)
       +
       +It has the patches applied from OpenBSD ports 7.6:
       +https://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/sysutils/usmb/
       +
       +It is mainly tested on OpenBSD (Linux has a SMB/CIFS driver anyway).
       +
       +Below is a summary of the most important changes:
       +
       +Performance:
       +
       +- Set struct stat st.st_blksiz to a higher number for more efficient buffering
       +  for programs using the standard FILE* stdio interfaces. Huge improvement for
       +  reads and writes.
       +  On OpenBSD the default block size for FUSE is 512 bytes.
       +  This cripples network performance.
       +  On OpenBSD there is no FUSE caching layer, so each read call had more overhead.
       +- Remove the hardcoded FUSE mount option max_read=N.
       +  This cripples network performance.
       +
       +
       +Security:
       +- Many code simplifications and deletions (attack surface and easier to review).
       +- Use unveil(2) syscall to lock down much of the filesystem except the
       +  mountpoint and required FUSE devices.
       +- Optional priviledge dropping support: on OpenBSD FUSE would need to run as root:
       +  (sysctl kern.usermount was removed around July 2016, around
       +  commit 65c8a8a0394483b41de8f02c862e65fb529cf538).
       +  After mounting the filesystem and acquiring access to the FUSE driver
       +  priviledges are dropped. This is not perfect, but at least now the Samba smbclient
       +  code runs as a user again.
       +- Remove support for reading the password from the terminal. This can be
       +  insecure and caused issues when running as a daemon and the network credentials
       +  changed.
       +
       +
       +Cleanups:
       +- Merge everything into one C file for easier code review.
       +- Remove Samba < 3.3 compatibility layer and code. This is hard to test nowadays anyway.
       +- Use getopt for option parsing: remove dependences on glib which was used for
       +  option parsing only.
       +  Remove long option support.
       +- Remove libxml2 dependency and configuration via XML. Configuration is now done via a
       +  simpler syntax as a URI from the command-line. This was also listed in the
       +  man page under the BUGS section as a wanted feature.
       +- Remove autoconf and files specific to Debian packaging. Use a simple Makefile.
       +- Man page rewritten from roff to mandoc.
 (DIR) diff --git a/aclocal.m4 b/aclocal.m4
       @@ -1,155 +0,0 @@
       -# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
       -# 
       -# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
       -#
       -# This program is free software; you can redistribute it and/or modify
       -# it under the terms of the GNU General Public License as published by
       -# the Free Software Foundation; either version 2 of the License, or
       -# (at your option) any later version.
       -#
       -# This program is distributed in the hope that it will be useful, but
       -# WITHOUT ANY WARRANTY; without even the implied warranty of
       -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       -# General Public License for more details.
       -#
       -# You should have received a copy of the GNU General Public License
       -# along with this program; if not, write to the Free Software
       -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
       -#
       -# As a special exception to the GNU General Public License, if you
       -# distribute this file as part of a program that contains a
       -# configuration script generated by Autoconf, you may include it under
       -# the same distribution terms that you use for the rest of that program.
       -
       -# PKG_PROG_PKG_CONFIG([MIN-VERSION])
       -# ----------------------------------
       -AC_DEFUN([PKG_PROG_PKG_CONFIG],
       -[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
       -m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
       -AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
       -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
       -        AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
       -fi
       -if test -n "$PKG_CONFIG"; then
       -        _pkg_min_version=m4_default([$1], [0.9.0])
       -        AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
       -        if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
       -                AC_MSG_RESULT([yes])
       -        else
       -                AC_MSG_RESULT([no])
       -                PKG_CONFIG=""
       -        fi
       -                
       -fi[]dnl
       -])# PKG_PROG_PKG_CONFIG
       -
       -# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
       -#
       -# Check to see whether a particular set of modules exists.  Similar
       -# to PKG_CHECK_MODULES(), but does not set variables or print errors.
       -#
       -#
       -# Similar to PKG_CHECK_MODULES, make sure that the first instance of
       -# this or PKG_CHECK_MODULES is called, or make sure to call
       -# PKG_CHECK_EXISTS manually
       -# --------------------------------------------------------------
       -AC_DEFUN([PKG_CHECK_EXISTS],
       -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
       -if test -n "$PKG_CONFIG" && \
       -    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
       -  m4_ifval([$2], [$2], [:])
       -m4_ifvaln([$3], [else
       -  $3])dnl
       -fi])
       -
       -
       -# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
       -# ---------------------------------------------
       -m4_define([_PKG_CONFIG],
       -[if test -n "$$1"; then
       -    pkg_cv_[]$1="$$1"
       - elif test -n "$PKG_CONFIG"; then
       -    PKG_CHECK_EXISTS([$3],
       -                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
       -                     [pkg_failed=yes])
       - else
       -    pkg_failed=untried
       -fi[]dnl
       -])# _PKG_CONFIG
       -
       -# _PKG_SHORT_ERRORS_SUPPORTED
       -# -----------------------------
       -AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
       -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
       -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
       -        _pkg_short_errors_supported=yes
       -else
       -        _pkg_short_errors_supported=no
       -fi[]dnl
       -])# _PKG_SHORT_ERRORS_SUPPORTED
       -
       -
       -# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
       -# [ACTION-IF-NOT-FOUND])
       -#
       -#
       -# Note that if there is a possibility the first call to
       -# PKG_CHECK_MODULES might not happen, you should be sure to include an
       -# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
       -#
       -#
       -# --------------------------------------------------------------
       -AC_DEFUN([PKG_CHECK_MODULES],
       -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
       -AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
       -AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
       -
       -pkg_failed=no
       -AC_MSG_CHECKING([for $1])
       -
       -_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
       -_PKG_CONFIG([$1][_LIBS], [libs], [$2])
       -
       -m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
       -and $1[]_LIBS to avoid the need to call pkg-config.
       -See the pkg-config man page for more details.])
       -
       -if test $pkg_failed = yes; then
       -        _PKG_SHORT_ERRORS_SUPPORTED
       -        if test $_pkg_short_errors_supported = yes; then
       -                $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1`
       -        else 
       -                $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1`
       -        fi
       -        # Put the nasty error message in config.log where it belongs
       -        echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
       -
       -        ifelse([$4], , [AC_MSG_ERROR(dnl
       -[Package requirements ($2) were not met:
       -
       -$$1_PKG_ERRORS
       -
       -Consider adjusting the PKG_CONFIG_PATH environment variable if you
       -installed software in a non-standard prefix.
       -
       -_PKG_TEXT
       -])],
       -                [AC_MSG_RESULT([no])
       -                $4])
       -elif test $pkg_failed = untried; then
       -        ifelse([$4], , [AC_MSG_FAILURE(dnl
       -[The pkg-config script could not be found or is too old.  Make sure it
       -is in your PATH or set the PKG_CONFIG environment variable to the full
       -path to pkg-config.
       -
       -_PKG_TEXT
       -
       -To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
       -                [$4])
       -else
       -        $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
       -        $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
       -        AC_MSG_RESULT([yes])
       -        ifelse([$3], , :, [$3])
       -fi[]dnl
       -])# PKG_CHECK_MODULES
 (DIR) diff --git a/conffile.c b/conffile.c
       @@ -1,237 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2013 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <assert.h>
       -#include <errno.h>
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include <string.h>
       -#include <sys/types.h>
       -#include <sys/stat.h>
       -#include <fcntl.h>
       -#include <pwd.h>
       -#include <unistd.h>
       -#include "utils.h"
       -#include "xml.h"
       -#include "conffile.h"
       -#include "config.rng.h"
       -
       -
       -static bool check_conf_perms (const char *conffile, int fd)
       -{
       -  struct stat buf;
       -
       -  if (0 == fstat (fd, &buf))
       -  {
       -    if (getuid() != buf.st_uid)
       -    {
       -      fprintf (stderr, "You do not own the configuration file %s.\n", conffile);
       -      return false;
       -    }
       -
       -    if (buf.st_mode & (S_IRWXG | S_IRWXO))
       -    {
       -      fprintf (stderr, "Configuration file %s is accessible to non-owner.\n",
       -               conffile);
       -      return false;
       -    }
       -  }
       -
       -  else
       -  {
       -    fprintf (stderr, "Cannot stat configuration file %s: %s.\n",
       -             conffile, strerror (errno));
       -    return false;
       -  }
       -
       -  return true;
       -}
       -
       -
       -static bool conffile_read (const char *filename,
       -                           xmlDocPtr *doc,
       -                           xmlXPathContextPtr *ctx)
       -{
       -  int fd = open (filename, O_RDONLY);
       -  if (-1 == fd)
       -  {
       -    fprintf (stderr, "Cannot open %s: %s.\n", filename, strerror (errno));
       -    return false;
       -  }
       -
       -  if (!check_conf_perms (filename, fd))
       -  {
       -    (void)close (fd);
       -    return false;
       -  }
       -
       -  *doc = xmlReadFd (fd, NULL, NULL, XML_PARSE_NONET);
       -  (void)close (fd);
       -
       -  if (NULL == *doc)
       -  {
       -    fprintf (stderr, "Cannot parse %s.\n", filename);
       -    return false;
       -  }
       -
       -  if (!xml_validate_relaxng (*doc, rng_config))
       -  {
       -    fprintf (stderr, "%s isn't a valid USMB configuration.\n", filename);
       -    xmlFreeDoc (*doc);
       -    return false;
       -  }
       -
       -  *ctx = xmlXPathNewContext (*doc);
       -  if (NULL == *ctx)
       -  {
       -    fputs ("Cannot create XPath context.\n", stderr);
       -    xmlFreeDoc (*doc);
       -    return false;
       -  }
       -
       -  return true;
       -}
       -
       -
       -static bool do_xpath_text (xmlXPathContextPtr ctx,
       -                           const char *parent, const char *id,
       -                           const char *child, char **out)
       -{
       -  char xpath[2048];
       -
       -  if (!bsnprintf (xpath, sizeof (xpath),
       -                  "/usmbconfig/%s[@id='%s']/%s/text()", parent, id, child))
       -    return false;
       -
       -  return xml_xpath_text (ctx, xpath, (void *)out);
       -}
       -
       -
       -// Expand ~ in *mountpoint.
       -static bool expand_tilde (char **mountpoint)
       -{
       -  assert (NULL != mountpoint);
       -  assert (NULL != *mountpoint);
       -
       -  if ('~' != **mountpoint)
       -    return true;
       -
       -  // Extract the username.
       -  char * const username = (*mountpoint) + 1;
       -  char * const end = strchr (username, '/');
       -
       -  const char *dir = NULL;
       -
       -  if (('\0' == *username) || (end == username))  // No username => use HOME.
       -  {
       -    dir = getenv ("HOME");
       -  }
       -  else  // Else look up the user's home directory.
       -  {
       -    if (NULL != end)
       -      *end = '\0';
       -
       -    struct passwd * const pwd = getpwnam (username);
       -    if (NULL != pwd)
       -      dir = pwd->pw_dir;
       -
       -    if (NULL != end)
       -      *end = '/';
       -  }
       -
       -  if (NULL == dir)
       -  {
       -    fputs ("Failed to expand tilde in mount point.\n", stderr);
       -    return false;
       -  }
       -
       -  char *result;
       -  if (!baprintf (&result, "%s%s", dir, (NULL == end) ? "" : end))
       -  {
       -    perror ("Failed to expand tilde in mount point");
       -    return false;
       -  }
       -
       -  free (*mountpoint);
       -  *mountpoint = result;
       -  return true;
       -}
       -
       -
       -bool conffile_get_mount (const char *filename, const char *key,
       -                         char **server, char **share,
       -                         char **mountpoint, char **options,
       -                         char **domain, char **username,
       -                         char **password)
       -{
       -  xmlDocPtr doc;
       -  xmlXPathContextPtr ctx;
       -  char xp[2048];
       -  char *creds = NULL;
       -
       -  *server = *share = *mountpoint = *options = NULL;
       -  *domain = *username = *password = NULL;
       -
       -  if (strchr (key, '\''))
       -  {
       -    fprintf (stderr, "Invalid share name: %s.\n", key);
       -    return false;
       -  }
       -
       -  if (!conffile_read (filename, &doc, &ctx))
       -    return false;
       -
       -  do {
       -    if (!do_xpath_text (ctx, "mount", key, "server", server)) break;
       -    if (!do_xpath_text (ctx, "mount", key, "share", share)) break;
       -    if (!do_xpath_text (ctx, "mount", key, "mountpoint", mountpoint)) break;
       -    if (!expand_tilde (mountpoint)) break;
       -    (void)do_xpath_text (ctx, "mount", key, "options", options);
       -
       -    if (!snprintf (xp, sizeof (xp), "/usmbconfig/mount[@id='%s']", key)) break;
       -    if (!xml_xpath_attr_value (ctx, xp, "credentials", &creds)) break;
       -
       -    (void)do_xpath_text (ctx, "credentials", creds, "domain", domain);
       -    if (!do_xpath_text (ctx, "credentials", creds, "username", username)) break;
       -
       -    if (!do_xpath_text (ctx, "credentials", creds, "password", password))
       -      *password = NULL;
       -
       -    xmlXPathFreeContext (ctx);
       -    xmlFreeDoc (doc);
       -
       -    return true;
       -    /*NOTREACHED*/
       -  } while (false /*CONSTCOND*/);
       -
       -  fputs ("Invalid configuration.\n", stderr);
       -
       -  xfree (*username);
       -  clear_and_free (*password);
       -  xfree (*domain);
       -  xfree (creds);
       -  xfree (*options);
       -  xfree (*mountpoint);
       -  xfree (*share);
       -  xfree (*server);
       -
       -  xmlXPathFreeContext (ctx);
       -  xmlFreeDoc (doc);
       -
       -  return false;
       -}
       -
 (DIR) diff --git a/conffile.h b/conffile.h
       @@ -1,27 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#ifndef CONFFILE_H
       -  #define CONFFILE_H
       -
       -  #include <stdbool.h>
       -
       -  bool conffile_get_mount (const char *filename, const char *key,
       -                           char **server, char **share,
       -                           char **mountpoint, char **options,
       -                           char **domain, char **username,
       -                           char **password) MUSTCHECK;
       -#endif
 (DIR) diff --git a/config.rng b/config.rng
       @@ -1,48 +0,0 @@
       -<grammar xmlns="http://relaxng.org/ns/structure/1.0">
       -
       -  <start>
       -    <ref name="usmbconfig" />
       -  </start>
       -
       -
       -  <define name="usmbconfig">
       -    <element name="usmbconfig">
       -      <zeroOrMore>
       -        <choice>
       -          <ref name="credentials" />
       -          <ref name="mount" />
       -        </choice>
       -      </zeroOrMore>
       -    </element>
       -  </define>
       -
       -
       -  <define name="credentials">
       -    <element name="credentials">
       -      <attribute name="id" />
       -      <optional>
       -        <element name="domain"> <text /> </element>
       -      </optional>
       -      <element name="username"> <text /> </element>
       -      <optional>
       -        <element name="password"> <text /> </element>
       -      </optional>
       -    </element>
       -  </define>
       -
       -
       -  <define name="mount">
       -    <element name="mount">
       -      <attribute name="id" />
       -      <attribute name="credentials" />
       -      <element name="server"> <text /> </element>
       -      <element name="share"> <text /> </element>
       -      <element name="mountpoint"> <text /> </element>
       -      <optional>
       -        <element name="options"> <text /> </element>
       -      </optional>
       -    </element>
       -  </define>
       -
       -</grammar>
       -
 (DIR) diff --git a/configure.ac b/configure.ac
       @@ -1,96 +0,0 @@
       -m4_include([version.m4])
       -
       -AC_PREREQ([2.63])
       -AC_INIT([usmb], VERSION_)
       -AC_CONFIG_SRCDIR([usmb.c])
       -AC_CONFIG_HEADERS([config.h])
       -
       -AC_DEFINE([USMB_VERSION],[0x]VERSION_,[usmb version])
       -AC_DEFINE([USMB_VERSION_STATUS],'[VERSION_STATUS_]',[Version status])
       -
       -AC_ARG_ENABLE([debug],
       -              [AS_HELP_STRING([--enable-debug],
       -                              [Build in debug mode (default no)])],
       -              [AC_DEFINE([DEBUG], [], [Define to build in debug mode])])
       -
       -AC_ARG_WITH([samba],
       -            [AS_HELP_STRING([--with-samba=prefix],
       -                              [Location of Samba (i.e. libsmbclient)])],
       -            [if test no = $withval ; then
       -               AC_MSG_ERROR(Samba is required for building AC_PACKAGE_NAME)
       -             else
       -               CFLAGS="$CFLAGS -I$withval/include"
       -               LDFLAGS="$LDFLAGS -L$withval/lib"
       -             fi])
       -
       -# Checks for programs.
       -AC_PROG_CC_C99([gcc])
       -AC_PROG_INSTALL
       -AC_PROG_MKDIR_P
       -AC_PROG_SED
       -
       -AC_DEFINE([_BSD_SOURCE], [], [Define to use BSD APIs (mandatory)])
       -AC_DEFINE([FUSE_USE_VERSION], [26], [Required FUSE API version])
       -
       -m4_define([UNUSED_],[])
       -m4_define([MUSTCHECK_],[])
       -
       -if test "$GCC" = yes ; then
       -  m4_define([UNUSED_], [__attribute__ ((unused))])
       -  m4_define([MUSTCHECK_], [__attribute__ ((warn_unused_result))])
       -  CFLAGS="$CFLAGS -Wall -Wextra -pedantic -Wformat-security -Winit-self -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations"
       -fi
       -
       -AC_DEFINE([UNUSED], [UNUSED_], [Marks unused parameters])
       -AC_DEFINE([MUSTCHECK], [MUSTCHECK_],
       -          [Marks functions whose result values must not be ignored])
       -
       -# Checks for libraries.
       -AC_CHECK_LIB([smbclient], [smbc_init], [],
       -             [AC_MSG_ERROR(Cannot find libsmbclient.)])
       -
       -AC_CHECK_LIB([smbclient], [smbc_getFunctionStatVFS],
       -             [AC_DEFINE([HAVE_SAMBA33], [],
       -              [Whether we have Samba 3.3 or later])
       -              SAMBA_VERSION=33])
       -
       -AC_CHECK_LIB([smbclient], [smbc_getFunctionOpen],
       -             [AC_DEFINE([HAVE_SAMBA32], [],
       -              [Whether we have Samba 3.2 or later])
       -              if test "$SAMBA_VERSION" = "" ; then
       -                SAMBA_VERSION=32
       -              fi])
       -
       -if test "$SAMBA_VERSION" = '' ; then
       -  SAMBA_VERSION=30
       -fi
       -
       -AC_SUBST(SAMBA_VERSION,[$SAMBA_VERSION])
       -
       -PKG_PROG_PKG_CONFIG
       -PKG_CHECK_MODULES([LIBXML2], [libxml-2.0])
       -PKG_CHECK_MODULES([GLIB], [glib-2.0])
       -PKG_CHECK_MODULES([FUSE], [fuse])
       -
       -
       -# Checks for header files.
       -AC_CHECK_HEADERS([fcntl.h limits.h stddef.h stdlib.h string.h sys/time.h termios.h unistd.h utime.h])
       -
       -# Checks for typedefs, structures, and compiler characteristics.
       -AC_HEADER_STDBOOL
       -AC_C_INLINE
       -AC_TYPE_MODE_T
       -AC_TYPE_OFF_T
       -AC_TYPE_SIZE_T
       -AC_TYPE_UID_T
       -AC_TYPE_UINT64_T
       -AC_CHECK_TYPES([ptrdiff_t])
       -
       -# Checks for library functions.
       -AC_FUNC_MALLOC
       -AC_FUNC_REALLOC
       -AC_CHECK_FUNCS([memset strchr strerror])
       -
       -AC_CONFIG_FILES([Makefile])
       -AC_OUTPUT
       -
 (DIR) diff --git a/debian/Makefile.pkgdeb b/debian/Makefile.pkgdeb
       @@ -1,43 +0,0 @@
       -deb_package = $(shell dpkg-parsechangelog | grep ^Source: | sed -e s,'^Source: ',,)
       -deb_version = $(shell dpkg-parsechangelog | grep ^Version: | sed -e s,'^Version: ',, -e 's,-.*,,')
       -revision = $(shell dpkg-parsechangelog | grep ^Version: | sed -e -e 's,.*-,,')
       -architecture = $(shell dpkg --print-architecture)
       -tar_dir = $(PACKAGE)-$(VERSION)
       -tar_gz   = $(tar_dir).tar.gz
       -pkg_deb_dir = pkgdeb
       -unpack_dir  = $(pkg_deb_dir)/$(tar_dir)
       -orig_tar_gz = $(pkg_deb_dir)/$(PACKAGE)_$(VERSION).orig.tar.gz
       -pkg_deb_src = $(pkg_deb_dir)/$(PACKAGE)_$(VERSION)-$(revision)_source.changes
       -pkg_deb_bin = $(pkg_deb_dir)/$(PACKAGE)_$(VERSION)-$(revision)_$(architecture).changes
       -
       -#deb_pkg_key = -kCB8C5858
       -deb_pkg_key = -us -uc
       -
       -debclean:
       -        rm -rf $(pkg_deb_dir)
       -
       -deb: debsrc debbin
       -
       -debbin: $(unpack_dir)
       -        cd $(unpack_dir) && dpkg-buildpackage -b $(deb_pkg_key)
       -
       -debsrc: $(unpack_dir)
       -        cd $(unpack_dir) && dpkg-buildpackage -S $(deb_pkg_key)
       -
       -$(unpack_dir): $(orig_tar_gz)
       -        tar -zxf $(orig_tar_gz) -C $(pkg_deb_dir)
       -        [ $(VERSION) = $(deb_version) ] || \
       -         ( cd $(unpack_dir) && debchange -m -v $(VERSION)-1  New upstream release $(VERSION). )
       -        # Remove requirements for preparing the release tarball
       -        # from the Debian control file
       -        sed -i -e '/^ autoconf/d' -e '/^ devscripts/d' $(unpack_dir)/debian/control
       -
       -$(tar_gz): tar
       -
       -$(orig_tar_gz): $(tar_gz) debclean
       -        mkdir $(pkg_deb_dir)
       -        [ $(PACKAGE) = $(deb_package) ]
       -        ln -s ../$(tar_gz) $(orig_tar_gz)
       -
       -
       -
 (DIR) diff --git a/debian/changelog b/debian/changelog
       @@ -1,5 +0,0 @@
       -usmb (20090411-1) UNRELEASED; urgency=low
       -
       -  * Initial release. (Closes: #572703)
       -
       - -- Michal Suchanek <hramrach@centrum.cz>  Wed, 10 Mar 2010 11:59:09 +0100
 (DIR) diff --git a/debian/compat b/debian/compat
       @@ -1 +0,0 @@
       -7
 (DIR) diff --git a/debian/control b/debian/control
       @@ -1,29 +0,0 @@
       -Source: usmb
       -Section: otherosfs
       -Priority: optional
       -Build-Depends:
       - debhelper,
       - autoconf (>= 2.63),
       - devscripts,
       - libfuse-dev (>= 2.6),
       - libglib2.0-dev,
       - libsmbclient-dev (>= 3),
       - libxml2-dev,
       - pkg-config
       -Standards-Version: 3.8.4
       -Maintainer: Michal Suchanek <hramrach@centrum.cz>
       -Homepage: http://repo.or.cz/w/usmb.git
       -
       -Package: usmb
       -Recommends: fuse-utils
       -Architecture: any
       -Depends:
       - ${shlibs:Depends},
       - ${misc:Depends},
       -Description: samba (CIFS) FUSE module
       - usmb mounts samba (CIFS, Windows, NetBIOS) shares just like smbfs does,
       - but uses FUSE to allow users other than root to mount shares.
       - .
       - Previously smbfs allowed the same by making mount.cifs setuid root but
       - this was recently disabled in the smbfs package due to security
       - concerns.
 (DIR) diff --git a/debian/copyright b/debian/copyright
       @@ -1,25 +0,0 @@
       -Authors:
       - Geoff Johnstone <qwerty@acm.org>
       -Download: http://ametros.net/code.html#usmb
       -
       -Files: *
       -Copyright:
       - (C) 2006-2013 Geoff Johnstone <qwerty@acm.org>
       - Debian packaging (C) 2010 Michal Suchanek <hramrach@centrum.cz>
       -License: GPL-3
       - This program is free software; you can redistribute it and/or
       - modify it under the terms of the GNU General Public License
       - version 3 as published by the Free Software Foundation.
       - .
       - This program is distributed in the hope that it will be useful,
       - but WITHOUT ANY WARRANTY; without even the implied warranty of
       - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
       - GNU General Public License for more details.
       - .
       - You should have received a copy of the GNU General Public License
       - along with this program; if not, write to the Free Software
       - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
       - .
       - On Debian systems, the complete text of the GNU General Public License
       - can be found in /usr/share/common-licenses/GPL-3 file.
       -
 (DIR) diff --git a/debian/rules b/debian/rules
       @@ -1,3 +0,0 @@
       -#!/usr/bin/make -f
       -%:
       -        dh $@
 (DIR) diff --git a/debian/usmb.docs b/debian/usmb.docs
       @@ -1,2 +0,0 @@
       -README
       -usmb.conf
 (DIR) diff --git a/install-sh b/install-sh
       @@ -1,519 +0,0 @@
       -#!/bin/sh
       -# install - install a program, script, or datafile
       -
       -scriptversion=2006-12-25.00
       -
       -# This originates from X11R5 (mit/util/scripts/install.sh), which was
       -# later released in X11R6 (xc/config/util/install.sh) with the
       -# following copyright and license.
       -#
       -# Copyright (C) 1994 X Consortium
       -#
       -# Permission is hereby granted, free of charge, to any person obtaining a copy
       -# of this software and associated documentation files (the "Software"), to
       -# deal in the Software without restriction, including without limitation the
       -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
       -# sell copies of the Software, and to permit persons to whom the Software is
       -# furnished to do so, subject to the following conditions:
       -#
       -# The above copyright notice and this permission notice shall be included in
       -# all copies or substantial portions of the Software.
       -#
       -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
       -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
       -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
       -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       -#
       -# Except as contained in this notice, the name of the X Consortium shall not
       -# be used in advertising or otherwise to promote the sale, use or other deal-
       -# ings in this Software without prior written authorization from the X Consor-
       -# tium.
       -#
       -#
       -# FSF changes to this file are in the public domain.
       -#
       -# Calling this script install-sh is preferred over install.sh, to prevent
       -# `make' implicit rules from creating a file called install from it
       -# when there is no Makefile.
       -#
       -# This script is compatible with the BSD install script, but was written
       -# from scratch.
       -
       -nl='
       -'
       -IFS=" ""        $nl"
       -
       -# set DOITPROG to echo to test this script
       -
       -# Don't use :- since 4.3BSD and earlier shells don't like it.
       -doit=${DOITPROG-}
       -if test -z "$doit"; then
       -  doit_exec=exec
       -else
       -  doit_exec=$doit
       -fi
       -
       -# Put in absolute file names if you don't have them in your path;
       -# or use environment vars.
       -
       -chgrpprog=${CHGRPPROG-chgrp}
       -chmodprog=${CHMODPROG-chmod}
       -chownprog=${CHOWNPROG-chown}
       -cmpprog=${CMPPROG-cmp}
       -cpprog=${CPPROG-cp}
       -mkdirprog=${MKDIRPROG-mkdir}
       -mvprog=${MVPROG-mv}
       -rmprog=${RMPROG-rm}
       -stripprog=${STRIPPROG-strip}
       -
       -posix_glob='?'
       -initialize_posix_glob='
       -  test "$posix_glob" != "?" || {
       -    if (set -f) 2>/dev/null; then
       -      posix_glob=
       -    else
       -      posix_glob=:
       -    fi
       -  }
       -'
       -
       -posix_mkdir=
       -
       -# Desired mode of installed file.
       -mode=0755
       -
       -chgrpcmd=
       -chmodcmd=$chmodprog
       -chowncmd=
       -mvcmd=$mvprog
       -rmcmd="$rmprog -f"
       -stripcmd=
       -
       -src=
       -dst=
       -dir_arg=
       -dst_arg=
       -
       -copy_on_change=false
       -no_target_directory=
       -
       -usage="\
       -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
       -   or: $0 [OPTION]... SRCFILES... DIRECTORY
       -   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
       -   or: $0 [OPTION]... -d DIRECTORIES...
       -
       -In the 1st form, copy SRCFILE to DSTFILE.
       -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
       -In the 4th, create DIRECTORIES.
       -
       -Options:
       -     --help     display this help and exit.
       -     --version  display version info and exit.
       -
       -  -c            (ignored)
       -  -C            install only if different (preserve the last data modification time)
       -  -d            create directories instead of installing files.
       -  -g GROUP      $chgrpprog installed files to GROUP.
       -  -m MODE       $chmodprog installed files to MODE.
       -  -o USER       $chownprog installed files to USER.
       -  -s            $stripprog installed files.
       -  -t DIRECTORY  install into DIRECTORY.
       -  -T            report an error if DSTFILE is a directory.
       -
       -Environment variables override the default commands:
       -  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
       -  RMPROG STRIPPROG
       -"
       -
       -while test $# -ne 0; do
       -  case $1 in
       -    -c) ;;
       -
       -    -C) copy_on_change=true;;
       -
       -    -d) dir_arg=true;;
       -
       -    -g) chgrpcmd="$chgrpprog $2"
       -        shift;;
       -
       -    --help) echo "$usage"; exit $?;;
       -
       -    -m) mode=$2
       -        case $mode in
       -          *' '* | *'        '* | *'
       -'*          | *'*'* | *'?'* | *'['*)
       -            echo "$0: invalid mode: $mode" >&2
       -            exit 1;;
       -        esac
       -        shift;;
       -
       -    -o) chowncmd="$chownprog $2"
       -        shift;;
       -
       -    -s) stripcmd=$stripprog;;
       -
       -    -t) dst_arg=$2
       -        shift;;
       -
       -    -T) no_target_directory=true;;
       -
       -    --version) echo "$0 $scriptversion"; exit $?;;
       -
       -    --)        shift
       -        break;;
       -
       -    -*)        echo "$0: invalid option: $1" >&2
       -        exit 1;;
       -
       -    *)  break;;
       -  esac
       -  shift
       -done
       -
       -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
       -  # When -d is used, all remaining arguments are directories to create.
       -  # When -t is used, the destination is already specified.
       -  # Otherwise, the last argument is the destination.  Remove it from $@.
       -  for arg
       -  do
       -    if test -n "$dst_arg"; then
       -      # $@ is not empty: it contains at least $arg.
       -      set fnord "$@" "$dst_arg"
       -      shift # fnord
       -    fi
       -    shift # arg
       -    dst_arg=$arg
       -  done
       -fi
       -
       -if test $# -eq 0; then
       -  if test -z "$dir_arg"; then
       -    echo "$0: no input file specified." >&2
       -    exit 1
       -  fi
       -  # It's OK to call `install-sh -d' without argument.
       -  # This can happen when creating conditional directories.
       -  exit 0
       -fi
       -
       -if test -z "$dir_arg"; then
       -  trap '(exit $?); exit' 1 2 13 15
       -
       -  # Set umask so as not to create temps with too-generous modes.
       -  # However, 'strip' requires both read and write access to temps.
       -  case $mode in
       -    # Optimize common cases.
       -    *644) cp_umask=133;;
       -    *755) cp_umask=22;;
       -
       -    *[0-7])
       -      if test -z "$stripcmd"; then
       -        u_plus_rw=
       -      else
       -        u_plus_rw='% 200'
       -      fi
       -      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
       -    *)
       -      if test -z "$stripcmd"; then
       -        u_plus_rw=
       -      else
       -        u_plus_rw=,u+rw
       -      fi
       -      cp_umask=$mode$u_plus_rw;;
       -  esac
       -fi
       -
       -for src
       -do
       -  # Protect names starting with `-'.
       -  case $src in
       -    -*) src=./$src;;
       -  esac
       -
       -  if test -n "$dir_arg"; then
       -    dst=$src
       -    dstdir=$dst
       -    test -d "$dstdir"
       -    dstdir_status=$?
       -  else
       -
       -    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
       -    # might cause directories to be created, which would be especially bad
       -    # if $src (and thus $dsttmp) contains '*'.
       -    if test ! -f "$src" && test ! -d "$src"; then
       -      echo "$0: $src does not exist." >&2
       -      exit 1
       -    fi
       -
       -    if test -z "$dst_arg"; then
       -      echo "$0: no destination specified." >&2
       -      exit 1
       -    fi
       -
       -    dst=$dst_arg
       -    # Protect names starting with `-'.
       -    case $dst in
       -      -*) dst=./$dst;;
       -    esac
       -
       -    # If destination is a directory, append the input filename; won't work
       -    # if double slashes aren't ignored.
       -    if test -d "$dst"; then
       -      if test -n "$no_target_directory"; then
       -        echo "$0: $dst_arg: Is a directory" >&2
       -        exit 1
       -      fi
       -      dstdir=$dst
       -      dst=$dstdir/`basename "$src"`
       -      dstdir_status=0
       -    else
       -      # Prefer dirname, but fall back on a substitute if dirname fails.
       -      dstdir=`
       -        (dirname "$dst") 2>/dev/null ||
       -        expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
       -             X"$dst" : 'X\(//\)[^/]' \| \
       -             X"$dst" : 'X\(//\)$' \| \
       -             X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
       -        echo X"$dst" |
       -            sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
       -                   s//\1/
       -                   q
       -                 }
       -                 /^X\(\/\/\)[^/].*/{
       -                   s//\1/
       -                   q
       -                 }
       -                 /^X\(\/\/\)$/{
       -                   s//\1/
       -                   q
       -                 }
       -                 /^X\(\/\).*/{
       -                   s//\1/
       -                   q
       -                 }
       -                 s/.*/./; q'
       -      `
       -
       -      test -d "$dstdir"
       -      dstdir_status=$?
       -    fi
       -  fi
       -
       -  obsolete_mkdir_used=false
       -
       -  if test $dstdir_status != 0; then
       -    case $posix_mkdir in
       -      '')
       -        # Create intermediate dirs using mode 755 as modified by the umask.
       -        # This is like FreeBSD 'install' as of 1997-10-28.
       -        umask=`umask`
       -        case $stripcmd.$umask in
       -          # Optimize common cases.
       -          *[2367][2367]) mkdir_umask=$umask;;
       -          .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
       -
       -          *[0-7])
       -            mkdir_umask=`expr $umask + 22 \
       -              - $umask % 100 % 40 + $umask % 20 \
       -              - $umask % 10 % 4 + $umask % 2
       -            `;;
       -          *) mkdir_umask=$umask,go-w;;
       -        esac
       -
       -        # With -d, create the new directory with the user-specified mode.
       -        # Otherwise, rely on $mkdir_umask.
       -        if test -n "$dir_arg"; then
       -          mkdir_mode=-m$mode
       -        else
       -          mkdir_mode=
       -        fi
       -
       -        posix_mkdir=false
       -        case $umask in
       -          *[123567][0-7][0-7])
       -            # POSIX mkdir -p sets u+wx bits regardless of umask, which
       -            # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
       -            ;;
       -          *)
       -            tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
       -            trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
       -
       -            if (umask $mkdir_umask &&
       -                exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
       -            then
       -              if test -z "$dir_arg" || {
       -                   # Check for POSIX incompatibilities with -m.
       -                   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
       -                   # other-writeable bit of parent directory when it shouldn't.
       -                   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
       -                   ls_ld_tmpdir=`ls -ld "$tmpdir"`
       -                   case $ls_ld_tmpdir in
       -                     d????-?r-*) different_mode=700;;
       -                     d????-?--*) different_mode=755;;
       -                     *) false;;
       -                   esac &&
       -                   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
       -                     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
       -                     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
       -                   }
       -                 }
       -              then posix_mkdir=:
       -              fi
       -              rmdir "$tmpdir/d" "$tmpdir"
       -            else
       -              # Remove any dirs left behind by ancient mkdir implementations.
       -              rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
       -            fi
       -            trap '' 0;;
       -        esac;;
       -    esac
       -
       -    if
       -      $posix_mkdir && (
       -        umask $mkdir_umask &&
       -        $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
       -      )
       -    then :
       -    else
       -
       -      # The umask is ridiculous, or mkdir does not conform to POSIX,
       -      # or it failed possibly due to a race condition.  Create the
       -      # directory the slow way, step by step, checking for races as we go.
       -
       -      case $dstdir in
       -        /*) prefix='/';;
       -        -*) prefix='./';;
       -        *)  prefix='';;
       -      esac
       -
       -      eval "$initialize_posix_glob"
       -
       -      oIFS=$IFS
       -      IFS=/
       -      $posix_glob set -f
       -      set fnord $dstdir
       -      shift
       -      $posix_glob set +f
       -      IFS=$oIFS
       -
       -      prefixes=
       -
       -      for d
       -      do
       -        test -z "$d" && continue
       -
       -        prefix=$prefix$d
       -        if test -d "$prefix"; then
       -          prefixes=
       -        else
       -          if $posix_mkdir; then
       -            (umask=$mkdir_umask &&
       -             $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
       -            # Don't fail if two instances are running concurrently.
       -            test -d "$prefix" || exit 1
       -          else
       -            case $prefix in
       -              *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
       -              *) qprefix=$prefix;;
       -            esac
       -            prefixes="$prefixes '$qprefix'"
       -          fi
       -        fi
       -        prefix=$prefix/
       -      done
       -
       -      if test -n "$prefixes"; then
       -        # Don't fail if two instances are running concurrently.
       -        (umask $mkdir_umask &&
       -         eval "\$doit_exec \$mkdirprog $prefixes") ||
       -          test -d "$dstdir" || exit 1
       -        obsolete_mkdir_used=true
       -      fi
       -    fi
       -  fi
       -
       -  if test -n "$dir_arg"; then
       -    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
       -    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
       -    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
       -      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
       -  else
       -
       -    # Make a couple of temp file names in the proper directory.
       -    dsttmp=$dstdir/_inst.$$_
       -    rmtmp=$dstdir/_rm.$$_
       -
       -    # Trap to clean up those temp files at exit.
       -    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
       -
       -    # Copy the file name to the temp name.
       -    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
       -
       -    # and set any options; do chmod last to preserve setuid bits.
       -    #
       -    # If any of these fail, we abort the whole thing.  If we want to
       -    # ignore errors from any of these, just make sure not to ignore
       -    # errors from the above "$doit $cpprog $src $dsttmp" command.
       -    #
       -    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
       -    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
       -    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
       -    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
       -
       -    # If -C, don't bother to copy if it wouldn't change the file.
       -    if $copy_on_change &&
       -       old=`LC_ALL=C ls -dlL "$dst"        2>/dev/null` &&
       -       new=`LC_ALL=C ls -dlL "$dsttmp"        2>/dev/null` &&
       -
       -       eval "$initialize_posix_glob" &&
       -       $posix_glob set -f &&
       -       set X $old && old=:$2:$4:$5:$6 &&
       -       set X $new && new=:$2:$4:$5:$6 &&
       -       $posix_glob set +f &&
       -
       -       test "$old" = "$new" &&
       -       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
       -    then
       -      rm -f "$dsttmp"
       -    else
       -      # Rename the file to the real destination.
       -      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
       -
       -      # The rename failed, perhaps because mv can't rename something else
       -      # to itself, or perhaps because mv is so ancient that it does not
       -      # support -f.
       -      {
       -        # Now remove or move aside any old file at destination location.
       -        # We try this two ways since rm can't unlink itself on some
       -        # systems and the destination file might be busy for other
       -        # reasons.  In this case, the final cleanup might fail but the new
       -        # file should still install successfully.
       -        {
       -          test ! -f "$dst" ||
       -          $doit $rmcmd -f "$dst" 2>/dev/null ||
       -          { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
       -            { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
       -          } ||
       -          { echo "$0: cannot unlink or rename $dst" >&2
       -            (exit 1); exit 1
       -          }
       -        } &&
       -
       -        # Now rename the file to the real destination.
       -        $doit $mvcmd "$dsttmp" "$dst"
       -      }
       -    fi || exit 1
       -
       -    trap '' 0
       -  fi
       -done
       -
       -# Local variables:
       -# eval: (add-hook 'write-file-hooks 'time-stamp)
       -# time-stamp-start: "scriptversion="
       -# time-stamp-format: "%:y-%02m-%02d.%02H"
       -# time-stamp-end: "$"
       -# End:
 (DIR) diff --git a/options.c b/options.c
       @@ -1,192 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2013 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <assert.h>
       -#include <glib.h>
       -#include <stdbool.h>
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include "options.h"
       -#include "utils.h"
       -#include "version.h"
       -
       -
       -static gboolean version = FALSE;
       -static gchar *conffile = NULL;
       -static gboolean debug = FALSE;
       -static gboolean nofork = FALSE;
       -static gboolean umount = FALSE;
       -static gchar **remaining = NULL;
       -
       -
       -static GOptionEntry entries[] = {
       -  { .long_name = "version",
       -    .short_name = 'v',
       -    .flags = 0,
       -    .arg = G_OPTION_ARG_NONE,
       -    .arg_data = &version,
       -    .description = "Show usmb, FUSE and Samba versions" },
       -
       -  { .long_name = "version",
       -    .short_name = 'V',
       -    .flags = G_OPTION_FLAG_HIDDEN,
       -    .arg = G_OPTION_ARG_NONE,
       -    .arg_data = &version,
       -    .description = NULL },
       -
       -  { .long_name = "config",
       -    .short_name = 'c',
       -    .flags = 0,
       -    .arg = G_OPTION_ARG_FILENAME,
       -    .arg_data = &conffile,
       -    .description = "usmb configuration file" },
       -
       -  { .long_name = "debug",
       -    .short_name = 'd',
       -    .arg = G_OPTION_ARG_NONE,
       -    .arg_data = &debug,
       -    .description = "Debug mode" },
       -
       -  { .long_name = "nofork",
       -    .short_name = 'f',
       -    .arg = G_OPTION_ARG_NONE,
       -    .arg_data = &nofork,
       -    .description = "Foreground operation" },
       -
       -  { .long_name = "unmount",
       -    .short_name = 'u',
       -    .arg = G_OPTION_ARG_NONE,
       -    .arg_data = &umount,
       -    .description = "Unmount the given filesystem" },
       -
       -  { .long_name = G_OPTION_REMAINING,
       -    .short_name = 0,
       -    .arg = G_OPTION_ARG_STRING_ARRAY,
       -    .arg_data = &remaining,
       -    .description = NULL },
       -
       -  { .long_name = NULL }
       -};
       -
       -
       -bool parse_args (int *argc, char ***argv,
       -                 const char **mountid, const char **out_conffile,
       -                 bool *out_umount)
       -{
       -  GError *error = NULL;
       -
       -  GOptionContext *context =
       -    g_option_context_new ("- mount SMB shares via FUSE and Samba");
       -  g_option_context_add_main_entries (context, entries, NULL);
       -  bool ret = g_option_context_parse (context, argc, argv, &error);
       -  g_option_context_free (context);
       -
       -  if (false == ret)
       -  {
       -    fprintf (stderr, "Try `%s --help' for more information\n", (*argv)[0]);
       -    return false;
       -  }
       -
       -  if (version)
       -  {
       -    show_version (stdout);
       -    exit (EXIT_SUCCESS);
       -  }
       -
       -  if ((NULL == remaining) || (NULL == remaining[0]))
       -  {
       -    fputs ("No share ID given.\n", stderr);
       -    return false;
       -  }
       -
       -  if (NULL != remaining[1])
       -  {
       -    fputs ("Too many arguments.\n", stderr);
       -    return false;
       -  }
       -
       -  *out_umount = umount;
       -  *mountid = remaining[0];
       -  g_free (remaining);
       -  DEBUG (fprintf (stderr, "Mount ID: %s\n", *mountid));
       -
       -  if (NULL != conffile)
       -    *out_conffile = conffile;
       -
       -  return ret;
       -}
       -
       -
       -/* FUSE args are:
       - *
       - * argv[0]
       - * -s
       - * -d          -- if debug mode requested
       - * -f          -- if foreground mode requested
       - * -o ...      -- if any mount options in the config file
       - * mount point
       - */
       -#define MAXARGS 12
       -void build_fuse_args (const char *options, const char *mountpoint,
       -                      int *out_argc, char ***out_argv)
       -{
       -  static char USMB[] = "usmb";
       -  static char MINUS_S[] = "-s";
       -  static char MINUS_D[] = "-d";
       -  static char MINUS_F[] = "-f";
       -  static char MINUS_O[] = "-o";
       -  static char MAX_READ[] = "max_read=32768";
       -
       -  assert (NULL != mountpoint);
       -  static char *argv[MAXARGS];
       -
       -  int argc = 0;
       -
       -  argv[argc++] = USMB;
       -  argv[argc++] = MINUS_S;
       -
       -  if (debug)
       -    argv[argc++] = MINUS_D;
       -
       -  // force -f in debug mode
       -#ifndef DEBUGON
       -  if (nofork)
       -#endif
       -    argv[argc++] = MINUS_F;
       -
       -  argv[argc++] = MINUS_O;
       -  argv[argc++] = MAX_READ;
       -
       -  if ((NULL != options) && ('\0' != options[0]))
       -  {
       -    argv[argc++] = MINUS_O;
       -    argv[argc++] = (char *)options;
       -  }
       -
       -  argv[argc++] = (char *)mountpoint;
       -  argv[argc] = NULL;          // for good measure...
       -
       -  assert (argc < MAXARGS);
       -  *out_argc = argc;
       -  *out_argv = argv;
       -
       -  #ifdef DEBUGON
       -    for (int i = 0; i < argc; ++i)
       -      fprintf (stderr, "%d: %s\n", i, argv[i]);
       -  #endif
       -}
       -
 (DIR) diff --git a/options.h b/options.h
       @@ -1,26 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#ifndef OPTIONS_H
       -  #define OPTIONS_H
       -
       -  bool parse_args (int *argc, char ***argv,
       -                   const char **mountid, const char **out_conffile,
       -                   bool *out_umount) MUSTCHECK;
       -  void build_fuse_args (const char *options, const char *mountpoint,
       -                        int *out_argc, char ***out_argv);
       -
       -#endif
 (DIR) diff --git a/password.c b/password.c
       @@ -1,86 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <assert.h>
       -#include <stdbool.h>
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include <string.h>
       -#include <termios.h>
       -#include <unistd.h>
       -#include "password.h"
       -#include "utils.h"
       -
       -
       -bool password_read (char **out)
       -{
       -  struct termios attr, new;
       -
       -  assert (NULL != out);
       -  *out = NULL;
       -
       -  if (0 != tcgetattr (STDIN_FILENO, &attr))
       -  {
       -    perror ("tcgetattr");
       -    fputs ("Cannot configure terminal to read password securely.\n", stderr);
       -    return false;
       -  }
       -
       -  new = attr;
       -  new.c_lflag &= ~ECHO;
       -
       -  if (0 != tcsetattr (STDIN_FILENO, TCSAFLUSH, &new))
       -  {
       -    perror ("tcsetattr");
       -    fputs ("Cannot configure terminal to read password securely.\n", stderr);
       -    return false;
       -  }
       -
       -  char buff[1024];
       -
       -  fputs ("\nPassword: ", stdout);
       -  fflush (stdout);
       -  const bool ok = (buff == fgets (buff, sizeof (buff), stdin));
       -  fputc ('\n', stdout);
       -
       -  if (0 != tcsetattr (STDIN_FILENO, TCSAFLUSH, &attr))
       -  {
       -    perror ("tcsetattr");
       -    fputs ("Failed to reset terminal.\n", stderr);
       -  }
       -
       -  if (!ok)
       -  {
       -    return false;
       -  }
       -
       -  // strip a trailing '\n'.
       -  {
       -    size_t len = strlen (buff);
       -
       -    if ((0 < len) && ('\n' == buff[len - 1]))
       -      buff[len - 1] = '\0';
       -  }
       -
       -  *out = xstrdup (buff);
       -  memset (buff, 0, sizeof (buff));
       -
       -  DEBUG (fprintf (stderr, "Password: %s\n", *out));
       -
       -  return (NULL != *out);
       -}
       -
 (DIR) diff --git a/password.h b/password.h
       @@ -1,24 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#ifndef PASSWORD_H
       -  #define PASSWORD_H
       -
       -  #include <stdbool.h>
       -
       -  bool password_read (char **out) MUSTCHECK;
       -
       -#endif
 (DIR) diff --git a/samba30_compat.c b/samba30_compat.c
       @@ -1,72 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <errno.h>
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include <string.h>
       -#include "samba3x-compat.h"
       -#include "usmb.h"
       -#include "usmb_file.h"
       -#include "utils.h"
       -
       -
       -int usmb_statfs (const char *path UNUSED, struct statvfs *vfs UNUSED)
       -{
       -  (void)path;
       -  (void)vfs;
       -  return -ENOSYS;
       -}
       -
       -
       -int compat_truncate (const char *path UNUSED, SMBCFILE *file UNUSED, off_t size)
       -{
       -  /* Windows doesn't support truncation so we implement a limited version:
       -   *  0 == size => create a new file for writing.
       -   *  current size == size => succeed.
       -   *  else return -ENOSYS.
       -   */
       -  
       -  if (0 == size)
       -  { 
       -    char *url = make_url (path);
       -    if (NULL == url)
       -      return -ENOMEM;
       -
       -    SMBCFILE *file_ = smbc_getFunctionOpen (ctx) (ctx, url,
       -                                                  O_WRONLY | O_TRUNC, 0);
       -    if (NULL == file_)
       -    { 
       -      free_errno (url);
       -      return -errno;
       -    }
       -    
       -    smbc_getFunctionClose (ctx) (ctx, file_);
       -    free (url);
       -
       -    return 0;
       -  } 
       -
       -  struct stat st;
       -  int ret = usmb_getattr (path, &st);
       -
       -  if (0 != ret)
       -    return ret;
       -
       -  return (size == st.st_size) ? 0 : -ENOSYS;
       -}
       -
 (DIR) diff --git a/samba32_compat.c b/samba32_compat.c
       @@ -1,40 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <errno.h>
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include <string.h>
       -#include "samba3x-compat.h"
       -#include "usmb.h"
       -#include "utils.h"
       -
       -
       -int usmb_statfs (const char *path, struct statvfs *vfs)
       -{
       -  (void)path;
       -  (void)vfs;
       -  return -ENOSYS;
       -}
       -
       -
       -
       -int compat_truncate (const char *path UNUSED, SMBCFILE *file, off_t size)
       -{
       -  return (0 > smbc_getFunctionFtruncate (ctx) (ctx, file, size)) ? -errno : 0;
       -}
       -
 (DIR) diff --git a/samba33_compat.c b/samba33_compat.c
       @@ -1,49 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <errno.h>
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include <string.h>
       -#include "samba3x-compat.h"
       -#include "usmb.h"
       -#include "utils.h"
       -
       -
       -int usmb_statfs (const char *path, struct statvfs *vfs)
       -{
       -  if ((NULL == path) || (NULL == vfs))
       -    return -EINVAL;
       -
       -  char *url = make_url (path);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "statfs (%s, %p)\n", url, (void *)vfs));
       -  memset (vfs, 0, sizeof (*vfs));
       -
       -  int ret = (0 > smbc_getFunctionStatVFS (ctx) (ctx, url, vfs)) ? -errno : 0;
       -  free (url);
       -  return ret;
       -}
       -
       -
       -int compat_truncate (const char *path UNUSED, SMBCFILE *file, off_t size)
       -{
       -  return (0 > smbc_getFunctionFtruncate (ctx) (ctx, file, size)) ? -errno : 0;
       -}
       -
 (DIR) diff --git a/samba3x-compat.h b/samba3x-compat.h
       @@ -1,283 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * Portions of this file are taken from Samba 3.2's libsmbclient.h:
       - *  Copyright (C) Andrew Tridgell 1998
       - *  Copyright (C) Richard Sharpe 2000
       - *  Copyright (C) John Terpsra 2000
       - *  Copyright (C) Tom Jansen (Ninja ISD) 2002
       - *  Copyright (C) Derrell Lipman 2003-2008
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License as published by the
       - * Free Software Foundation; either version 3 of the License, or (at your
       - * option) any later version.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#ifndef SAMBA_30_COMPAT_H
       -  #define SAMBA_30_COMPAT_H
       -
       -  #include "config.h"
       -  #include <libsmbclient.h>
       -  #include <sys/statvfs.h>
       -
       -
       -  int usmb_statfs (const char *path UNUSED, struct statvfs *vfs UNUSED);
       -  int compat_truncate (const char *path, SMBCFILE *file, off_t size);
       -
       -
       -  #ifndef HAVE_SAMBA32
       -
       -    typedef int (*smbc_chmod_fn) (SMBCCTX *c, const char *fname, mode_t mode);
       -
       -    static inline smbc_chmod_fn smbc_getFunctionChmod (SMBCCTX *c)
       -    {
       -      return c->chmod;
       -    }
       -
       -
       -    typedef int (*smbc_close_fn) (SMBCCTX *c, SMBCFILE *file);
       -
       -    static inline smbc_close_fn smbc_getFunctionClose (SMBCCTX *c)
       -    {
       -      return c->close_fn;
       -    }
       -
       -
       -    typedef int (*smbc_closedir_fn) (SMBCCTX *c, SMBCFILE *dir);
       -
       -    static inline smbc_closedir_fn smbc_getFunctionClosedir (SMBCCTX *c)
       -    {
       -      return c->closedir;
       -    }
       -
       -
       -    typedef SMBCFILE * (*smbc_creat_fn) (SMBCCTX *c,
       -                                         const char *path,
       -                                         mode_t mode);
       -
       -    static inline smbc_creat_fn smbc_getFunctionCreat (SMBCCTX *c)
       -    {
       -      return c->creat;
       -    }
       -
       -
       -    typedef int (*smbc_fstat_fn) (SMBCCTX *c, SMBCFILE *file, struct stat *st);
       -
       -    static inline smbc_fstat_fn smbc_getFunctionFstat (SMBCCTX *c)
       -    {
       -      return c->fstat;
       -    }
       -
       -
       -    typedef int (*smbc_getxattr_fn) (SMBCCTX *context,
       -                                     const char *fname,
       -                                     const char *name,
       -                                     const void *value,
       -                                     size_t size);
       -
       -    static inline smbc_getxattr_fn smbc_getFunctionGetxattr (SMBCCTX *c)
       -    {
       -      return c->getxattr;
       -    }
       -
       -
       -    typedef int (*smbc_listxattr_fn) (SMBCCTX *context,
       -                                      const char *fname,
       -                                      char *list,
       -                                      size_t size);
       -
       -    static inline smbc_listxattr_fn smbc_getFunctionListxattr (SMBCCTX *c)
       -    {
       -      return c->listxattr;
       -    }
       -
       -
       -    typedef off_t (*smbc_lseek_fn) (SMBCCTX *c,
       -                                    SMBCFILE *file,
       -                                    off_t offset,
       -                                    int whence);
       -
       -    static inline smbc_lseek_fn smbc_getFunctionLseek (SMBCCTX *c)
       -    {
       -      return c->lseek;
       -    }
       -
       -
       -    typedef int (*smbc_mkdir_fn) (SMBCCTX *c, const char *fname, mode_t mode);
       -
       -    static inline smbc_mkdir_fn smbc_getFunctionMkdir (SMBCCTX *c)
       -    {
       -      return c->mkdir;
       -    }
       -
       -
       -    typedef SMBCFILE * (*smbc_open_fn) (SMBCCTX *c,
       -                                        const char *fname,
       -                                        int flags,
       -                                        mode_t mode);
       -
       -    static inline smbc_open_fn smbc_getFunctionOpen (SMBCCTX *c)
       -    {
       -      return c->open;
       -    }
       -
       -
       -    typedef SMBCFILE * (*smbc_opendir_fn) (SMBCCTX *c, const char *fname);
       -
       -    static inline smbc_opendir_fn smbc_getFunctionOpendir (SMBCCTX *c)
       -    {
       -      return c->opendir;
       -    }
       -
       -
       -    typedef ssize_t (*smbc_read_fn) (SMBCCTX *c,
       -                                     SMBCFILE *file,
       -                                     void *buf,
       -                                     size_t count);
       -
       -    static inline smbc_read_fn smbc_getFunctionRead (SMBCCTX *c)
       -    {
       -      return c->read;
       -    }
       -
       -
       -    typedef struct smbc_dirent * (*smbc_readdir_fn) (SMBCCTX *c, SMBCFILE *dir);
       -
       -    static inline smbc_readdir_fn smbc_getFunctionReaddir (SMBCCTX *c)
       -    {
       -      return c->readdir;
       -    }
       -
       -
       -    typedef int (*smbc_removexattr_fn) (SMBCCTX *context,
       -                                        const char *fname,
       -                                        const char *name);
       -
       -    static inline smbc_removexattr_fn smbc_getFunctionRemovexattr (SMBCCTX *c)
       -    {
       -      return c->removexattr;
       -    }
       -
       -
       -    typedef int (*smbc_rename_fn) (SMBCCTX *ocontext,
       -                                   const char *oname,
       -                                   SMBCCTX *ncontext,
       -                                   const char *nname);
       -
       -    static inline smbc_rename_fn smbc_getFunctionRename (SMBCCTX *c)
       -    {
       -      return c->rename;
       -    }
       -
       -
       -    typedef int (*smbc_rmdir_fn) (SMBCCTX *c, const char *fname);
       -
       -    static inline smbc_rmdir_fn smbc_getFunctionRmdir (SMBCCTX *c)
       -    {
       -      return c->rmdir;
       -    }
       -
       -
       -    typedef int (*smbc_lseekdir_fn)(SMBCCTX *c,
       -                                    SMBCFILE *dir,
       -                                    off_t offset);
       -
       -    static inline smbc_lseekdir_fn smbc_getFunctionLseekdir (SMBCCTX *c)
       -    {
       -      return c->lseekdir;
       -    }
       -
       -
       -    typedef int (*smbc_setxattr_fn) (SMBCCTX *context,
       -                                     const char *fname,
       -                                     const char *name,
       -                                     const void *value,
       -                                     size_t size,
       -                                     int flags);
       -
       -    static inline smbc_setxattr_fn smbc_getFunctionSetxattr (SMBCCTX *c)
       -    {
       -      return c->setxattr;
       -    }
       -
       -
       -    typedef int (*smbc_stat_fn) (SMBCCTX *c, const char *fname, struct stat *s);
       -
       -    static inline smbc_stat_fn smbc_getFunctionStat (SMBCCTX *c)
       -    {
       -      return c->stat;
       -    }
       -
       -
       -    typedef int (*smbc_unlink_fn) (SMBCCTX *c, const char *fname);
       -
       -    static inline smbc_unlink_fn smbc_getFunctionUnlink (SMBCCTX *c)
       -    {
       -      return c->unlink;
       -    }
       -
       -
       -    typedef int (*smbc_utimes_fn) (SMBCCTX *c,
       -                                   const char *fname,
       -                                   struct timeval *tbuf);
       -
       -    static inline smbc_utimes_fn smbc_getFunctionUtimes (SMBCCTX *c)
       -    {
       -      return c->utimes;
       -    }
       -
       -
       -    typedef ssize_t (*smbc_write_fn) (SMBCCTX *c,
       -                                      SMBCFILE *file,
       -                                      void *buf,
       -                                      size_t count);
       -
       -    static inline smbc_write_fn smbc_getFunctionWrite (SMBCCTX *c)
       -    {
       -      return c->write;
       -    }
       -
       -
       -    typedef void (*smbc_get_auth_fn) (const char *srv,
       -                                      const char *shr,
       -                                      char *wg, int wglen,
       -                                      char *un, int unlen,
       -                                      char *pw, int pwlen);
       -
       -    static inline void smbc_setFunctionAuthData (SMBCCTX *c,
       -                                                 smbc_get_auth_data_fn fn)
       -    {
       -      c->callbacks.auth_fn = fn;
       -    }
       -
       -
       -    static inline void smbc_setTimeout (SMBCCTX *c, int timeout)
       -    {
       -      c->timeout = timeout;
       -    }
       -
       -
       -    static inline void smbc_setUser (SMBCCTX *c, char *user)
       -    {
       -      c->user = user;
       -    }
       -
       -
       -    static inline void smbc_setWorkgroup (SMBCCTX *c, char *workgroup)
       -    {
       -      c->workgroup = workgroup;
       -    }
       -
       -  #endif
       -
       -#endif
       -
 (DIR) diff --git a/susmb.1 b/susmb.1
       @@ -0,0 +1,86 @@
       +.Dd March 5, 2025
       +.Dt SUSMB 1
       +.Os
       +.Sh NAME
       +.Nm susmb
       +.Nd Mount SMB/CIFS shares via FUSE
       +.Sh SYNOPSIS
       +.Nm
       +.Op Fl d
       +.Op Fl f
       +.Op Fl v
       +.Op Fl o Ar options
       +.Op Fl u Ar user
       +.Op Fl g Ar gid
       +.Ar URI
       +.Ar mountpoint
       +.Pp
       +.Ar URI
       +is in the format: smb://domain\\someuser@192.168.1.1/Storage
       +.Pp
       +The password should be specified with the environment variable
       +.Ev SMB_PASS .
       +.Sh DESCRIPTION
       +.Nm
       +mounts SMB and CIFS shares through FUSE, including Samba shares and
       +Windows shared folders.
       +Unlike some other such filesystems,
       +.Nm
       +can mount
       +shares from any server, including those not browsable or advertised on the
       +network.
       +.Pp
       +The options are as follows:
       +.Bl -tag -width Ds
       +.It Fl d
       +Debug mode.
       +.It Fl f
       +Foreground operation (i.e. don't daemonise).
       +.It Fl v
       +Show
       +.Nm ,
       +FUSE and Samba versions and exit.
       +.It Fl o Ar options
       +Additional list of FUSE options as a comma-separated list.
       +These options are platform-specific, see the man page of your FUSE
       +implementation for the supported options.
       +.It Fl u Ar user
       +Privdrop to user.
       +When a name is given then the uid and gid is read from the password
       +database entry.
       +Otherwise the option is interpreted as an uid number.
       +.It Fl g Ar gid
       +Privdrop to group.
       +This option is interpreted as an gid number.
       +.El
       +.Pp
       +Both a uid and gid should be specified or resolved to be able to use privdrop.
       +.Sh EXIT STATUS
       +.Ex -std
       +.Sh EXAMPLES
       +.Bd -literal
       +SMB_PASS="password" susmb -u hiltjo -f -o 'uid=1000,gid=1000,allow_other' "smb://domain\\someuser@192.168.1.1/Storage" /mnt/share
       +.Ed
       +.Sh SEE ALSO
       +.Xr fusermount 1 ,
       +.Xr fuse_mount 3 ,
       +.Xr mount.cifs 8 ,
       +.Xr umount.cifs 8
       +.Sh AUTHORS
       +.An Hiltjo Posthuma Aq Mt hiltjo@codemadness.org
       +.Pp
       +usmb authors:
       +.Pp
       +Geoff Johnstone, with contributions from Jonathan Schultz, Stijn Hoop, Nigel
       +Smith and Michal Suchanek.
       +.Sh CAVEATS
       +.Bl -item
       +.It
       +When running
       +.Nm
       +as a privilege-dropped user on Linux there may be issues unmounting the
       +network share in a clean manner.
       +A workaround could be a shellscript wrapper that does something like:
       +.Pp
       +trap 'umount /mnt/testshare' INT TERM EXIT
       +.El
 (DIR) diff --git a/susmb.c b/susmb.c
       @@ -0,0 +1,1377 @@
       +/* susmb - mount SMB shares via FUSE and Samba
       + * Copyright (C) 2025 Hiltjo Posthuma
       + * Copyright (C) 2006-2013 Geoff Johnstone
       + *
       + * Portions of this file are taken from Samba 3.2's libsmbclient.h:
       + *  Copyright (C) Andrew Tridgell 1998
       + *  Copyright (C) Richard Sharpe 2000
       + *  Copyright (C) John Terpsra 2000
       + *  Copyright (C) Tom Jansen (Ninja ISD) 2002
       + *  Copyright (C) Derrell Lipman 2003-2008
       + *
       + * This program is free software; you can redistribute it and/or modify
       + * it under the terms of the GNU General Public License version 3 as
       + * published by the Free Software Foundation.
       + *
       + * This program is distributed in the hope that it will be useful,
       + * but WITHOUT ANY WARRANTY; without even the implied warranty of
       + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       + * GNU General Public License for more details.
       + *
       + * You should have received a copy of the GNU General Public License
       + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       + */
       +
       +/* Marks unused parameters */
       +#define UNUSED __attribute__ ((unused))
       +
       +#define SUSMB_VERSION "0.9"
       +
       +#include <libsmbclient.h>
       +
       +/* Required FUSE API version */
       +#define FUSE_USE_VERSION 26
       +
       +#include <fuse.h>
       +
       +#include <sys/types.h>
       +#include <sys/statvfs.h>
       +
       +/* struct timeval needed by libsmbclient.h */
       +#include <sys/time.h>
       +
       +#include <dirent.h>
       +#include <err.h>
       +#include <errno.h>
       +#include <limits.h>
       +#include <pwd.h>
       +#include <stdarg.h>
       +#include <stdbool.h>
       +#include <stddef.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <unistd.h>
       +
       +/* use libbsd stdlib.h for arc4random() */
       +#ifdef __linux__
       +#include <bsd/stdlib.h>
       +#endif
       +
       +#ifndef __OpenBSD__
       +#define unveil(p1,p2) 0
       +#endif
       +
       +/* ctype-like macros, but always compatible with ASCII / UTF-8 */
       +#define ISALPHA(c) ((((unsigned)c) | 32) - 'a' < 26)
       +#define ISCNTRL(c) ((c) < ' ' || (c) == 0x7f)
       +#define ISDIGIT(c) (((unsigned)c) - '0' < 10)
       +#define ISSPACE(c) ((c) == ' ' || ((((unsigned)c) - '\t') < 5))
       +#define TOLOWER(c) ((((unsigned)c) - 'A' < 26) ? ((c) | 32) : (c))
       +
       +/* URI */
       +struct uri {
       +        char proto[48];     /* scheme including ":" or "://" */
       +        char userinfo[256]; /* username [:password] */
       +        char host[256];
       +        char port[6];       /* numeric port */
       +        char path[1024];
       +        char query[1024];
       +        char fragment[1024];
       +};
       +
       +int uri_parse(const char *s, struct uri *u);
       +
       +char * make_url(const char *path);
       +bool create_smb_context(SMBCCTX **pctx);
       +void destroy_smb_context(SMBCCTX *ctx_, int shutdown);
       +
       +int usmb_statfs(const char *path UNUSED, struct statvfs *vfs UNUSED);
       +int compat_truncate(const char *path, SMBCFILE *file, off_t size);
       +
       +void show_about(FILE *fp);
       +void show_version(FILE *fp);
       +void usage(void);
       +
       +void build_fuse_args(const char *options, const char *mountpoint,
       +        int debug, int nofork,
       +        int *out_argc, char ***out_argv);
       +
       +int usmb_fuse_main(int argc, char *argv[],
       +                             const struct fuse_operations *op, size_t op_size,
       +                             void *user_data);
       +
       +int usmb_getattr(const char *filename, struct stat *st);
       +int usmb_fgetattr(const char *filename, struct stat *st,
       +                  struct fuse_file_info *fi);
       +int usmb_unlink(const char *filename);
       +int usmb_open(const char *filename, struct fuse_file_info *fi);
       +int usmb_release(const char *filename, struct fuse_file_info *fi);
       +int usmb_read(const char *filename, char *buff, size_t len, off_t off,
       +              struct fuse_file_info *fi);
       +int usmb_write(const char *filename, const char *buff, size_t len, off_t off,
       +               struct fuse_file_info *fi);
       +int usmb_mknod(const char *filename, mode_t mode, dev_t dev);
       +int usmb_create(const char *filename, mode_t mode,
       +                struct fuse_file_info *fi);
       +int usmb_rename(const char *from, const char *to);
       +int usmb_utime(const char *filename, struct utimbuf *utb);
       +int usmb_truncate(const char *filename, off_t newsize);
       +int usmb_chmod(const char *filename, mode_t mode);
       +int usmb_ftruncate(const char *path, off_t size,
       +                   struct fuse_file_info *fi);
       +
       +/* directory operations */
       +
       +int usmb_mkdir(const char *dirname, mode_t mode);
       +int usmb_rmdir(const char *dirname);
       +int usmb_opendir(const char *dirname, struct fuse_file_info *fi);
       +int usmb_readdir(const char *path, void *h, fuse_fill_dir_t filler,
       +                 off_t offset, struct fuse_file_info *fi);
       +int usmb_releasedir(const char *path, struct fuse_file_info *fi);
       +int usmb_setxattr(const char *path, const char *name, const char *value,
       +                  size_t size, int flags);
       +int usmb_getxattr(const char *path, const char *name, char *value,
       +                  size_t size);
       +int usmb_listxattr(const char *path, char *list, size_t size);
       +int usmb_removexattr(const char *path, const char *name);
       +
       +void *emalloc(size_t size);
       +void *erealloc(void *ptr, size_t size);
       +char *estrdup(const char *s);
       +
       +char * xstrdup(const char *in);
       +void clear_and_free(char *ptr);
       +void free_errno(void *ptr);
       +
       +/* globals */
       +
       +static SMBCCTX *ctx;
       +static int opt_debug, opt_nofork;
       +static char *opt_server, *opt_share, *opt_mountpoint, *opt_options,
       +            *opt_domain, *opt_username, *opt_password;
       +static int disconnect;
       +static char *sharename;
       +static const char *argv0 = "susmb";
       +
       +/* for privdrop */
       +static uid_t opt_uid;
       +static gid_t opt_gid;
       +static int opt_privdrop;
       +
       +/* fuse_file_info uses a uint64_t for a "File handle" */
       +static inline uint64_t
       +smbcfile_to_fd(SMBCFILE *file)
       +{
       +        return (uint64_t)(uintptr_t)file;
       +}
       +
       +static inline SMBCFILE *
       +fd_to_smbcfile(uint64_t fd)
       +{
       +        return (SMBCFILE *)(uintptr_t)fd;
       +}
       +
       +void *
       +emalloc(size_t size)
       +{
       +        void *p;
       +
       +        p = malloc(size);
       +        if (p == NULL)
       +                err(1, "malloc");
       +        return p;
       +}
       +
       +void *
       +erealloc(void *ptr, size_t size)
       +{
       +        void *p;
       +
       +        p = realloc(ptr, size);
       +        if (p == NULL)
       +                err(1, "realloc");
       +        return p;
       +}
       +
       +char *
       +estrdup(const char *s)
       +{
       +        char *p;
       +
       +        p = strdup(s);
       +        if (p == NULL)
       +                err(1, "strdup");
       +        return p;
       +}
       +
       +/* Parse URI string `s` into an uri structure `u`.
       + * Returns 0 on success or -1 on failure */
       +int
       +uri_parse(const char *s, struct uri *u)
       +{
       +        const char *p = s;
       +        char *endptr;
       +        size_t i;
       +        long l;
       +
       +        u->proto[0] = u->userinfo[0] = u->host[0] = u->port[0] = '\0';
       +        u->path[0] = u->query[0] = u->fragment[0] = '\0';
       +
       +        /* protocol-relative */
       +        if (*p == '/' && *(p + 1) == '/') {
       +                p += 2; /* skip "//" */
       +                goto parseauth;
       +        }
       +
       +        /* scheme / protocol part */
       +        for (; ISALPHA((unsigned char)*p) || ISDIGIT((unsigned char)*p) ||
       +                       *p == '+' || *p == '-' || *p == '.'; p++)
       +                ;
       +        /* scheme, except if empty and starts with ":" then it is a path */
       +        if (*p == ':' && p != s) {
       +                if (*(p + 1) == '/' && *(p + 2) == '/')
       +                        p += 3; /* skip "://" */
       +                else
       +                        p++; /* skip ":" */
       +
       +                if ((size_t)(p - s) >= sizeof(u->proto))
       +                        return -1; /* protocol too long */
       +                memcpy(u->proto, s, p - s);
       +                u->proto[p - s] = '\0';
       +
       +                if (*(p - 1) != '/')
       +                        goto parsepath;
       +        } else {
       +                p = s; /* no scheme format, reset to start */
       +                goto parsepath;
       +        }
       +
       +parseauth:
       +        /* userinfo (username:password) */
       +        i = strcspn(p, "@/?#");
       +        if (p[i] == '@') {
       +                if (i >= sizeof(u->userinfo))
       +                        return -1; /* userinfo too long */
       +                memcpy(u->userinfo, p, i);
       +                u->userinfo[i] = '\0';
       +                p += i + 1;
       +        }
       +
       +        /* IPv6 address */
       +        if (*p == '[') {
       +                /* bracket not found, host too short or too long */
       +                i = strcspn(p, "]");
       +                if (p[i] != ']' || i < 3)
       +                        return -1;
       +                i++; /* including "]" */
       +        } else {
       +                /* domain / host part, skip until port, path or end. */
       +                i = strcspn(p, ":/?#");
       +        }
       +        if (i >= sizeof(u->host))
       +                return -1; /* host too long */
       +        memcpy(u->host, p, i);
       +        u->host[i] = '\0';
       +        p += i;
       +
       +        /* port */
       +        if (*p == ':') {
       +                p++;
       +                if ((i = strcspn(p, "/?#")) >= sizeof(u->port))
       +                        return -1; /* port too long */
       +                memcpy(u->port, p, i);
       +                u->port[i] = '\0';
       +                /* check for valid port: range 1 - 65535, may be empty */
       +                errno = 0;
       +                l = strtol(u->port, &endptr, 10);
       +                if (i && (errno || *endptr || l <= 0 || l > 65535))
       +                        return -1;
       +                p += i;
       +        }
       +
       +parsepath:
       +        /* path */
       +        if ((i = strcspn(p, "?#")) >= sizeof(u->path))
       +                return -1; /* path too long */
       +        memcpy(u->path, p, i);
       +        u->path[i] = '\0';
       +        p += i;
       +
       +        /* query */
       +        if (*p == '?') {
       +                p++;
       +                if ((i = strcspn(p, "#")) >= sizeof(u->query))
       +                        return -1; /* query too long */
       +                memcpy(u->query, p, i);
       +                u->query[i] = '\0';
       +                p += i;
       +        }
       +
       +        /* fragment */
       +        if (*p == '#') {
       +                p++;
       +                if ((i = strlen(p)) >= sizeof(u->fragment))
       +                        return -1; /* fragment too long */
       +                memcpy(u->fragment, p, i);
       +                u->fragment[i] = '\0';
       +        }
       +
       +        return 0;
       +}
       +
       +char *
       +xstrdup(const char *in)
       +{
       +        if (in != NULL)
       +                return estrdup(in);
       +        return NULL;
       +}
       +
       +void
       +clear_and_free(char *ptr)
       +{
       +        if (ptr != NULL) {
       +                explicit_bzero(ptr, strlen(ptr));
       +                free(ptr);
       +        }
       +}
       +
       +void
       +free_errno(void *ptr)
       +{
       +        int saved_errno = errno;
       +        free(ptr);
       +        errno = saved_errno;
       +}
       +
       +int
       +usmb_statfs(const char *path, struct statvfs *vfs)
       +{
       +        if (path == NULL || vfs == NULL)
       +                return -EINVAL;
       +
       +        char *url = make_url(path);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        memset(vfs, 0, sizeof(*vfs));
       +
       +        int ret = (0 > smbc_getFunctionStatVFS(ctx) (ctx, url, vfs)) ? -errno : 0;
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +compat_truncate(const char *path UNUSED, SMBCFILE *file, off_t size)
       +{
       +        return (0 > smbc_getFunctionFtruncate(ctx) (ctx, file, size)) ? -errno : 0;
       +}
       +
       +static bool
       +change_blksiz(struct stat *st)
       +{
       +        if (st == NULL)
       +                return false;
       +
       +        /* change block size to improve performance of stdio FILE * operations,
       +           only for regular files to be on the safe side. */
       +        if (S_ISREG(st->st_mode)) {
       +                st->st_blksize = 32768;
       +                return true;
       +        }
       +
       +        return false;
       +}
       +
       +/* Samba gets st_nlink wrong for directories. */
       +/* still wrong in 2025-03-03 with Samba 4.20 */
       +static bool
       +fix_nlink(const char *url, struct stat *st)
       +{
       +        if (!S_ISDIR(st->st_mode))
       +                return true;
       +
       +        SMBCFILE *file = smbc_getFunctionOpendir(ctx) (ctx, url);
       +        if (file == NULL)
       +                return false;
       +
       +        st->st_nlink = 0;
       +        errno = ERANGE;
       +
       +        struct smbc_dirent *dirent;
       +        while (NULL != (dirent = smbc_getFunctionReaddir(ctx) (ctx, file))) {
       +                if (SMBC_DIR == dirent->smbc_type) {
       +                        if (INT_MAX == st->st_nlink++) {
       +                                break;
       +                        }
       +                }
       +        }
       +
       +        (void)smbc_getFunctionClosedir(ctx) (ctx, file);
       +
       +        return (dirent == NULL);
       +}
       +
       +int
       +usmb_getattr(const char *filename, struct stat *st)
       +{
       +        char *url = make_url(filename);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        int ret = smbc_getFunctionStat(ctx) (ctx, url, st);
       +
       +        if ((0 > ret) || !fix_nlink(url, st))
       +                ret = -errno;
       +
       +        change_blksiz(st);
       +
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_fgetattr(const char *filename UNUSED, struct stat *st,
       +              struct fuse_file_info *fi)
       +{
       +        SMBCFILE *file = fd_to_smbcfile(fi->fh);
       +
       +        if (0 > smbc_getFunctionFstat(ctx) (ctx, file, st))
       +                return -errno;
       +
       +        if (S_ISDIR(st->st_mode)) {
       +                char *url = make_url(filename);
       +                if (url == NULL)
       +                        return -ENOMEM;
       +
       +                bool ok = fix_nlink(url, st);
       +                free_errno(url);
       +
       +                if (!ok)
       +                        return -errno;
       +        }
       +
       +        change_blksiz(st);
       +
       +        return 0;
       +}
       +
       +int
       +usmb_unlink(const char *filename)
       +{
       +        char *url = make_url(filename);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        int ret = (0 > smbc_getFunctionUnlink(ctx) (ctx, url)) ? -errno : 0;
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_open(const char *filename, struct fuse_file_info *fi)
       +{
       +        char *url = make_url(filename);
       +
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        SMBCFILE *file = smbc_getFunctionOpen(ctx) (ctx, url, fi->flags, 0);
       +
       +        int ret = (file == NULL) ? -errno : 0;
       +        free(url);
       +        fi->fh = smbcfile_to_fd(file);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_release(const char *filename UNUSED, struct fuse_file_info *fi)
       +{
       +        SMBCFILE *file = fd_to_smbcfile(fi->fh);
       +        return (0 > smbc_getFunctionClose(ctx) (ctx, file)) ? -errno : 0;
       +}
       +
       +int
       +usmb_read(const char *filename UNUSED, char *buff, size_t len, off_t off,
       +          struct fuse_file_info *fi)
       +{
       +        SMBCFILE *file = fd_to_smbcfile(fi->fh);
       +
       +        if (0 > smbc_getFunctionLseek(ctx) (ctx, file, off, SEEK_SET)) {
       +                return -errno;
       +        }
       +
       +        int bytes = smbc_getFunctionRead(ctx) (ctx, file, buff, len);
       +
       +        return (0 > bytes) ? -errno : (int)bytes;
       +}
       +
       +int
       +usmb_write(const char *filename UNUSED, const char *buff, size_t len,
       +           off_t off, struct fuse_file_info *fi)
       +{
       +        SMBCFILE *file = fd_to_smbcfile(fi->fh);
       +        size_t written = 0;
       +        int bytes = 0;
       +
       +        if (0 > smbc_getFunctionLseek(ctx)(ctx, file, off, SEEK_SET))
       +                return -errno;
       +
       +        const smbc_write_fn write_fn = smbc_getFunctionWrite(ctx);
       +        while (written < len) {
       +                bytes = write_fn(ctx, file, (char *)buff, len);
       +                if (0 > bytes)
       +                        break;
       +
       +                written += bytes;
       +                buff += bytes;
       +
       +                /* avoids infinite loops. */
       +                if (bytes == 0)
       +                        break;
       +        }
       +
       +        return (0 > bytes) ? -errno : (int)written;
       +}
       +
       +/* File systems must support mknod on OpenBSD */
       +int
       +usmb_mknod(const char *filename, mode_t mode, __attribute__((unused)) dev_t dev)
       +{
       +        char *url = make_url(filename);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode) || S_ISSOCK(mode))
       +                return -EPERM;
       +
       +        SMBCFILE *file = smbc_getFunctionCreat(ctx) (ctx, url, mode);
       +        int ret = (file == NULL) ? -errno : 0;
       +
       +        /* File must not be open when mknod returns. */
       +        if (ret == 0)
       +                smbc_getFunctionClose(ctx) (ctx, file);
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_create(const char *filename, mode_t mode, struct fuse_file_info *fi)
       +{
       +        char *url = make_url(filename);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        SMBCFILE *file = smbc_getFunctionCreat(ctx) (ctx, url, mode);
       +
       +        int ret = (file == NULL) ? -errno : 0;
       +        fi->fh = smbcfile_to_fd(file);
       +
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_rename(const char *from, const char *to)
       +{
       +        char *fromurl = make_url(from);
       +        if (fromurl == NULL)
       +                return -ENOMEM;
       +
       +        char *tourl = make_url(to);
       +        if (tourl == NULL) {
       +                free(fromurl);
       +                return -ENOMEM;
       +        }
       +
       +        int ret =
       +            (0 > smbc_getFunctionRename(ctx)(ctx, fromurl, ctx, tourl)) ? -errno : 0;
       +        free(tourl);
       +        free(fromurl);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_utime(const char *filename, struct utimbuf *utb)
       +{
       +        struct utimbuf tmp_utb;
       +
       +        if (utb == NULL) {
       +                for (;;) {
       +                        time_t now = time(NULL);
       +                        if (now != (time_t)-1) {
       +                                tmp_utb.actime = tmp_utb.modtime = now;
       +                                break;
       +                        }
       +
       +                        if (EINTR != errno)
       +                                return -errno;
       +
       +                        usleep(1000); /* sleep a bit to not hog the CPU */
       +                }
       +                utb = &tmp_utb;
       +        }
       +
       +        char *url = make_url(filename);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        struct timeval tv[2] = {
       +                { .tv_sec = utb->actime,  .tv_usec = 0 },
       +                { .tv_sec = utb->modtime, .tv_usec = 0 },
       +        };
       +
       +        int ret = (0 > smbc_getFunctionUtimes (ctx) (ctx, url, tv)) ? -errno : 0;
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_chmod(const char *filename, mode_t mode)
       +{
       +        char *url = make_url(filename);
       +
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        int ret = (0 > smbc_getFunctionChmod(ctx) (ctx, url, mode)) ? -errno : 0;
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_truncate(const char *filename, off_t newsize)
       +{
       +        char *url = make_url(filename);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        SMBCFILE *file = smbc_getFunctionOpen(ctx) (ctx, url, O_WRONLY, 0);
       +        if (file == NULL) {
       +                int ret = -errno;
       +                free(url);
       +                return ret;
       +        }
       +
       +        int ret = compat_truncate(filename, file, newsize);
       +
       +        smbc_getFunctionClose(ctx) (ctx, file);
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_ftruncate(const char *path, off_t size,
       +               struct fuse_file_info *fi)
       +{
       +        return compat_truncate(path, fd_to_smbcfile(fi->fh), size);
       +}
       +
       +/* directory operations below */
       +
       +int
       +usmb_mkdir(const char *dirname, mode_t mode)
       +{
       +        char *url = make_url(dirname);
       +
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        int ret = smbc_getFunctionMkdir(ctx) (ctx, url, mode) ? -errno : 0;
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_rmdir(const char *dirname)
       +{
       +        char *url = make_url(dirname);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        int ret = smbc_getFunctionRmdir(ctx) (ctx, url) ? -errno : 0;
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_opendir(const char *dirname, struct fuse_file_info *fi)
       +{
       +        char *url = make_url(dirname);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        SMBCFILE *file = smbc_getFunctionOpendir(ctx) (ctx, url);
       +
       +        int ret = (file == NULL) ? -errno : 0;
       +        free(url);
       +
       +        fi->fh = smbcfile_to_fd(file);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_readdir(const char *path, void *h, fuse_fill_dir_t filler,
       +             off_t offset UNUSED, struct fuse_file_info *fi UNUSED)
       +{
       +        SMBCCTX *ctx_ = NULL;
       +        SMBCFILE *file = NULL;
       +        char *url = NULL;
       +        struct smbc_dirent *dirent;
       +        struct stat stbuf;
       +        int ret = 0;
       +
       +        if (!create_smb_context(&ctx_))
       +                return -errno;
       +
       +        do {
       +                url = make_url(path);
       +                if (url == NULL) {
       +                        ret = -ENOMEM;
       +                        break;
       +                }
       +
       +                file = smbc_getFunctionOpendir(ctx_) (ctx_, url);
       +                if (file == NULL) {
       +                        ret = -errno;
       +                        break;
       +                }
       +
       +                smbc_getFunctionLseekdir(ctx_) (ctx_, file, 0);
       +
       +                while (NULL != (dirent = smbc_getFunctionReaddir(ctx_) (ctx_, file))) {
       +                        memset(&stbuf, 0, sizeof(stbuf));
       +                        stbuf.st_ino = arc4random();
       +
       +                        switch (dirent->smbc_type)  {
       +                        case SMBC_DIR:
       +                                stbuf.st_mode = S_IFDIR;
       +                                break;
       +                        case SMBC_FILE:
       +                                stbuf.st_mode = S_IFREG;
       +                                break;
       +                        case SMBC_LINK:
       +                                stbuf.st_mode = S_IFLNK;
       +                                break;
       +                        default:
       +                                break;
       +                        }
       +
       +                        if (1 == filler(h, dirent->name, &stbuf, 0)) { /* if error */
       +                                ret = -1;
       +                                break;
       +                        }
       +                }
       +        } while (false /*CONSTCOND*/);
       +
       +        if (file != NULL)
       +                (void)smbc_getFunctionClosedir(ctx_) (ctx_, file);
       +
       +        free(url);
       +        destroy_smb_context(ctx_, 0);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_releasedir(const char *path UNUSED, struct fuse_file_info *fi)
       +{
       +        SMBCFILE *file = fd_to_smbcfile(fi->fh);
       +
       +        return (0 > smbc_getFunctionClosedir(ctx) (ctx, file)) ? -errno : 0;
       +}
       +
       +int
       +usmb_setxattr(const char *path, const char *name, const char *value,
       +              size_t size, int flags)
       +{
       +        char *url = make_url(path);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        int ret = smbc_getFunctionSetxattr(ctx) (ctx, url, name,
       +                value, size, flags) ? -errno : 0;
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_getxattr(const char *path, const char *name, char *value, size_t size)
       +{
       +        char *url = make_url(path);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        int ret = smbc_getFunctionGetxattr(ctx) (ctx, url, name,
       +                value, size) ?  -errno : 0;
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_listxattr(const char *path, char *list, size_t size)
       +{
       +        char *url = make_url(path);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        int ret = smbc_getFunctionListxattr(ctx) (ctx, url, list, size) ? -errno : 0;
       +        free(url);
       +
       +        return ret;
       +}
       +
       +int
       +usmb_removexattr(const char *path, const char *name)
       +{
       +        char *url = make_url(path);
       +        if (url == NULL)
       +                return -ENOMEM;
       +
       +        int ret = smbc_getFunctionRemovexattr(ctx) (ctx, url, name) ? -errno : 0;
       +        free(url);
       +
       +        return ret;
       +}
       +
       +char *
       +make_url(const char *path)
       +{
       +        size_t len;
       +        char *p;
       +
       +        /* no path or path is empty */
       +        if ((path == NULL) || (path[0] == '\0')) {
       +                return xstrdup(sharename);
       +        } else {
       +                len = strlen(sharename) + strlen(path) + 1;
       +                p = emalloc(len);
       +                snprintf(p, len, "%s%s", sharename, path);
       +                return p;
       +        }
       +}
       +
       +static void
       +auth_fn(const char *srv UNUSED, const char *shr UNUSED,
       +        char *wg, int wglen, char *un, int unlen,
       +        char *pw, int pwlen)
       +{
       +        /* snprintf is used in this way to behave similar to strlcpy(), for portability */
       +
       +        if (opt_domain != NULL)
       +                snprintf(wg, wglen, "%s", opt_domain);
       +        else if (wglen)
       +                wg[0] = '\0'; /* no domain */
       +
       +        snprintf(un, unlen, "%s", opt_username);
       +        snprintf(pw, pwlen, "%s", opt_password);
       +}
       +
       +void
       +destroy_smb_context(SMBCCTX *ctx_, int shutdown)
       +{
       +        /* Samba frees the workgroup and user strings but we want to persist them. */
       +        smbc_setWorkgroup(ctx_, NULL);
       +        smbc_setUser(ctx_, NULL);
       +        smbc_free_context(ctx_, shutdown);
       +}
       +
       +bool
       +create_smb_context(SMBCCTX **pctx)
       +{
       +        *pctx = smbc_new_context();
       +
       +        if (*pctx == NULL) {
       +                perror("Cannot create SMB context");
       +                return false;
       +        }
       +
       +        smbc_setWorkgroup(*pctx, opt_domain);
       +        smbc_setUser(*pctx, opt_username);
       +        smbc_setTimeout(*pctx, 5000);
       +        smbc_setFunctionAuthData(*pctx, auth_fn);
       +
       +        if (smbc_init_context(*pctx) == NULL) {
       +                perror("Cannot initialise SMB context");
       +                destroy_smb_context(*pctx, 1);
       +                return false;
       +        }
       +
       +        return true;
       +}
       +
       +static void *
       +usmb_init(struct fuse_conn_info *conn UNUSED)
       +{
       +        return NULL;
       +}
       +
       +static void
       +usmb_destroy(void *unused UNUSED)
       +{
       +}
       +
       +// probably won't (can't ?) implement these:
       +// readlink symlink flush fsync
       +
       +// no easy way of implementing these:
       +// access
       +
       +#define SET_ELEMENT(name,value) name = value
       +
       +static struct fuse_operations fuse_ops = {
       +  SET_ELEMENT (.getattr, usmb_getattr),
       +  SET_ELEMENT (.readlink, NULL),
       +  SET_ELEMENT (.getdir, NULL),
       +  SET_ELEMENT (.mknod, usmb_mknod),
       +  SET_ELEMENT (.mkdir, usmb_mkdir),
       +  SET_ELEMENT (.unlink, usmb_unlink),
       +  SET_ELEMENT (.rmdir, usmb_rmdir),
       +  SET_ELEMENT (.symlink, NULL),
       +  SET_ELEMENT (.rename, usmb_rename),
       +  SET_ELEMENT (.link, NULL),
       +  SET_ELEMENT (.chmod, usmb_chmod),
       +  SET_ELEMENT (.chown, NULL), // usmb_chown, --not implemented in libsmbclient
       +  SET_ELEMENT (.truncate, usmb_truncate),
       +  SET_ELEMENT (.utime, usmb_utime),
       +  SET_ELEMENT (.open, usmb_open),
       +  SET_ELEMENT (.read, usmb_read),
       +  SET_ELEMENT (.write, usmb_write),
       +  SET_ELEMENT (.statfs, usmb_statfs),
       +  SET_ELEMENT (.flush, NULL),
       +  SET_ELEMENT (.release, usmb_release),
       +  SET_ELEMENT (.fsync, NULL),
       +  SET_ELEMENT (.setxattr, usmb_setxattr),
       +  SET_ELEMENT (.getxattr, usmb_getxattr),
       +  SET_ELEMENT (.listxattr, usmb_listxattr),
       +  SET_ELEMENT (.removexattr, usmb_removexattr),
       +  SET_ELEMENT (.opendir, usmb_opendir),
       +  SET_ELEMENT (.readdir, usmb_readdir),
       +  SET_ELEMENT (.releasedir, usmb_releasedir),
       +  SET_ELEMENT (.fsyncdir, NULL),
       +  SET_ELEMENT (.init, usmb_init),
       +  SET_ELEMENT (.destroy, usmb_destroy),
       +  SET_ELEMENT (.access, NULL),
       +  SET_ELEMENT (.create, usmb_create),
       +  SET_ELEMENT (.ftruncate, usmb_ftruncate),
       +  SET_ELEMENT (.fgetattr, usmb_fgetattr),
       +  SET_ELEMENT (.lock, NULL),                   // TODO: implement
       +  SET_ELEMENT (.utimens, NULL),                // TODO: implement
       +  SET_ELEMENT (.bmap, NULL),                   // TODO: implement
       +};
       +
       +static char *
       +create_share_name(const char *server_, const char *sharename)
       +{
       +        /* len: + 2 for "/" and NUL terminator */
       +        size_t len = strlen("smb://") + strlen(server_) + strlen(sharename) + 2;
       +        char *p;
       +
       +        p = emalloc(len);
       +        snprintf(p, len, "smb://%s/%s", server_, sharename);
       +
       +        return p;
       +}
       +
       +static bool
       +check_credentials(void)
       +{
       +        char *url = make_url("");
       +        if (url == NULL) {
       +                errno = ENOMEM;
       +                return false;
       +        }
       +
       +        struct stat stat_;
       +        bool ret = (0 == (smbc_getFunctionStat(ctx) (ctx, url, &stat_)));
       +
       +        free_errno(url);
       +
       +        return ret;
       +}
       +
       +static bool
       +get_context(void)
       +{
       +        ctx = NULL;
       +
       +        if (disconnect)
       +                return false;
       +
       +        disconnect = 1;
       +        if (!create_smb_context(&ctx))
       +                return false;
       +
       +        if (!check_credentials()) {
       +                perror("Connection failed");
       +                destroy_smb_context(ctx, 1);
       +                ctx = NULL;
       +                return NULL;
       +        }
       +
       +        disconnect = 0;
       +
       +        return (ctx != NULL);
       +}
       +
       +void
       +show_about(FILE *fp)
       +{
       +        fprintf(fp, "susmb - mount SMB shares via FUSE and Samba\n"
       +                "\n"
       +                "Copyright (C) 2025 Hiltjo Posthuma.\n"
       +                "Copyright (C) 2006-2013 Geoff Johnstone.\n"
       +                "\n"
       +                "Licensed under the GNU General Public License.\n"
       +                "susmb comes with ABSOLUTELY NO WARRANTY; "
       +                "for details please see\n"
       +                "http://www.gnu.org/licenses/gpl.txt\n"
       +                "\n"
       +                "Please send bug reports, patches etc. to hiltjo@codemadness.org\n");
       +}
       +
       +void
       +show_version(FILE *fp)
       +{
       +        show_about(fp);
       +        fputc('\n', fp);
       +        fprintf(fp, "susmb version: %s\n"
       +                "FUSE version: %d.%d\n"
       +                "Samba version: %s\n",
       +                SUSMB_VERSION,
       +                FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION,
       +                smbc_version());
       +}
       +
       +void
       +usage(void)
       +{
       +        fprintf(stdout,
       +                "Usage: %s [-dfv] [-o options] [-u user] [-g gid] <smb://domain\\user@server/sharename> <mountpoint>\n"
       +                "\n"
       +                "Options:\n"
       +                "  -d Debug mode\n"
       +                "  -f Foreground operation\n"
       +                "  -o Additional FUSE options\n"
       +                "  -u Privdrop to user and its group or uid\n"
       +                "  -g Privdrop to group id\n"
       +                "  -v Show program, FUSE and Samba versions\n", argv0);
       +        exit(1);
       +}
       +
       +/* FUSE args are:
       + *
       + * argv[0]
       + * -s
       + * -d          -- if debug mode requested
       + * -f          -- if foreground mode requested
       + * -o ...      -- if any mount options in the config file
       + * mount point
       + */
       +#define MAXARGS 12
       +void build_fuse_args(const char *options, const char *mountpoint,
       +                     int debug, int nofork,
       +                     int *out_argc, char ***out_argv)
       +{
       +        static char SUSMB[] = "susmb";
       +        static char MINUS_S[] = "-s";
       +        static char MINUS_D[] = "-d";
       +        static char MINUS_F[] = "-f";
       +        static char MINUS_O[] = "-o";
       +        static char *argv[MAXARGS];
       +        int argc = 0;
       +
       +        argv[argc++] = SUSMB;
       +        argv[argc++] = MINUS_S;
       +
       +        if (debug)
       +                argv[argc++] = MINUS_D;
       +
       +        if (nofork)
       +                argv[argc++] = MINUS_F;
       +
       +        if ((options != NULL) && (options[0] != '\0')) {
       +                argv[argc++] = MINUS_O;
       +                argv[argc++] = (char *)options;
       +        }
       +
       +        argv[argc++] = (char *)mountpoint;
       +        argv[argc] = NULL;
       +
       +        *out_argc = argc;
       +        *out_argv = argv;
       +}
       +
       +int usmb_fuse_main(int argc, char *argv[],
       +                   const struct fuse_operations *op, size_t op_size,
       +                   void *user_data)
       +{
       +        struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
       +        struct fuse *fuse = NULL;
       +        struct fuse_chan *chan = NULL;
       +        struct fuse_session *session = NULL;
       +        int fd, res = 1;
       +        int fflag = 0, sflag = 0;
       +        char *mountpoint = NULL;
       +
       +        if (fuse_parse_cmdline(&args, &mountpoint, &sflag, &fflag) != 0)
       +                return 1;
       +
       +        if (mountpoint == NULL || *mountpoint == '\0') {
       +                warnx("error: no mountpoint specified");
       +                res = 2;
       +                goto out1;
       +        }
       +
       +        chan = fuse_mount(mountpoint, &args);
       +        if (chan == NULL) {
       +                res = 4;
       +                goto out2;
       +        }
       +
       +        fuse = fuse_new(chan, &args, op, op_size, user_data);
       +        if (fuse == NULL) {
       +                res = 3;
       +                goto out1;
       +        }
       +
       +        /* daemonize */
       +        if (!fflag) {
       +                switch (fork()) {
       +                case -1:
       +                        res = 5;
       +                        warn("fork");
       +                        goto out3;
       +                case 0:
       +                        break;
       +                default:
       +                        _exit(0);
       +                }
       +
       +                if (setsid() == -1) {
       +                        res = 5;
       +                        warn("setsid");
       +                        goto out3;
       +                }
       +
       +                (void)chdir("/"); /* nochdir */
       +
       +                /* noclose */
       +                if ((fd = open("/dev/null", O_RDWR)) != -1) {
       +                        (void)dup2(fd, STDIN_FILENO);
       +                        (void)dup2(fd, STDOUT_FILENO);
       +                        (void)dup2(fd, STDERR_FILENO);
       +                        if (fd > 2)
       +                                (void)close(fd);
       +                }
       +        }
       +
       +        /* setup signal handlers: can only be used if privdrop is not used */
       +        if (!opt_privdrop) {
       +                session = fuse_get_session(fuse);
       +                if (fuse_set_signal_handlers(session) != 0) {
       +                        res = 6;
       +                        goto out3;
       +                }
       +        }
       +
       +        /* privdrop */
       +        if (opt_privdrop) {
       +                if (setresgid(opt_uid, opt_uid, opt_uid) == -1)
       +                        err(1, "setresgid");
       +                if (setresuid(opt_gid, opt_gid, opt_gid) == -1)
       +                        err(1, "setresuid");
       +        }
       +
       +        res = fuse_loop(fuse);
       +        if (res)
       +                res = 8;
       +
       +        if (!opt_privdrop) {
       +                if (session)
       +                        fuse_remove_signal_handlers(session);
       +        }
       +
       +out3:
       +        if (chan)
       +                fuse_unmount(mountpoint, chan);
       +out2:
       +        if (fuse)
       +                fuse_destroy(fuse);
       +out1:
       +        return res;
       +}
       +
       +int
       +main(int argc, char **argv)
       +{
       +        struct uri u;
       +        struct passwd *pw;
       +        char *tmp, *p;
       +        char **fuse_argv;
       +        int fuse_argc;
       +        int ch, ret = 1;
       +        long l;
       +
       +        while ((ch = getopt(argc, argv, "hvVdfo:u:g:")) != -1) {
       +                switch (ch) {
       +                case 'd':
       +                        opt_debug = 1;
       +                        break;
       +                case 'f':
       +                        opt_nofork = 1;
       +                        break;
       +                case 'o':
       +                        opt_options = xstrdup(optarg);
       +                        break;
       +                case 'h':
       +                        usage();
       +                        break;
       +                case 'u':
       +                        opt_privdrop = 1;
       +                        /* by username: use uid and gid from passwd entry */
       +                        if ((pw = getpwnam(optarg)) != NULL) {
       +                                opt_uid = pw->pw_uid;
       +                                opt_gid = pw->pw_gid;
       +                        } else {
       +                                /* try to parse number */
       +                                errno = 0;
       +                                l = strtol(optarg, NULL, 10);
       +                                if (l <= 0 || errno)
       +                                        usage();
       +                                opt_uid = (uid_t)l;
       +                        }
       +                        break;
       +                case 'g':
       +                        opt_privdrop = 1;
       +                        /* parse gid as number */
       +                        errno = 0;
       +                        l = strtol(optarg, NULL, 10);
       +                        if (l <= 0 || errno)
       +                                usage();
       +                        opt_gid = (gid_t)l;
       +                        break;
       +                case 'v':
       +                case 'V':
       +                        show_version(stdout);
       +                        exit(0);
       +                        break;
       +                default:
       +                        usage();
       +                }
       +        }
       +
       +        argc -= optind;
       +        argv += optind;
       +
       +        if (opt_privdrop && (opt_uid == 0 || opt_gid == 0))
       +                usage();
       +
       +        /* password is read from enviroment variable.
       +           It is assumed the environment is secure */
       +        if ((tmp = getenv("SMB_PASS")) != NULL)
       +                opt_password = xstrdup(tmp);
       +
       +        /* options were succesfully parsed */
       +        if (ch == '?' || ch == ':') {
       +                usage();
       +                return 0;
       +        }
       +
       +        if (argc != 2)
       +                usage();
       +
       +        /* parse URI */
       +        tmp = xstrdup(argv[0]);
       +        if (uri_parse(tmp, &u) == -1)
       +                usage();
       +
       +        /* check required options and format */
       +        if (strcmp(u.proto, "smb://") ||
       +            u.userinfo[0] == '\0' ||
       +            u.host[0] == '\0' ||
       +            u.path[0] != '/') {
       +                usage();
       +        }
       +
       +        /* password in userinfo field is not allowed */
       +        if (strchr(u.userinfo, ':')) {
       +                fprintf(stderr, "password must be specified via $SMB_PASS\n\n");
       +                usage();
       +        }
       +
       +        /* split domain\user if '\' is found */
       +        if ((p = strchr(u.userinfo, '\\'))) {
       +                *p = '\0';
       +                opt_domain = xstrdup(u.userinfo);
       +                opt_username = xstrdup(p + 1);
       +        } else {
       +                opt_domain = xstrdup("");
       +                opt_username = xstrdup(u.userinfo);
       +        }
       +
       +        opt_server = xstrdup(u.host);
       +        opt_share = xstrdup(u.path + 1); /* share name, "/Sharename" -> "Sharename". */
       +        free(tmp);
       +
       +        opt_mountpoint = xstrdup(argv[1]);
       +
       +        if (opt_mountpoint == NULL || opt_mountpoint[0] == '\0' ||
       +            opt_server == NULL || opt_server[0] == '\0' ||
       +            opt_share == NULL || opt_share[0] == '\0' ||
       +            opt_username == NULL || opt_username[0] == '\0' ||
       +            opt_password == NULL) {
       +                usage();
       +        }
       +
       +        if (unveil("/", "") == -1)
       +                err(1, "unveil");
       +        /* required for daemonize mode and ignoring output */
       +        if (unveil("/dev/null", "rw") == -1)
       +                err(1, "unveil");
       +        /* read-write permissions to OpenBSD FUSE driver */
       +        if (unveil("/dev/fuse0", "rw") == -1)
       +                err(1, "unveil");
       +        /* (r)ead, (w)rite, e(x)ecute, (c)reate permissions to mountpoint */
       +        if (unveil(opt_mountpoint, "rwxc") == -1)
       +                err(1, "unveil");
       +        /* lock further unveil calls */
       +        if (unveil(NULL, NULL) == -1)
       +                err(1, "unveil");
       +
       +        sharename = create_share_name(opt_server, opt_share);
       +        if (sharename != NULL) {
       +                if (get_context()) {
       +                        build_fuse_args(opt_options, opt_mountpoint, opt_debug, opt_nofork, &fuse_argc, &fuse_argv);
       +                        ret = usmb_fuse_main(fuse_argc, fuse_argv, &fuse_ops, sizeof(fuse_ops), NULL);
       +                        destroy_smb_context(ctx, 1);
       +                }
       +        }
       +
       +        free(sharename);
       +        clear_and_free(opt_password);
       +        free(opt_username);
       +        free(opt_domain);
       +        free(opt_options);
       +        free(opt_mountpoint);
       +        free(opt_share);
       +        free(opt_server);
       +
       +        return ret;
       +}
 (DIR) diff --git a/usmb.1 b/usmb.1
       @@ -1,156 +0,0 @@
       -.\" Copyright (C) 2010 Geoff Johnstone.
       -.\" See section COPYING for conditions for redistribution.
       -.TH usmb 1 "April 2010" "usmb" "User Commands"
       -.fp 0 CR
       -.SH NAME
       -usmb \- Mount SMB/CIFS shares via FUSE
       -.SH SYNOPSIS
       -usmb [\-c \fIfile\fR] [\-d] [\-f] \fImount_id\fR
       -.br
       -usmb [\-c \fIfile\fR] \-u \fImount_id\fR
       -.SH DESCRIPTION
       -.P
       -usmb mounts SMB and CIFS shares through FUSE, including Samba shares and
       -Windows shared folders. Unlike some other such filesystems, usmb can mount
       -shares from any server, including those not browsable or advertised on the
       -network.
       -.P
       -Shares, usernames and other details are defined in a configuration file, by
       -default ${HOME}/.usmb.conf.
       -.SH OPTIONS
       -.TP
       -\fB\-c\fR \fIfile\fR, \fB\-\-config\fR=\fIfile\fR
       -Use \fIfile\fR rather than ${HOME}/.usmb.conf as the configuration file.
       -.TP
       -\fB\-d\fR, \fB\-\-debug\fR
       -Debug mode.
       -.TP
       -\fB\-f\fR, \fB\-\-nofork\fR
       -Foreground operation (i.e. don't daemonise).
       -.TP
       -\fB\-h\fR, \fB\-\-help\fR
       -Show usage information and exit.
       -.TP
       -\fB\-u\fR, \fB\-\-unmount\fR
       -Unmount the given filesystem.
       -.TP
       -\fB\-v\fR, \fB\-\-version\fR
       -Show usmb, FUSE and Samba versions and exit.
       -.P
       -.SH CONFIGURATION
       -.P
       -usmb uses the configuration file ${HOME}/.usmb.conf to define shares and the
       -credentials used to access them. The configuration file is an XML file with
       -two main elements: credentials and mounts. The file can contain any number of
       -credentials and mounts elements; the whole file is wrapped in a usmbconfig
       -element.
       -.SS Credentials
       -.P
       -.ft CR
       -  <credentials id="\fIID used in mount elements\f(CR">
       -    <domain>\fIdomain or workgroup\f(CR</domain>
       -    <username>\fIusername\f(CR</username>
       -    <password>\fIpassword (optional)\f(CR</password>
       -  </credentials>
       -.P
       -Each credentials element defines a domain/username/password triple. If you
       -omit the <password> element then usmb will prompt for a password when the
       -credentials are used.
       -.SS Mounts
       -.P
       -.ft CR
       -  <mount id="\fImount_id\f(CR" credentials="\fIID of credentials to use\f(CR">
       -    <server>\fIhostname or IP address of server\f(CR</server>
       -    <share>\fIshare name\f(CR</share>
       -    <mountpoint>\fI/path/to/mount/point\f(CR</mountpoint>
       -    <options>\fImount options\f(CR</options>
       -  </mount>
       -.P
       -A mount element describes a share. The id attribute is given on the usmb
       -command line to identify the share to mount. The credentials attribute
       -identified the id of the credentials element to use. The (optional) options
       -element gives a comma-separated list of FUSE mount options:
       -.TP
       -\fBhard_remove\fR
       -Immediate removal (don't hide files)
       -.TP
       -\fBumask=M\fR
       -Set file permissions (octal)
       -.TP
       -\fBuid=N\fR
       -Set file owner
       -.TP
       -\fBgid=N\fR
       -Set file group
       -.TP
       -\fBallow_other\fR
       -Allow access to other users
       -.TP
       -\fBallow_root\fR
       -Allow access to root
       -.TP
       -\fBnonempty\fR
       -Allow mount over non-empty directory
       -.SS Example
       -.P
       -.ft CR
       -<?xml version="1.0" encoding="ISO-8859-1"?>
       -.br
       -<usmbconfig>
       -
       -  <credentials id="cred1">
       -    <domain>WORKGROUP</domain>
       -    <username>user</username>
       -    <password>pass</password>
       -  </credentials>
       -
       -  <credentials id="cred2">
       -    <domain>mydomain</domain>
       -    <username>anotheruser</username>
       -    <!--  No password element => prompt for password at runtime. -->
       -  </credentials>
       -
       -  <mount id="home" credentials="cred1">
       -    <server>192.168.0.5</server>
       -    <share>myshare</share>
       -    <mountpoint>/tmp/smb</mountpoint>
       -  </mount>
       -
       -  <mount id="music" credentials="cred2">
       -    <server>winbox</server>
       -    <share>music</share>
       -
       -    <!-- You can use ~/xyz or ~user/xyz for the mountpoint. -->
       -    <mountpoint>~/music</mountpoint>
       -    <options>allow_root</options>
       -  </mount>
       -
       -</usmbconfig>
       -.P
       -This defines two shares:
       -.RS 2
       -\\\\192.168.0.5\\myshare on /tmp/smb authenticating as WORKGROUP\\user
       -.br
       -\\\\winbox\\music on ${HOME}/music authenticating as mydomain\\anotheruser
       -.RE
       -.P
       -These can be mounted using "usmb home" or "usmb music".
       -.SH AUTHOR
       -Geoff Johnstone, with contributions from Jonathan Schultz, Stijn Hoop, Nigel
       -Smith and Michal Suchanek.
       -.SH FILES
       -${HOME}/.usmb.conf
       -.SH BUGS
       -.P
       -usmb should not require a configuration file. The configuration file can
       -provide defaults but you should be able to specify everything necessary on
       -the command line.
       -.P
       -usmb does not support Kerberos / GSSAPI authentication, although a development
       -branch exists with preliminary support.
       -.SH "SEE ALSO"
       -fusermount(1), mount.cifs(8), umount.cifs(8).
       -.SH COPYING
       -Copyright \(co 2006-2013 Geoff Johnstone.
       -.br
       -Licence: GNU GPL version 3 <http://gnu.org/licenses/gpl.html>.
 (DIR) diff --git a/usmb.c b/usmb.c
       @@ -1,336 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2013 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <sys/time.h>        // struct timeval needed by libsmbclient.h
       -#include <unistd.h>
       -#include <libsmbclient.h>
       -#include "samba3x-compat.h"
       -#include <fuse.h>
       -#include <assert.h>
       -#include <limits.h>
       -#include <errno.h>
       -#include <stdarg.h>
       -#include <stdbool.h>
       -#include <stddef.h>
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include <string.h>
       -#include "conffile.h"
       -#include "options.h"
       -#include "password.h"
       -#include "usmb.h"
       -#include "usmb_dir.h"
       -#include "usmb_file.h"
       -#include "utils.h"
       -#include "version.h"
       -
       -
       -SMBCCTX *ctx;
       -static char *server, *share, *mountpoint, *options,
       -            *domain, *username, *password;
       -
       -
       -char * make_url (const char *path)
       -{
       -  assert (NULL != share);
       -
       -  if ((NULL == path) || ('\0' == path[0]))
       -    return xstrdup (share);
       -  else
       -    return concat_strings (2, share, path);
       -}
       -
       -
       -static inline void do_strncpy (char *to, const char *from, int tolen)
       -{
       -  strncpy (to, from, tolen);
       -  to[tolen - 1] = '\0';
       -}
       -
       -
       -static void auth_fn (const char *srv UNUSED, const char *shr UNUSED,
       -                     char *wg, int wglen, char *un, int unlen,
       -                     char *pw, int pwlen)
       -{
       -  DEBUG (fprintf (stderr, "Authenticating for \\\\%s\\%s\n", srv, shr));
       -  DEBUG (fprintf (stderr, "Domain: %s; User: %s; Password: %s\n",
       -                  domain, username, password));
       -
       -  if (NULL != domain)
       -    do_strncpy (wg, domain, wglen);
       -
       -  do_strncpy (un, username, unlen);
       -  do_strncpy (pw, password, pwlen);
       -}
       -
       -
       -void destroy_smb_context (SMBCCTX *ctx_, int shutdown)
       -{
       -  // Samba frees the workgroup and user strings but we want to persist them.
       -  smbc_setWorkgroup (ctx_, NULL);
       -  smbc_setUser (ctx_, NULL);
       -  smbc_free_context (ctx_, shutdown);
       -}
       -
       -
       -bool create_smb_context (SMBCCTX **pctx)
       -{
       -  *pctx = smbc_new_context();
       -
       -  if (NULL == *pctx)
       -  {
       -    perror ("Cannot create SMB context");
       -    return false;
       -  }
       -
       -  smbc_setWorkgroup (*pctx, domain);
       -  smbc_setUser (*pctx, username);
       -  smbc_setTimeout (*pctx, 5000);
       -  smbc_setFunctionAuthData (*pctx, auth_fn);
       -
       -  if (NULL == smbc_init_context (*pctx))
       -  {
       -    perror ("Cannot initialise SMB context");
       -    destroy_smb_context (*pctx, 1);
       -    return false;
       -  }
       -
       -  return true;
       -}
       -
       -
       -static void * usmb_init (struct fuse_conn_info *conn UNUSED)
       -{
       -  DEBUG (fputs ("usmb_init()\n", stderr));
       -  return NULL;
       -}
       -
       -
       -static void usmb_destroy (void *unused UNUSED)
       -{
       -  DEBUG (fputs ("usmb_destroy()\n", stderr));
       -}
       -
       -
       -// probably won't (can't ?) implement these:
       -// readlink mknod symlink flush fsync
       -
       -// no easy way of implementing these:
       -// access
       -
       -#ifdef __lint
       -#define SET_ELEMENT(name,value) value
       -#else
       -#define SET_ELEMENT(name,value) name = value
       -#endif
       -static struct fuse_operations fuse_ops = {
       -  SET_ELEMENT (.getattr, usmb_getattr),
       -  SET_ELEMENT (.readlink, NULL),
       -  SET_ELEMENT (.getdir, NULL),
       -  SET_ELEMENT (.mknod, NULL),
       -  SET_ELEMENT (.mkdir, usmb_mkdir),
       -  SET_ELEMENT (.unlink, usmb_unlink),
       -  SET_ELEMENT (.rmdir, usmb_rmdir),
       -  SET_ELEMENT (.symlink, NULL),
       -  SET_ELEMENT (.rename, usmb_rename),
       -  SET_ELEMENT (.link, NULL),
       -  SET_ELEMENT (.chmod, usmb_chmod),
       -  SET_ELEMENT (.chown, NULL), // usmb_chown, --not implemented in libsmbclient
       -  SET_ELEMENT (.truncate, usmb_truncate),
       -  SET_ELEMENT (.utime, usmb_utime),
       -  SET_ELEMENT (.open, usmb_open),
       -  SET_ELEMENT (.read, usmb_read),
       -  SET_ELEMENT (.write, usmb_write),
       -  SET_ELEMENT (.statfs, usmb_statfs),
       -  SET_ELEMENT (.flush, NULL),
       -  SET_ELEMENT (.release, usmb_release),
       -  SET_ELEMENT (.fsync, NULL),
       -  SET_ELEMENT (.setxattr, usmb_setxattr),
       -  SET_ELEMENT (.getxattr, usmb_getxattr),
       -  SET_ELEMENT (.listxattr, usmb_listxattr),
       -  SET_ELEMENT (.removexattr, usmb_removexattr),
       -  SET_ELEMENT (.opendir, usmb_opendir),
       -  SET_ELEMENT (.readdir, usmb_readdir),
       -  SET_ELEMENT (.releasedir, usmb_releasedir),
       -  SET_ELEMENT (.fsyncdir, NULL),
       -  SET_ELEMENT (.init, usmb_init),
       -  SET_ELEMENT (.destroy, usmb_destroy),
       -  SET_ELEMENT (.access, NULL),
       -  SET_ELEMENT (.create, usmb_create),
       -  SET_ELEMENT (.ftruncate, usmb_ftruncate),
       -  SET_ELEMENT (.fgetattr, usmb_fgetattr),
       -  SET_ELEMENT (.lock, NULL),                   // TODO: implement
       -  SET_ELEMENT (.utimens, NULL),                // TODO: implement
       -  SET_ELEMENT (.bmap, NULL),                   // TODO: implement
       -};
       -
       -
       -static bool create_share_name (const char *server_, const char *sharename)
       -{
       -  size_t len = strlen ("smb:///") +
       -               strlen (server_) +
       -               strlen (sharename) + 1;
       -
       -  if (NULL == (share = malloc (len)))
       -  {
       -    perror ("Cannot allocate share name");
       -    return false;
       -  }
       -
       -  if (!bsnprintf (share, len, "smb://%s/%s", server_, sharename))
       -  {
       -    fputs ("Share server and/or name are too long.\n", stderr);
       -    free (share);
       -    return false;
       -  }
       -
       -  DEBUG (fprintf (stderr, "Share URL: %s\n", share));
       -  return true;
       -}
       -
       -
       -static void free_strings (char *sharename)
       -{
       -  xfree (sharename);
       -  clear_and_free (password);
       -  xfree (username);
       -  xfree (domain);
       -  xfree (options);
       -  xfree (mountpoint);
       -  xfree (share);
       -  xfree (server);
       -}
       -
       -
       -static bool check_credentials (void)
       -{
       -  char *url = make_url ("");
       -  if (NULL == url)
       -  {
       -    errno = ENOMEM;
       -    return false;
       -  }
       -
       -  DEBUG (fprintf (stderr, "URL: %s\n", url));
       -
       -  struct stat stat_;
       -  bool ret = (0 == (smbc_getFunctionStat (ctx) (ctx, url, &stat_)));
       -
       -  free_errno (url);
       -  return ret;
       -}
       -
       -
       -static bool get_context (void)
       -{
       -  ctx = NULL;
       -
       -  unsigned attempts = 3;
       -
       -  while (0 != attempts--)
       -  {
       -    if ((NULL == password) && !password_read (&password))
       -      break;
       -
       -    if (!create_smb_context (&ctx))
       -    {
       -      clear_and_free (password);
       -      password = NULL;
       -      ctx = NULL;
       -      break;
       -    }
       -
       -    if (check_credentials())
       -      break;
       -
       -    perror ("Connection failed");
       -    clear_and_free (password);
       -    password = NULL;
       -
       -    destroy_smb_context (ctx, 1);
       -    ctx = NULL;
       -  }
       -
       -  return (NULL != ctx);
       -}
       -
       -
       -int main (int argc, char **argv)
       -{
       -  const char *conffile, *mountid;
       -  bool umount;
       -  char *sharename = NULL;
       -  int ret = EXIT_FAILURE;
       -
       -  if (sizeof (uint64_t) < sizeof (uintptr_t))
       -  {
       -    fputs ("usmb is not supported on this platform.\n", stderr);
       -    return EXIT_FAILURE;
       -  }
       -
       -  {
       -    static char conf[PATH_MAX];
       -    const char * const HOME = getenv ("HOME");
       -    if (NULL == HOME)
       -    {
       -      fputs ("Please set the HOME environment variable.\n", stderr);
       -      return EXIT_FAILURE;
       -    }
       -
       -    if (!bsnprintf (conf, sizeof (conf), "%s/.usmb.conf", HOME))
       -    {
       -      fputs ("Configuration file path is too long.\n", stderr);
       -      return EXIT_FAILURE;
       -    }
       -
       -    conffile = conf;
       -  }
       -
       -  if (!parse_args (&argc, &argv, &mountid, &conffile, &umount))
       -    return EXIT_FAILURE;
       -
       -  if (!umount)
       -    show_about (stdout);
       -
       -  if (!conffile_get_mount (conffile, mountid,
       -                           &server, &sharename, &mountpoint, &options,
       -                           &domain, &username, &password))
       -    return EXIT_FAILURE;
       -
       -  DEBUG (fprintf (stderr, "Mountpoint: %s\n", mountpoint));
       -
       -  if (umount)
       -  {
       -    execlp ("fusermount", "fusermount", "-u", mountpoint, NULL);
       -    perror ("Failed to execute fusermount");
       -  }
       -
       -  else if (create_share_name (server, sharename) && get_context())
       -  {
       -    DEBUG (fprintf (stderr, "Username: %s\\%s\n", domain, username));
       -
       -    int fuse_argc;
       -    char **fuse_argv;
       -    build_fuse_args (options, mountpoint, &fuse_argc, &fuse_argv);
       -    ret = fuse_main (fuse_argc, fuse_argv, &fuse_ops, NULL);
       -    destroy_smb_context (ctx, 1);
       -  }
       -
       -  free_strings (sharename);
       -  return ret;
       -}
       -
 (DIR) diff --git a/usmb.conf b/usmb.conf
       @@ -1,61 +0,0 @@
       -<?xml version="1.0" encoding="ISO-8859-1"?>
       -
       -<!--
       -  Example usmb.conf
       -  =================
       -
       -  This defines two shares:
       -
       -    \\192.168.0.5\myshare on /tmp/smb authenticating as WORKGROUP\user
       -    \\winbox\music on ${HOME}/music authenticating as mydomain\anotheruser
       -
       -  These can be mounted using
       -
       -    usmb home
       -    usmb music
       -
       -  Mount options are comma-separated. Useful options:
       -
       -    hard_remove - immediate removal (don't hide files)
       -    umask=M     - set file permissions (octal)
       -    uid=N       - set file owner
       -    gid=N       - set file group
       -    allow_other - allow access to other users
       -    allow_root  - allow access to root
       -    nonempty    - allow mount over non-empty directory
       -
       --->
       -
       -<usmbconfig>
       -
       -  <credentials id="cred1">
       -    <domain>WORKGROUP</domain>
       -    <username>user</username>
       -    <password>pass</password>
       -  </credentials>
       -
       -  <credentials id="cred2">
       -    <domain>mydomain</domain>
       -    <username>anotheruser</username>
       -    <!--  No password element => prompt for password at runtime.
       -      <password>secret</password>
       -    -->
       -  </credentials>
       -
       -  <mount id="home" credentials="cred1">
       -    <server>192.168.0.5</server>
       -    <share>myshare</share>
       -    <mountpoint>/tmp/smb</mountpoint>
       -  </mount>
       -
       -  <mount id="music" credentials="cred2">
       -    <server>winbox</server>
       -    <share>music</share>
       -
       -    <!-- You can use ~/xyz or ~user/xyz for the mountpoint. -->
       -    <mountpoint>~/music</mountpoint>
       -    <options>allow_root</options>
       -  </mount>
       -
       -</usmbconfig>
       -
 (DIR) diff --git a/usmb.h b/usmb.h
       @@ -1,43 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#ifndef USMB_H
       -  #define USMB_H
       -
       -  #include <stdbool.h>
       -  #include <stdint.h>
       -  #include <libsmbclient.h>
       -
       -  extern SMBCCTX *ctx;
       -
       -  char * make_url (const char *path) MUSTCHECK;
       -
       -  bool create_smb_context (SMBCCTX **pctx) MUSTCHECK;
       -  void destroy_smb_context (SMBCCTX *ctx, int shutdown);
       -
       -  /* fuse_file_info uses a uint64_t for a "File handle" */
       -  static inline uint64_t smbcfile_to_fd (SMBCFILE *file)
       -  {
       -    return (uint64_t)(uintptr_t)file;
       -  }
       -
       -
       -  static inline SMBCFILE * fd_to_smbcfile (uint64_t fd)
       -  {
       -    return (SMBCFILE *)(uintptr_t)fd;
       -  }
       -
       -#endif
 (DIR) diff --git a/usmb_dir.c b/usmb_dir.c
       @@ -1,217 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2013 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <sys/time.h>        // struct timeval needed by libsmbclient.h
       -#include <libsmbclient.h>
       -#include "samba3x-compat.h"
       -#include <fuse.h>
       -#include <dirent.h>
       -#include <errno.h>
       -#include <stdarg.h>
       -#include <stddef.h>
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include <string.h>
       -#include "usmb_dir.h"
       -#include "usmb.h"
       -#include "utils.h"
       -
       -
       -int usmb_mkdir (const char *dirname, mode_t mode)
       -{
       -  char *url = make_url (dirname);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "mkdir (%s)\n", url));
       -  int ret = smbc_getFunctionMkdir (ctx) (ctx, url, mode) ? -errno : 0;
       -  free (url);
       -  return ret;
       -}
       -
       -
       -int usmb_rmdir (const char *dirname)
       -{
       -  char *url = make_url (dirname);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "rmdir (%s)\n", url));
       -  int ret = smbc_getFunctionRmdir (ctx) (ctx, url) ? -errno : 0;
       -  free (url);
       -
       -  return ret;
       -}
       -
       -
       -int usmb_opendir (const char *dirname, struct fuse_file_info *fi)
       -{
       -  char *url = make_url (dirname);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "opendir (%s)", url));
       -  SMBCFILE *file = smbc_getFunctionOpendir (ctx) (ctx, url);
       -  DEBUG (fprintf (stderr, " = %p\n", (void *)file));
       -
       -  int ret = (NULL == file) ? -errno : 0;
       -  free (url);
       -  fi->fh = smbcfile_to_fd (file);
       -
       -  return ret;
       -}
       -
       -
       -int usmb_readdir (const char *path, void *h, fuse_fill_dir_t filler,
       -                  off_t offset UNUSED, struct fuse_file_info *fi UNUSED)
       -{
       -  SMBCCTX *ctx_ = NULL;
       -  SMBCFILE *file = NULL;
       -  char *url = NULL;
       -  struct smbc_dirent *dirent;
       -  int ret = 0;
       -
       -  DEBUG (fprintf (stderr, "readdir (%s)\n", path));
       -
       -  if (!create_smb_context (&ctx_))
       -    return -errno;
       -
       -  do
       -  {
       -    url = make_url (path);
       -    if (NULL == url)
       -    {
       -      ret = -ENOMEM;
       -      break;
       -    }
       -
       -    file = smbc_getFunctionOpendir (ctx_) (ctx_, url);
       -    if (NULL == file)
       -    {
       -      ret = -errno;
       -      break;
       -    }
       -
       -    smbc_getFunctionLseekdir (ctx_) (ctx_, file, 0);
       -
       -    while (NULL != (dirent = smbc_getFunctionReaddir (ctx_) (ctx_, file)))
       -    {
       -      struct stat stbuf;
       -
       -      switch (dirent->smbc_type)
       -      {
       -        case SMBC_DIR:
       -          stbuf.st_mode = DT_DIR << 12;
       -          break;
       -
       -        case SMBC_FILE:
       -          stbuf.st_mode = DT_REG << 12;
       -          break;
       -
       -        case SMBC_LINK:
       -          stbuf.st_mode = DT_LNK << 12;
       -          break;
       -
       -        default:
       -          break;
       -      }
       -
       -      DEBUG (fprintf (stderr, "  %s\n", dirent->name));
       -      if (1 == filler (h, dirent->name, &stbuf, 0))  /* if error */
       -      {
       -        ret = -1;
       -        break;
       -      }
       -    }
       -  } while (false /*CONSTCOND*/);
       -
       -  if (NULL != file)
       -    (void)smbc_getFunctionClosedir (ctx_) (ctx_, file);
       -
       -  if (NULL != url)
       -    free (url);
       -
       -  destroy_smb_context (ctx_, 0);
       -  return ret;
       -}
       -
       -
       -int usmb_releasedir (const char *path UNUSED, struct fuse_file_info *fi)
       -{
       -  SMBCFILE *file = fd_to_smbcfile (fi->fh);
       -  DEBUG (fprintf (stderr, "releasedir (%s, %p)\n", path, (void *)file));
       -  return (0 > smbc_getFunctionClosedir (ctx) (ctx, file)) ? -errno : 0;
       -}
       -
       -
       -int usmb_setxattr (const char *path, const char *name, const char *value,
       -                   size_t size, int flags)
       -{
       -  char *url = make_url (path);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "setxattr (%s, %s, %p, %llu, %x)\n",
       -                  path, url, value, (unsigned long long)size, flags));
       -  int ret = smbc_getFunctionSetxattr (ctx) (ctx, url, name,
       -                                            value, size, flags) ? -errno : 0;
       -  free (url);
       -  return ret;
       -}
       -
       -
       -int usmb_getxattr (const char *path, const char *name, char *value, size_t size)
       -{
       -  char *url = make_url (path);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "getxattr (%s, %s, %p, %llu)\n",
       -                  path, url, value, (unsigned long long)size));
       -  int ret = smbc_getFunctionGetxattr (ctx) (ctx, url, name,
       -                                            value, size) ?  -errno : 0;
       -  free (url);
       -  return ret;
       -}
       -
       -
       -int usmb_listxattr (const char *path, char *list, size_t size)
       -{
       -  char *url = make_url (path);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "listxattr (%s, %p, %llu)\n",
       -                  url, list, (unsigned long long)size));
       -  int ret = smbc_getFunctionListxattr (ctx) (ctx, url, list, size) ? -errno : 0;
       -  free (url);
       -  return ret;
       -}
       -
       -
       -int usmb_removexattr (const char *path, const char *name)
       -{
       -  char *url = make_url (path);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "removexattr (%s, %s)\n", url, name));
       -  int ret = smbc_getFunctionRemovexattr (ctx) (ctx, url, name) ? -errno : 0;
       -  free (url);
       -  return ret;
       -}
       -
 (DIR) diff --git a/usmb_dir.h b/usmb_dir.h
       @@ -1,36 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#ifndef USMB_DIR_H
       -  #define USMB_DIR_H
       -
       -  #include <sys/types.h>
       -  #include <fuse.h>
       -
       -  int usmb_mkdir (const char *dirname, mode_t mode);
       -  int usmb_rmdir (const char *dirname);
       -  int usmb_opendir (const char *dirname, struct fuse_file_info *fi);
       -  int usmb_readdir (const char *path, void *h, fuse_fill_dir_t filler,
       -                    off_t offset, struct fuse_file_info *fi);
       -  int usmb_releasedir (const char *path, struct fuse_file_info *fi);
       -  int usmb_setxattr (const char *path, const char *name, const char *value,
       -                     size_t size, int flags);
       -  int usmb_getxattr (const char *path, const char *name, char *value,
       -                     size_t size);
       -  int usmb_listxattr (const char *path, char *list, size_t size);
       -  int usmb_removexattr (const char *path, const char *name);
       -
       -#endif
 (DIR) diff --git a/usmb_file.c b/usmb_file.c
       @@ -1,339 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <sys/time.h>        // struct timeval needed by libsmbclient.h
       -#include <libsmbclient.h>
       -#include "samba3x-compat.h"
       -#include <limits.h>
       -#include <assert.h>
       -#include <fuse.h>
       -#include <errno.h>
       -#include <stdbool.h>
       -#include <stddef.h>
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include <string.h>
       -#include "usmb_file.h"
       -#include "usmb.h"
       -#include "utils.h"
       -
       -
       -// Samba gets st_nlink wrong for directories.
       -static bool fix_nlink (const char *url, struct stat *st)
       -{
       -  assert (NULL != url);
       -  assert (NULL != st);
       -
       -  if (!S_ISDIR (st->st_mode))
       -    return true;
       -
       -  SMBCFILE *file = smbc_getFunctionOpendir (ctx) (ctx, url);
       -  if (NULL == file)
       -    return false;
       -
       -  // st->st_nlink = 2;
       -  st->st_nlink = 0;
       -  errno = ERANGE;
       -
       -  struct smbc_dirent *dirent;
       -
       -  while (NULL != (dirent = smbc_getFunctionReaddir (ctx) (ctx, file)))
       -    if (SMBC_DIR == dirent->smbc_type)
       -      if (INT_MAX == st->st_nlink++)
       -        break;
       -
       -  (void)smbc_getFunctionClosedir (ctx) (ctx, file);
       -  return (NULL == dirent);
       -}
       -
       -
       -int usmb_getattr (const char *filename, struct stat *st)
       -{
       -  char *url = make_url (filename);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "stat (%s)\n", url));
       -
       -  int ret = smbc_getFunctionStat (ctx) (ctx, url, st);
       -
       -  if ((0 > ret) || !fix_nlink (url, st))
       -    ret = -errno;
       -
       -  free (url);
       -  return ret;
       -}
       -
       -
       -int usmb_fgetattr (const char *filename UNUSED, struct stat *st,
       -                   struct fuse_file_info *fi)
       -{
       -  SMBCFILE *file = fd_to_smbcfile (fi->fh);
       -  DEBUG (fprintf (stderr, "fgetattr (%s, %p)\n", filename, (void *)file));
       -
       -  if (0 > smbc_getFunctionFstat (ctx) (ctx, file, st))
       -    return -errno;
       -
       -  if (S_ISDIR (st->st_mode))
       -  {
       -    char *url = make_url (filename);
       -    if (NULL == url)
       -      return -ENOMEM;
       -
       -    bool ok = fix_nlink (url, st);
       -    free_errno (url);
       -
       -    if (!ok)
       -      return -errno;
       -  }
       -
       -  return 0;
       -}
       -
       -
       -int usmb_unlink (const char *filename)
       -{
       -  char *url = make_url (filename);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "unlink (%s)\n", url));
       -  int ret = (0 > smbc_getFunctionUnlink (ctx) (ctx, url)) ? -errno : 0;
       -  free (url);
       -  return ret;
       -}
       -
       -
       -int usmb_open (const char *filename, struct fuse_file_info *fi)
       -{
       -  char *url = make_url (filename);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "open (%s, %d)", url, fi->flags));
       -  SMBCFILE *file = smbc_getFunctionOpen (ctx) (ctx, url, fi->flags, 0);
       -  DEBUG (fprintf (stderr, " = %p\n", (void *)file));
       -
       -  int ret = (NULL == file) ? -errno : 0;
       -  free (url);
       -  fi->fh = smbcfile_to_fd (file);
       -
       -  return ret;
       -}
       -
       -
       -int usmb_release (const char *filename UNUSED, struct fuse_file_info *fi)
       -{
       -  SMBCFILE *file = fd_to_smbcfile (fi->fh);
       -  DEBUG (fprintf (stderr, "release (%s, %p)\n", filename, (void *)file));
       -  return (0 > smbc_getFunctionClose (ctx) (ctx, file)) ? -errno : 0;
       -}
       -
       -
       -int usmb_read (const char *filename UNUSED, char *buff, size_t len, off_t off,
       -               struct fuse_file_info *fi)
       -{
       -  assert (32768 >= len);
       -
       -  SMBCFILE *file = fd_to_smbcfile (fi->fh);
       -  DEBUG (fprintf (stderr, "read (%p, %p, %llu, %lld) ",
       -                  (void *)file, buff, (unsigned long long)len, (long long)off));
       -
       -  if (0 > smbc_getFunctionLseek (ctx) (ctx, file, off, SEEK_SET))
       -  {
       -    fprintf (stderr, "- seek failed: %d\n", -errno);
       -    return -errno;
       -  }
       -
       -  int bytes = smbc_getFunctionRead (ctx) (ctx, file, buff, len);
       -  DEBUG (fprintf (stderr, "= %d\n", bytes));
       -  return (0 > bytes) ? -errno : (int)bytes;
       -}
       -
       -
       -int usmb_write (const char *filename UNUSED, const char *buff, size_t len,
       -                off_t off, struct fuse_file_info *fi)
       -{
       -  SMBCFILE *file = fd_to_smbcfile (fi->fh);
       -  DEBUG (fprintf (stderr, "write (%p, %p, len=%llu, off=%lld) ",
       -                  (void *)file, buff, (unsigned long long)len, (long long)off));
       -
       -  if (0 > smbc_getFunctionLseek (ctx) (ctx, file, off, SEEK_SET))
       -    return -errno;
       -
       -  size_t written = 0;
       -  int bytes = 0;
       -
       -  // No idea whether Windows servers don't like > 32768 byte writes
       -  // (cf. usmb_read), but taking no chances...
       -
       -  const smbc_write_fn write_fn = smbc_getFunctionWrite (ctx);
       -
       -  while (written < len)
       -  {
       -    bytes = write_fn (ctx, file, (char *)buff, (len > 32768) ? 32768 : len);
       -    if (0 > bytes)
       -      break;
       -
       -    written += bytes;
       -    buff += bytes;
       -
       -    // avoids infinite loops
       -    if (0 == bytes)
       -      break;
       -  }
       -
       -  DEBUG (fprintf (stderr, "= %d\n", (0 > bytes) ? -errno : (int)written));
       -  return (0 > bytes) ? -errno : (int)written;
       -}
       -
       -
       -int usmb_create (const char *filename, mode_t mode, struct fuse_file_info *fi)
       -{
       -  char *url = make_url (filename);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "creat (%s)", url));
       -
       -  SMBCFILE *file = smbc_getFunctionCreat (ctx) (ctx, url, mode);
       -  DEBUG (fprintf (stderr, " = %p\n", (void *)file));
       -  int ret = (NULL == file) ? -errno : 0;
       -  fi->fh = smbcfile_to_fd (file);
       -
       -  free (url);
       -  return ret;
       -}
       -
       -
       -int usmb_rename (const char *from, const char *to)
       -{
       -  char *fromurl = make_url (from);
       -  if (NULL == fromurl)
       -    return -ENOMEM;
       -
       -  char *tourl = make_url (to);
       -  if (NULL == tourl)
       -  {
       -    free (fromurl);
       -    return -ENOMEM;
       -  }
       -
       -  DEBUG (fprintf (stderr, "rename (%s, %s)\n", fromurl, tourl));
       -  int ret =
       -    (0 > smbc_getFunctionRename (ctx) (ctx, fromurl, ctx, tourl)) ? -errno : 0;
       -  free (tourl);
       -  free (fromurl);
       -  return ret;
       -}
       -
       -
       -int usmb_utime (const char *filename, struct utimbuf *utb)
       -{
       -  struct utimbuf tmp_utb;
       -
       -  if (NULL == utb)
       -  {
       -    for (;;)
       -    {
       -      time_t now = time (NULL);
       -      if ((time_t)-1 != now)
       -      {
       -        tmp_utb.actime = tmp_utb.modtime = now;
       -        break;
       -      }
       -
       -      if (EINTR != errno)
       -        return -errno;
       -    }
       -
       -    utb = &tmp_utb;
       -  }
       -
       -  char *url = make_url (filename);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  struct timeval tv[2] = {
       -    { .tv_sec = utb->actime,  .tv_usec = 0 },
       -    { .tv_sec = utb->modtime, .tv_usec = 0 },
       -  };
       -
       -  DEBUG (fprintf (stderr, "utime (%s)\n", url));
       -  int ret = (0 > smbc_getFunctionUtimes (ctx) (ctx, url, tv)) ? -errno : 0;
       -  free (url);
       -  return ret;
       -}
       -
       -
       -#if 0
       -Samba defines utimes as taking struct timevals rather than timespecs.
       -int usmb_utimes (const char *filename, const struct timespec ts[2])
       -{
       -  char *url = make_url (filename);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "utimes (%s)\n", url));
       -  int ret = (0 > ctx->utimes (ctx, url, ts)) ? -errno : 0;
       -  free (url);
       -  return ret;
       -}
       -#endif
       -
       -
       -int usmb_chmod (const char *filename, mode_t mode)
       -{
       -  char *url = make_url (filename);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  DEBUG (fprintf (stderr, "chmod (%s, %u)\n", url, mode));
       -  int ret = (0 > smbc_getFunctionChmod (ctx) (ctx, url, mode)) ? -errno : 0;
       -  free (url);
       -  return ret;
       -}
       -
       -
       -int usmb_truncate (const char *filename, off_t offset)
       -{
       -  char *url = make_url (filename);
       -  if (NULL == url)
       -    return -ENOMEM;
       -
       -  SMBCFILE *file = smbc_getFunctionOpen (ctx) (ctx, url, O_WRONLY, 0);
       -  if (NULL == file)
       -  {
       -    int ret = -errno;
       -    free (url);
       -    return ret;
       -  }
       -
       -  int ret = compat_truncate (filename, file, offset);
       -
       -  smbc_getFunctionClose (ctx) (ctx, file);
       -  free (url);
       -  return ret;
       -}
       -
       -
       -int usmb_ftruncate (const char *path, off_t size,
       -                    struct fuse_file_info *fi)
       -{
       -  return compat_truncate (path, fd_to_smbcfile (fi->fh), size);
       -}
       -
 (DIR) diff --git a/usmb_file.h b/usmb_file.h
       @@ -1,43 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#ifndef USMB_FILE_H
       -  #define USMB_FILE_H
       -
       -  #include <fuse.h>
       -  #include <stddef.h>
       -  #include <sys/types.h>
       -
       -  int usmb_getattr (const char *filename, struct stat *st);
       -  int usmb_fgetattr (const char *filename, struct stat *st,
       -                     struct fuse_file_info *fi);
       -  int usmb_unlink (const char *filename);
       -  int usmb_open (const char *filename, struct fuse_file_info *fi);
       -  int usmb_release (const char *filename, struct fuse_file_info *fi);
       -  int usmb_read (const char *filename, char *buff, size_t len, off_t off,
       -                 struct fuse_file_info *fi);
       -  int usmb_write (const char *filename, const char *buff, size_t len, off_t off,
       -                  struct fuse_file_info *fi);
       -  int usmb_create (const char *filename, mode_t mode,
       -                   struct fuse_file_info *fi);
       -  int usmb_rename (const char *from, const char *to);
       -  int usmb_utime (const char *filename, struct utimbuf *utb);
       -  int usmb_truncate (const char *filename, off_t newsize);
       -  int usmb_chmod (const char *filename, mode_t mode);
       -  int usmb_ftruncate (const char *path, off_t size,
       -                      struct fuse_file_info *fi);
       -
       -#endif
 (DIR) diff --git a/utils.c b/utils.c
       @@ -1,216 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2013 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <assert.h>
       -#include <errno.h>
       -#include <limits.h>
       -#include <stdarg.h>
       -#include <stddef.h>
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include <string.h>
       -#include "utils.h"
       -
       -
       -
       -#define INIT_LEN 256
       -char * concat_strings (int num, ...)
       -{
       -  va_list ap;
       -
       -  char *base, *out;
       -
       -  base = out = malloc (INIT_LEN);
       -  if (NULL == base)
       -    return NULL;
       -
       -  size_t buff_size = INIT_LEN;
       -
       -  va_start (ap, num);
       -  for (int i = 0; i < num; ++i)
       -  {
       -    const char *next = va_arg (ap, const char *);
       -    assert (NULL != next);
       -
       -    size_t next_len = strlen (next);
       -    /*LINTED*/
       -    size_t required = (out - base) + next_len + 1;
       -
       -    if (buff_size < required)
       -    {
       -      while (buff_size < required)
       -      {
       -        size_t dbl_len = buff_size * 2;
       -        if (dbl_len < buff_size)
       -        {
       -          free (base);
       -          va_end (ap);
       -          return NULL;
       -        }
       -
       -        buff_size = dbl_len;
       -      }
       -
       -      /*LINTED*/
       -      ptrdiff_t diff = out - base;
       -
       -      char *newbase = realloc (base, buff_size);
       -      if (NULL == newbase)
       -      {
       -        free (base);
       -        va_end (ap);
       -        return NULL;
       -      }
       -
       -      base = newbase;
       -      out = base + diff;
       -    }
       -
       -    memcpy (out, next, next_len);
       -    out += next_len;
       -  }
       -  va_end (ap);
       -
       -  *out = '\0';
       -  return base;
       -}
       -
       -
       -char * xstrdup (const char *in)
       -{
       -  char *out = NULL;
       -
       -  if (NULL != in)
       -  {
       -    size_t len = strlen (in) + 1;
       -
       -    if ((out = malloc (len)))
       -      memcpy (out, in, len);
       -  }
       -
       -  return out;
       -}
       -
       -
       -// the const here lets us pass a pointer to const
       -void xfree (const void *ptr)
       -{
       -  if (NULL != ptr)
       -    free ((void *)ptr);
       -}
       -
       -
       -void clear_and_free (char *ptr)
       -{
       -  if (NULL != ptr)
       -  {
       -    for (char *pch = ptr; '\0' != *pch; ++pch)
       -      *pch = '\0';
       -
       -    free (ptr);
       -  }
       -}
       -
       -
       -void free_errno (const void *ptr)
       -{
       -  int err = errno;
       -  free ((void *)ptr);
       -  errno = err;
       -}
       -
       -
       -void xfree_errno (const void *ptr)
       -{
       -  int err = errno;
       -  xfree (ptr);
       -  errno = err;
       -}
       -
       -
       -bool bsnprintf (char *str, size_t size, const char *format, ...)
       -{
       -  va_list ap;
       -  bool ret;
       -
       -  va_start (ap, format);
       -  ret = bvsnprintf (str, size, format, ap);
       -  va_end (ap);
       -
       -  return ret;
       -}
       -
       -
       -bool bvsnprintf (char *str, size_t size, const char *format, va_list ap)
       -{
       -  int ret;
       -
       -  assert (NULL != str);
       -  assert (NULL != format);
       -
       -  ret = vsnprintf (str, size, format, ap);
       -
       -  return ((ret >= 0) && ((size_t)ret < size));
       -}
       -
       -
       -bool baprintf (char **out, const char *format, ...)
       -{
       -  va_list ap;
       -  bool ret;
       -
       -  va_start (ap, format);
       -  ret = bvaprintf (out, format, ap);
       -  va_end (ap);
       -
       -  return ret;
       -}
       -
       -
       -bool bvaprintf (char **out, const char *format, va_list ap)
       -{
       -  assert (NULL != out);
       -  assert (NULL != format);
       -  *out = NULL;
       -
       -  va_list ap2;
       -  va_copy (ap2, ap);
       -  int bytes = vsnprintf (NULL, 0, format, ap2);
       -  va_end (ap2);
       -
       -  if ((1 > bytes) || (INT_MAX == bytes))
       -    return false;
       -
       -  ++bytes;  // '\0'.
       -
       -  if (bytes != (int)(size_t)bytes)
       -    return false;
       -
       -  *out = malloc ((size_t)bytes);
       -  if (NULL == *out)
       -    return false;
       -
       -  if (!bvsnprintf (*out, bytes, format, ap))
       -  {
       -    free (*out);
       -    *out = NULL;
       -    return false;
       -  }
       -
       -  return true;
       -}
       -
 (DIR) diff --git a/utils.h b/utils.h
       @@ -1,47 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#ifndef UTILS_H
       -  #define UTILS_H
       -
       -  #include <stdarg.h>
       -  #include <stdbool.h>
       -  #include <stddef.h>
       -
       -  #ifdef DEBUG
       -    #undef DEBUG
       -    #define DEBUG(x) (x)
       -    #define DEBUGON
       -  #else
       -    #define DEBUG(x) ((void)0)
       -  #endif
       -
       -  char * concat_strings (int num, ...) MUSTCHECK;
       -  char * xstrdup (const char *in) MUSTCHECK;
       -  void xfree (const void *ptr);
       -  void clear_and_free (char *ptr);
       -  void free_errno (const void *ptr);
       -  void xfree_errno (const void *ptr);
       -  bool bsnprintf (char *str, size_t size, const char *format, ...)
       -    __attribute__ ((format (printf, 3, 4))) MUSTCHECK;
       -  bool bvsnprintf (char *str, size_t size,
       -                   const char *format,
       -                   va_list ap) MUSTCHECK;
       -  bool baprintf (char **out, const char *format, ...)
       -    __attribute__ ((format (printf, 2, 3))) MUSTCHECK;
       -  bool bvaprintf (char **out, const char *format, va_list ap) MUSTCHECK;
       -
       -#endif
 (DIR) diff --git a/version.c b/version.c
       @@ -1,72 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <stdio.h>
       -#include <sys/time.h>
       -#include <libsmbclient.h>
       -#include <fuse.h>
       -#include "version.h"
       -
       -
       -#if ((USMB_VERSION_STATUS != 'a') && \
       -     (USMB_VERSION_STATUS != 'b') && \
       -     (USMB_VERSION_STATUS != 'p') && \
       -     (USMB_VERSION_STATUS != 's'))
       -  #error Unsupported USMB_VERSION_STATUS
       -#endif
       -
       -
       -void show_about (FILE *fp)
       -{
       -  fprintf (fp, "usmb - mount SMB shares via FUSE and Samba\n"
       -               "\n"
       -               "Copyright (C) 2006-2013 Geoff Johnstone.\n"
       -               "Licensed under the GNU General Public License.\n"
       -               "usmb comes with ABSOLUTELY NO WARRANTY; "
       -                 "for details please see\n"
       -               "http://www.gnu.org/licenses/gpl.txt\n"
       -               "\n"
       -               "Please send bug reports, patches etc. to %s@%s.org\n",
       -               "geoffjohnstone", "acm");   // anti-spam.
       -}
       -
       -
       -static inline const char * get_status (char ch)
       -{
       -  switch (ch)
       -  {
       -    case 'a': return "alpha";
       -    case 'b': return "beta";
       -    case 'p': return "pre-release";
       -    case 's': return "stable";
       -    default:  return "unofficial";
       -  }
       -}
       -
       -
       -void show_version (FILE *fp)
       -{
       -  show_about (fp);
       -  fputc ('\n', fp);
       -  fprintf (fp, "usmb version: %08x (%s)\n"
       -               "FUSE version: %d.%d\n"
       -               "Samba version: %s\n",
       -           USMB_VERSION, get_status (USMB_VERSION_STATUS),
       -           FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION,
       -           smbc_version());
       -}
       -
 (DIR) diff --git a/version.h b/version.h
       @@ -1,25 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#ifndef VERSION_H
       -  #define VERSION_H
       -
       -  #include <stdio.h>
       -
       -  void show_about (FILE *fp);
       -  void show_version (FILE *fp);
       -
       -#endif
 (DIR) diff --git a/version.m4 b/version.m4
       @@ -1,5 +0,0 @@
       -m4_define([VERSION_],[20130204])
       -
       -# a - alpha, b - beta, p - pre-release, s - stable
       -m4_define([VERSION_STATUS_],[s])
       -
 (DIR) diff --git a/xml.c b/xml.c
       @@ -1,187 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2013 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#include "config.h"
       -#include <libxml/xmlreader.h>
       -#include <libxml/xpath.h>
       -#include <libxml/xpathInternals.h>
       -#include <assert.h>
       -#include <stdbool.h>
       -#include <string.h>
       -#include "xml.h"
       -#include "utils.h"
       -
       -
       -bool xml_validate_relaxng (xmlDocPtr doc, const char *schema)
       -{
       -  xmlRelaxNGParserCtxtPtr rngpcptr = NULL;
       -  xmlRelaxNGPtr rngptr = NULL;
       -  xmlRelaxNGValidCtxtPtr rngvptr = NULL;
       -  bool ret = false;
       -
       -  assert (NULL != doc);
       -
       -  do
       -  {
       -    rngpcptr = xmlRelaxNGNewMemParserCtxt (schema, strlen (schema));
       -    if (NULL == rngpcptr)
       -      break;
       -
       -    rngptr = xmlRelaxNGParse (rngpcptr);
       -    if (NULL == rngptr)
       -      break;
       -
       -    rngvptr = xmlRelaxNGNewValidCtxt (rngptr);
       -    if (NULL == rngvptr)
       -      break;
       -
       -    ret = (0 == xmlRelaxNGValidateDoc (rngvptr, doc));
       -  } while (false /*CONSTCOND*/);
       -
       -  if (NULL != rngvptr)
       -    xmlRelaxNGFreeValidCtxt (rngvptr);
       -
       -  if (NULL != rngptr)
       -    xmlRelaxNGFree (rngptr);
       -
       -  if (NULL != rngpcptr)
       -    xmlRelaxNGFreeParserCtxt (rngpcptr);
       -
       -  return ret;
       -}
       -
       -
       -bool xml_xpath_attr_value (xmlXPathContextPtr ctx,
       -                           char *xpath,
       -                           const char *attr,
       -                           char **out)
       -{
       -  xmlXPathObjectPtr obj;
       -  xmlChar *tmp;
       -
       -  assert (NULL != ctx);
       -  assert (NULL != xpath);
       -  assert (NULL != out);
       -
       -  *out = NULL;
       -
       -  obj = xmlXPathEval (BAD_CAST xpath, ctx);
       -  if (NULL == obj)
       -  {
       -    DEBUG (fputs ("XPath evaluation error\n", stderr));
       -    return false;
       -  }
       -
       -  do
       -  {
       -    if (XPATH_NODESET != obj->type)
       -    {
       -      DEBUG (fputs ("XPath evaluation didn't return a nodeset\n", stderr));
       -      break;
       -    }
       -
       -    if (NULL == obj->nodesetval)
       -    {
       -      DEBUG (fputs ("nodesetval is NULL\n", stderr));
       -      break;
       -    }
       -
       -    if (1 != obj->nodesetval->nodeNr)
       -    {
       -      DEBUG (fprintf (stderr, "Nodeset has %d elements\n",
       -                          obj->nodesetval->nodeNr));
       -      break;
       -    }
       -
       -    tmp = xmlGetProp (obj->nodesetval->nodeTab[0], BAD_CAST attr);
       -    if (NULL == tmp)
       -      break;
       -
       -    *out = xstrdup ((char *)tmp);
       -    if (NULL == *out)
       -      break;
       -
       -    xmlXPathFreeObject (obj);
       -    return true;
       -    /*NOTREACHED*/
       -  } while (false /*CONSTCOND*/);
       -
       -  *out = NULL;
       -  xmlXPathFreeObject (obj);
       -  return false;
       -}
       -
       -
       -bool xml_xpath_text (xmlXPathContextPtr ctx, char *xpath, char **out)
       -{
       -  xmlXPathObjectPtr obj;
       -
       -  assert (NULL != ctx);
       -  assert (NULL != xpath);
       -  assert (NULL != out);
       -
       -  *out = NULL;
       -
       -  DEBUG (fprintf (stderr, "xml_xpath_text (%s)\n", xpath));
       -
       -  obj = xmlXPathEval (BAD_CAST xpath, ctx);
       -  if (NULL == obj)
       -  {
       -    DEBUG (fputs ("XPath evaluation error\n", stderr));
       -    return false;
       -  }
       -
       -  do
       -  {
       -    if (XPATH_NODESET != obj->type)
       -    {
       -      DEBUG (fputs ("XPath evaluation didn't return a nodeset\n", stderr));
       -      break;
       -    }
       -
       -    if (NULL == obj->nodesetval)
       -    {
       -      DEBUG (fputs ("nodesetval is NULL\n", stderr));
       -      break;
       -    }
       -
       -    if (1 != obj->nodesetval->nodeNr)
       -    {
       -      DEBUG (fprintf (stderr, "Nodeset has %d elements\n",
       -                          obj->nodesetval->nodeNr));
       -      break;
       -    }
       -
       -    if (NULL == obj->nodesetval->nodeTab[0]->content)
       -    {
       -      DEBUG (fputs ("Node has no text\n", stderr));
       -      break;
       -    }
       -
       -    *out = xstrdup ((char *)obj->nodesetval->nodeTab[0]->content);
       -    if (NULL == *out)
       -      break;
       -
       -    xmlXPathFreeObject (obj);
       -    return true;
       -    /*NOTREACHED*/
       -  } while (false /*CONSTCOND*/);
       -
       -  *out = NULL;
       -  xmlXPathFreeObject (obj);
       -  return false;
       -}
       -
 (DIR) diff --git a/xml.h b/xml.h
       @@ -1,34 +0,0 @@
       -/* usmb - mount SMB shares via FUSE and Samba
       - * Copyright (C) 2006-2009 Geoff Johnstone
       - *
       - * This program is free software; you can redistribute it and/or modify
       - * it under the terms of the GNU General Public License version 3 as
       - * published by the Free Software Foundation.
       - *
       - * This program is distributed in the hope that it will be useful,
       - * but WITHOUT ANY WARRANTY; without even the implied warranty of
       - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       - * GNU General Public License for more details.
       - *
       - * You should have received a copy of the GNU General Public License
       - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
       - */
       -
       -#ifndef XML_H
       -  #define XML_H
       -
       -  #include <libxml/xmlreader.h>
       -  #include <libxml/xpath.h>
       -  #include <libxml/xpathInternals.h>
       -  #include <stdbool.h>
       -
       -
       -  bool xml_validate_relaxng (xmlDocPtr doc, const char *schema) MUSTCHECK;
       -  bool xml_xpath_attr_value (xmlXPathContextPtr ctx,
       -                             char *xpath,
       -                             const char *attribute,
       -                             char **out) MUSTCHECK;
       -  bool xml_xpath_text (xmlXPathContextPtr ctx,
       -                       char *xpath, char **out) MUSTCHECK;
       -
       -#endif