fsarchiver-0.8.5/0000755000176100017610000000000013321213314010656 500000000000000fsarchiver-0.8.5/aclocal.m40000644000176100017610000015502313321212501012441 00000000000000# generated automatically by aclocal 1.15.1 -*- Autoconf -*- # Copyright (C) 1996-2017 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 11 (pkg-config-0.29.1) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.1]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) 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 ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have 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_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. 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` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. 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 ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl 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 AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [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])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [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 .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------ dnl dnl Prepare a "--with-" configure option using the lowercase dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and dnl PKG_CHECK_MODULES in a single macro. AC_DEFUN([PKG_WITH_MODULES], [ m4_pushdef([with_arg], m4_tolower([$1])) m4_pushdef([description], [m4_default([$5], [build with ]with_arg[ support])]) m4_pushdef([def_arg], [m4_default([$6], [auto])]) m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) m4_case(def_arg, [yes],[m4_pushdef([with_without], [--without-]with_arg)], [m4_pushdef([with_without],[--with-]with_arg)]) AC_ARG_WITH(with_arg, AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, [AS_TR_SH([with_]with_arg)=def_arg]) AS_CASE([$AS_TR_SH([with_]with_arg)], [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], [auto],[PKG_CHECK_MODULES([$1],[$2], [m4_n([def_action_if_found]) $3], [m4_n([def_action_if_not_found]) $4])]) m4_popdef([with_arg]) m4_popdef([description]) m4_popdef([def_arg]) ])dnl PKG_WITH_MODULES dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ----------------------------------------------- dnl dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES dnl check._[VARIABLE-PREFIX] is exported as make variable. AC_DEFUN([PKG_HAVE_WITH_MODULES], [ PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) AM_CONDITIONAL([HAVE_][$1], [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) ])dnl PKG_HAVE_WITH_MODULES dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------------------ dnl dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make dnl and preprocessor variable. AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) ])dnl PKG_HAVE_DEFINE_WITH_MODULES # Copyright (C) 2002-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.15' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.15.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.15.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # -*- Autoconf -*- # Obsolete and "removed" macros, that must however still report explicit # error messages when used, to smooth transition. # # Copyright (C) 1996-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. AC_DEFUN([AM_CONFIG_HEADER], [AC_DIAGNOSE([obsolete], ['$0': this macro is obsolete. You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl AC_CONFIG_HEADERS($@)]) AC_DEFUN([AM_PROG_CC_STDC], [AC_PROG_CC am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc AC_DIAGNOSE([obsolete], ['$0': this macro is obsolete. You should simply use the 'AC][_PROG_CC' macro instead. Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', but upon 'ac_cv_prog_cc_stdc'.])]) AC_DEFUN([AM_C_PROTOTYPES], [AC_FATAL([automatic de-ANSI-fication support has been removed])]) AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR fsarchiver-0.8.5/README0000644000176100017610000000744413233300034011465 00000000000000===================================================================== fsarchiver: Filesystem Archiver for Linux [http://www.fsarchiver.org] ===================================================================== About FSArchiver ---------------- FSArchiver is a system tool that allows you to save the contents of a filesystem to a compressed archive file. The filesystem contents can be restored on a device which has a different size and it can be restored on a different filesystem. Unlike tar/dar, FSArchiver also creates the filesystem when it extracts the data to devices. Everything is checksummed in the archive in order to protect the data. If the archive is corrupt, you just lose the current file, not the whole archive. FSArchiver is released under the GPLv2 license. You should read the Quick Start guide [http://www.fsarchiver.org/quickstart/] if you are using FSArchiver for the first time. Detailed description -------------------- The purpose of this project is to provide a safe and flexible filesystem backup/deployment tool. Other open-source filesystems tools such as Partimage already exist. These tools are working at the filesystem block level, so it's not possible to restore the backup to a smaller device, and restoring to a bigger one forces you to resize the filesystem by hand. The purpose is to have a very flexible program. FSArchiver can extract an archive to a device which is smaller that the original one as long as there is enough space to store the data. It can also restore the data on a different filesystem, so you can use it when you want to convert your filesystem: you can backup an EXT3 filesystem, and restore it as ReiserFS. FSArchiver works at the file level. It can make an archive of most Linux filesystems (EXT3, ReiserFS, XFS, ...) that the running kernel can mount with read-write support. It will preserve all the standard Unix file attributes (permissions, timestamps, symbolic-links, hard-links, extended-attributes, ...), as long as the kernel has support for them enabled. Limitations ----------- There are limitations anyway: FAT filesystem is supported basically for EFI System Partition volumes (UEFI systems) and won't work for bootable Windows volumes. Also, NTFS support is experimental and shouldn't be used in production. FSArchiver won't preserve features which are very specific to a filesystem. For instance, if you create a snapshot in a Btrfs volume, FSArchiver won't know anything about that, and it will just backup the contents seen when you mount the device. FSArchiver is safe when it makes backups of devices which are not mounted or are mounted read-only. There is an option to force the backup of a read-write mounted volume, but there may be problems with the files that changed during the backup. If you want to backup a device which are in use, the best thing to do is to make an LVM snapshot of it using lvcreate -s, which is part of the LVM userland tools. Unfortunately you can only make snapshots of devices which are LVM Logical Volumes. Protection against data loss ---------------------------- FSArchiver is using two levels of checksums to protect your data against corruption. Each block of each file has a 32-bit checksum written in the archive. That way we can identify which block of your file is damaged. Once a file has been restored, the MD5 checksum of the whole file is compared to the original MD5. It's a 128-bit checksum, so it will detect all file corruptions. In case one file is damaged, FSArchiver will restore all the other files from your archive, so you won't lose all your data. It's very different from tar.gz where the whole tar is compressed with gzip. In that case, the data which are written after the corruption are lost. FSArchiver-0.2.3 and newer versions are able to ignore corrupt contents in an archive file, so all the other files will be restored. fsarchiver-0.8.5/AUTHORS0000644000176100017610000000000012461437135011651 00000000000000fsarchiver-0.8.5/THANKS0000644000176100017610000000221113147064563011525 00000000000000===================================================================== fsarchiver: Filesystem Archiver for Linux [http://www.fsarchiver.org] ===================================================================== Special thanks to Clive Wagenaar who helped a lot by testing fsarchiver-0.3.x and found several important bugs and help in their resolutions. Special thanks to Leon Bene who reported a crash and who executed many tests using debugging version to identify the cause of the crash. It permitted to fix a critical integer overflow bug with the "u64 headerlen" when the total size of the attributes is more than 65535 bytes in the header. It has been fixed in fsarchiver-0.6.4. Many thanks to Marcos Mello who helped a lot improve the XFS support in fsarchiver-0.6.20. He found unexpected fsarchiver behaviors with new versions of the kernel and xfsprogs, did a lot of research regarding these components, and tested the XFS fixes in fsarchiver. He also provided fixes and documentation updates in fsarchiver-0.6.24. He also did a lot of research regarding EXT4 and helped improve the handling of extfs on very large block devices in fsarchiver-0.8.2. fsarchiver-0.8.5/compile0000755000176100017610000001632613321212503012163 00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2016-01-11.22; # UTC # Copyright (C) 1999-2017 Free Software Foundation, Inc. # Written by Tom Tromey . # # 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, 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 . # 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. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: fsarchiver-0.8.5/internals/0000755000176100017610000000000012461437135012672 500000000000000fsarchiver-0.8.5/internals/MULTITHREADING0000644000176100017610000001441212461437135014657 00000000000000===================================================================== fsarchiver: Filesystem Archiver for Linux [http://www.fsarchiver.org] ===================================================================== About multi-threading --------------------- Today all the new processors are dual-core or quad-core. But all the standard compression tools are single threaded. It means that when you use "tar cfz" for "tar cfj", to compress a tarball using gzip or bzip2, you just use one cpu, so just 50% of 25% of the power you have. FSArchiver is multi-threaded if you use option "-j" to create several compression jobs, so that it can use all the power of your processors to compress faster. For instnace, compressing on an intel Q6600 quad-core with bzip2 is really fast, and with lzma it's not too slow. Implementation of the multi-threading ------------------------------------- FSArchiver is using three kinds of threads even if you don't use the option "-j". There is a main thread, a archive-io thread, and one or more compression/decompression threads. When you use option "-j" you just create more than one compression/decompression threads. To implement multi-threading, fsarchiver is using the pthread library (POSIX Pthread libraries). This is a standard threads implementation available on many operating systems. The most important thing in the multi-threading implementation is the queue which is implemented in queue.c. All the data that are read of written in a file first go in the queue. The queue is a list of items that have to be written: it can be either an header or a data block. The contents are split into blocks of few hundreds kilo-bytes. For instance, if you want to archive a 10MB file, it can be spitted into 50 datablocks. The queue must be big enough to contain multiple data blocks at a time. The compression/decompression threads are always searching for the first block to be processed in the queue, they process it, and update the block in the queue. For instance if the queue is able to store 10 data blocks at a given time, it means that a quad-core processor will have enough blocks to feed each of its cores, and then to use all the power of this processor. The size of the queue is defined by FSA_MAX_QUEUESIZE. It says how many data blocks can be stored in the queue at a given time. When this limit is reached, the thread which fills the queue will have to wait. Overview of the threads ----------------------- Here are how the threads work: a) when we write an archive (savefs / savedir): - the mainthread (create.c) is writing items to the queue - the compression thread is reading and writing in the queue - the archio thread is reading items to the disk (queue writer) b) when we read an archive (restfs / restrdir / archinfo): - the mainthread (extract.c) is reading items from the queue - the decompression thread is reading and writing in the queue - the archio thread is writing items to the disk (queue reader) Queue and synchronization ------------------------- The queue is what links all the threads together. It's a critical section of the code so it's very important that it contains no bug. The consistency of this queue is guaranteed with a mutex (to make sure that two threads can't change the same thing at the same time). It's very important that each function that locks this mutex unlocks it before it exits, else there will be a dead-lock. It's also useful to keep the queue management quite simple in order to avoid bugs. To synchronize threads, there are two attributes: a) end_of_archive: which is an attribute of the queue b) g_stopfillqueue which is a global variable outside of the queue c) g_abort is set when the user wants to stop. It's outside of the queue The threads have to play with these two attributes to manage events such as errors of the end of data. In a normal situation: 1. the queue writer puts data in the queue and sets end_of_archive to true when there are no more data to be written to the queue 2. the queue reader has to read data from the queue until end_of_archive is set to true and the queue is empty. In case of errors: a) when the user press Ctrl+C, the signal handler will set g_abort to true and the main thread has to manage that case. b) if the queue writer has a problem and wants to stop, it just has to set end_of_archive to true and the queue reader will stop reading it queue_set_end_of_queue(&g_queue, true); c) if the queue reader has a problem and wants to stop, it has to set g_stopfillqueue to true, to say to the queue writer that it has to stop. Then the queue writer checks g_stopfillqueue and stop filling the queue. Then the queue reader has to remove the remaining items from the queue, using queue_destroy_first_item() set_stopfillqueue(); // don't need any more data while (queue_get_end_of_queue(&g_queue)==false) queue_destroy_first_item(&g_queue); General rules for multi-threading: ---------------------------------- - all the important decisions (aborting, creating/destroying threads, ...) are taken in the main thread (implemented in either create.c or extract.c) - when there is an error, the first thing to do is to stop the source that fills the queue. If you are in the thread that reads the queue, you set g_stopfillqueue to true to stop the source of data and then process the remaining items which are still in the queue - in case of an error, a secondary thread has to make sure that the main thread is aware of that error (through a global variable or through the set_end_of_queue attribute if it's the queue writer) - in case of an error, always make sure the queue is empty before the current thread exits, so that the threads that are involved in the queue don't continue to wait for data. - the compression/decompression thread is in the middle of the chain. It exits when queue_get_end_of_queue(&g_queue)==false, so we must be sure that the queue is empty when we terminate with an error, else the compression thread will never exit and the program will hang. - only the main thread is involved in the management of the signals (when the users does Ctrl+C), the main threads must often checks that g_abort is set to false, and in case it's set to true, it must stops its own processing, and warn the secondary threads that they have to terminate. fsarchiver-0.8.5/internals/FILEFORMAT0000644000176100017610000002402712461437135014172 00000000000000===================================================================== fsarchiver: Filesystem Archiver for Linux [http://www.fsarchiver.org] ===================================================================== About the file format --------------------- The file format is made of two sort of structures: headers and data-blocks. The headers are all a dictionnary where the key is an integer. That way we can add new things in headers in next versions without having to break the file format. Global archive layout --------------------- 1) All fsarchiver archives are made of one or multiple volumes. Each volume starts with an FSA_MAGIC_VOLH header and terminates with a FSA_MAGIC_VOLF header. These headers are used to determine that the archive is the fsarchiver format, and which volume it is. 2) The beginning of the archive (which is always at the beginning of the first volume) contains an archive header (FSA_MAGIC_MAIN) where se store information such as the archive creation date. Then we write all the filesystem information header (FSA_MAGIC_FSIN). It stores things such as the filesystem type (ext3, reiserfs, ...), and all its attributes (label, uuid, space used, ...). Some of these attributes are specific to a particular filesystem. For instance, it saves the compatibility flags of ext2/ext3/ext4 filesystem so that fsarchiver can recreates a filesystem with the same properties. 3) Then the archive contains all the filesystems contents: there is an header that marks the beginning of a filesystem data (FSA_MAGIC_FSYB) and another header is used to mark its end (FSA_MAGIC_DATF). The filesystem contents is a list of object headers (FSA_MAGIC_OBJT) and data-blocks. 4) The archive splitting mechanism will never split the archive in the middle of an archive or datablock. An in-memory structure called s_writebuf has been created to store all the data which are written to the archive. All the bytes that are part of an header / block are first accumulated in a s_writebuf. When it's ready, it's passed to the write-to-archive function in charge of the file splitting. That way an s_writebuf is like an atomic item that cannot be splitted. The consequence it that it's not possible to respect exactly the volume size specified by the user, it will always be a bit smaller. About regular files management ------------------------------ Creating a normal tar.gz file is like compressing a tar file. It means if there is a corruption in the tar.gz file, we can't ungzip it and then we can untar it. Just a single corruption in one byte at the beginning of the file make it unreadable. For this reason fsarchiver is working the other way. It's like a gz.tar: we archive files that have already been compressed before. It provides a better safety for your data: if one byte if corrupt, we just ignore the current file and we can extract the next one. There is a problem with that: in case there are a lot of small files, like in the linux-sources-2.6, we compress each small files in a single data block of only few KB, which produces a bad compression ratio compared to compression of a big tar archive of all the small files. For that reason, all the small files are processed in a different way in fsarchiver-0.4.4 and later: it creates a set of small files that can fit in a single data block (256KB by default) and then it compresses a block which is quite big compared to the size of a single file. There is a threshold which is used to know whether a regular file will be considered as a small file (sharing a data block with other small files) or if it will be considered as a normal/big one having its own data blocks. This threshold depends of the size of a data block, which depends itself on the algirithm choosen to compress the data. In general, a data block is 256KB (it can be bigger) and the threshold will be 256KB/4 = 64KB. Empty files (size=0) are saved in a single regular file (as large files) and they have no footer (there is no need to have an md5 checksum for empty files) How files are stored in the archive ----------------------------------- There are many sort of objects in a filesystem: 1) special files (symbolic links, hard links, directories, ...) all these files just have one header in the archive. It contains all their attributes (name, permissions, xattr, time stats, ...) 2) normal/big regular files (bigger than the threshold) [REGFILE ] these files have their header first (FSA_MAGIC_OBJT) with the file attributes, and then one or several data blocks (depending on how big the file is), and then a file footer (FSA_MAGIC_FILF) with the md5sum of the contents for files which are not empty. The md5sum can't be written in the object header (before the data blocks) because it would require to read the file twice: first pass to compute the checksum, and a second pass to copy the contents the data blocks. (think about a very large file, say 5GB, which is written to an fsa archive which is split into small volumes, say 100MB) 3) small regular files (smaller than the threshold) [REGFILEM] small files are written to the archive when we have a full set of small files, or at the end of the savefs/savedir operation. during the savefs, all the small files are stored in a structure called s_regmulti. When this structure is full, it's copied to the archive and a new one is created. So we end up with the following data in the archive: we first write one object header (FSA_MAGIC_OBJT) for each small file in the s_regmulti. This headers contains extra keys (not found in object-header for normal files): DISKITEMKEY_MD5SUM, DISKITEMKEY_MULTIFILESCOUNT, DISKITEMKEY_MULTIFILESOFFSET. It's the md5sum for the file (we can compute it before it's written to disk because the files are quite small, and it saves an extra FSA_MAGIC_FILF footer), the number of small-files to expect in the current set (used at the extraction to know what read), and the offset of the data for the current file in the shrared data block. After the individual small-files headers, we write a single shared data-block (which is compressed and may be encrypted as any other data block). There is no header/footer after the shared data lock in the archive. About datablocks ---------------- Each data block which is written to the archive has its own header (FSA_MAGIC_BLKH). This header stores block attributes: original block size, compressed size, compression algorithm used, encryption algorithm used, offset of the first byte in the file, ... When both compression and encryption are used, the compression is done first. It's more efficient to process that way because the encryption algorithm will have less things to do because the compressed block is smaller. When the compression makes a block bigger than the original one, fsarchiver automatically ignores the compressed version and keeps the uncompressed block. About endianess --------------- fsarchiver should be endianess safe. All the integers are converted to little-endian before they are written to the disk. So it's neutral on intel platforms, and it requires a conversion on all the big-endian platforms. The only things that have to be converted are the integers which are part of the headers. These conversions don't pollute the source code since they are all converted in the functions that manage the headers: write-header-to-disk and read-header-from-disk functions. All the higer level functions in the code just have to add a number to the header, they don't have to worry about endianess. About headers ------------- All the information which is not the files contents itself (meta-data) are stored in a generic management system called headers. It's not just a normal C structure which is written to disk. A specific object oriented mechanism has been written for that. The headers are quite high-level data structures that are reused a lot in the sources. They provide endianess management, checksumming, and extensibility. Since the data are stored as a dictinnary, where the keys are 16bit integers, it will be possible to extend the headers in the future by adding new keys to add new information in the next versions. These headers are just implemented as s_dico in the program, and the magic and checksum are added when we write it to the archive file. Here is how an header is stored in an archive: - 32bit magic string used to identify the type of header it is - 32bit archive id (random number generated suring the savefs / savedir) - 16bit filesystem id (which filesystem of the archive it belongs to) - dictionary with its own internal data (length, 32bit checksum, ...) The random 32bit archive id is used to make sure the program won't be disturbed by nested archive in case the archive is corrupt. When an archive is corrupt, we can skip data and search for the next header using the known magic strings. In case we have nested archives, we could find the magic string that belongs to a nested archive. It won't be used since we also compare the random 32bit archive id, and the id of the nested archive header will be different so the program will know that it has to ignore that header and continue to search. About checksumming ------------------ Almost everything in the archive is checksummed to make sure the program will never silently restore corrupt data. The headers that contains all the meta-data (file names, permissions, attributes, ...) are checksummed using a 32bit fletcher32 checksum. The files contents are written in the archive as blocks of few hundreds kilo-bytes. Each block is compressed (except if the compression makes the block bigger) and it may also be encrypted (if the user provided a password). Each block also has its own 32bit fletcher32 checksum. All the files where size>0 also have an individual md5 checksum that makes sure the whole file is exactly the same as the original one (the blocks are checksummed but it allows to make sure we did not drop one of the block of a file for instance). Because of the md5 checksum, we can be sure that the program is aware of the corruption if it happens. fsarchiver-0.8.5/src/0000755000176100017610000000000013321213314011445 500000000000000fsarchiver-0.8.5/src/archreader.c0000644000176100017610000004021213242523705013642 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include "fsarchiver.h" #include "dico.h" #include "common.h" #include "options.h" #include "archreader.h" #include "queue.h" #include "comp_gzip.h" #include "comp_bzip2.h" #include "error.h" int archreader_init(carchreader *ai) { assert(ai); memset(ai, 0, sizeof(struct s_archreader)); ai->cryptalgo=ENCRYPT_NULL; ai->compalgo=COMPRESS_NULL; ai->fsacomp=-1; ai->complevel=-1; ai->archfd=-1; ai->archid=0; ai->curvol=0; ai->filefmtver=0; ai->hasdirsinfohead=false; return 0; } int archreader_destroy(carchreader *ai) { assert(ai); return 0; } int archreader_open(carchreader *ai) { struct stat64 st; char volhead[64]; int magiclen; assert(ai); // on the archive volume ai->archfd=open64(ai->volpath, O_RDONLY|O_LARGEFILE); if (ai->archfd<0) { sysprintf ("cannot open archive %s\n", ai->volpath); return -1; } // check the archive volume is a regular file if (fstat64(ai->archfd, &st)!=0) { sysprintf("fstat64(%s) failed\n", ai->volpath); return -1; } if (!S_ISREG(st.st_mode)) { errprintf("%s is not a regular file, cannot continue\n", ai->volpath); close(ai->archfd); return -1; } // read file format version and rewind to beginning of the volume if (read(ai->archfd, volhead, sizeof(volhead))!=sizeof(volhead)) { sysprintf("cannot read magic from %s\n", ai->volpath); close(ai->archfd); return -1; } if (lseek64(ai->archfd, 0, SEEK_SET)!=0) { sysprintf("cannot rewind volume %s\n", ai->volpath); close(ai->archfd); return -1; } // interpret magic an get file format version magiclen=strlen(FSA_FILEFORMAT); if ((memcmp(volhead+40, "FsArCh_001", magiclen)==0) || (memcmp(volhead+40, "FsArCh_00Y", magiclen)==0)) { ai->filefmtver=1; } else if (memcmp(volhead+42, "FsArCh_002", magiclen)==0) { ai->filefmtver=2; } else { errprintf("%s is not a supported fsarchiver file format\n", ai->volpath); close(ai->archfd); return -1; } msgprintf(MSG_VERB2, "Detected fileformat=%d in archive %s\n", (int)ai->filefmtver, ai->volpath); return 0; } int archreader_close(carchreader *ai) { assert(ai); if (ai->archfd<0) return -1; lockf(ai->archfd, F_ULOCK, 0); close(ai->archfd); ai->archfd=-1; return 0; } int archreader_volpath(carchreader *ai) { int res; res=get_path_to_volume(ai->volpath, PATH_MAX, ai->basepath, ai->curvol); return res; } int archreader_incvolume(carchreader *ai, bool waitkeypress) { assert(ai); ai->curvol++; return archreader_volpath(ai); } int archreader_read_data(carchreader *ai, void *data, u64 size) { long lres; assert(ai); if ((lres=read(ai->archfd, (char*)data, (long)size))!=(long)size) { sysprintf("read failed: read(size=%ld)=%ld\n", (long)size, lres); return -1; } return 0; } int archreader_read_dico(carchreader *ai, cdico *d) { u16 size; u32 headerlen; u32 origsum; u32 newsum; u8 *buffer; u8 *bufpos; u16 temp16; u32 temp32; u8 section; u16 count; u8 type; u16 key; int i; assert(ai); assert(d); // header-len, header-data, header-checksum switch (ai->filefmtver) { case 1: if (archreader_read_data(ai, &temp16, sizeof(temp16))!=0) { errprintf("imgdisk_read_data() failed\n"); return OLDERR_FATAL; } headerlen=le16_to_cpu(temp16); break; case 2: if (archreader_read_data(ai, &temp32, sizeof(temp32))!=0) { errprintf("imgdisk_read_data() failed\n"); return OLDERR_FATAL; } headerlen=le32_to_cpu(temp32); break; default: errprintf("Fatal error: invalid file format version: ai->filefmtver=%d\n", ai->filefmtver); return OLDERR_FATAL; } bufpos=buffer=malloc(headerlen); if (!buffer) { errprintf("cannot allocate memory for header\n"); return FSAERR_ENOMEM; } if (archreader_read_data(ai, buffer, headerlen)!=0) { errprintf("cannot read header data\n"); free(buffer); return OLDERR_FATAL; } if (archreader_read_data(ai, &temp32, sizeof(temp32))!=0) { errprintf("cannot read header checksum\n"); free(buffer); return OLDERR_FATAL; } origsum=le32_to_cpu(temp32); // check header-data integrity using checksum newsum=fletcher32(buffer, headerlen); if (newsum!=origsum) { errprintf("bad checksum for header\n"); free(buffer); return OLDERR_MINOR; // header corrupt --> skip file } // read count from buffer memcpy(&temp16, bufpos, sizeof(temp16)); bufpos+=sizeof(temp16); count=le16_to_cpu(temp16); // read items for (i=0; i < count; i++) { // a. read type from buffer memcpy(&type, bufpos, sizeof(type)); bufpos+=sizeof(section); // b. read section from buffer memcpy(§ion, bufpos, sizeof(section)); bufpos+=sizeof(section); // c. read key from buffer memcpy(&temp16, bufpos, sizeof(temp16)); bufpos+=sizeof(temp16); key=le16_to_cpu(temp16); // d. read sizeof(data) memcpy(&temp16, bufpos, sizeof(temp16)); bufpos+=sizeof(temp16); size=le16_to_cpu(temp16); // e. add item to dico if (dico_add_generic(d, section, key, bufpos, size, type)!=0) return OLDERR_FATAL; bufpos+=size; } free(buffer); return FSAERR_SUCCESS; } int archreader_read_header(carchreader *ai, char *magic, cdico **d, bool allowseek, u16 *fsid) { s64 curpos; u16 temp16; u32 temp32; u32 archid; int res; assert(ai); assert(d); assert(fsid); // init memset(magic, 0, FSA_SIZEOF_MAGIC); *fsid=FSA_FILESYSID_NULL; *d=NULL; if ((*d=dico_alloc())==NULL) { errprintf("dico_alloc() failed\n"); return OLDERR_FATAL; } // search for next read header marker and magic (it may be further if corruption in archive) if ((curpos=lseek64(ai->archfd, 0, SEEK_CUR))<0) { sysprintf("lseek64() failed to get the current position in archive\n"); return OLDERR_FATAL; } if ((res=archreader_read_data(ai, magic, FSA_SIZEOF_MAGIC))!=FSAERR_SUCCESS) { msgprintf(MSG_STACK, "cannot read header magic: res=%d\n", res); return OLDERR_FATAL; } // we don't want to search for the magic if it's a volume header if (is_magic_valid(magic)!=true && allowseek!=true) { errprintf("cannot read header magic: this is not a valid fsarchiver file, or it has been created with a different version.\n"); return OLDERR_FATAL; } while (is_magic_valid(magic)!=true) { if (lseek64(ai->archfd, curpos++, SEEK_SET)<0) { sysprintf("lseek64(pos=%lld, SEEK_SET) failed\n", (long long)curpos); return OLDERR_FATAL; } if ((res=archreader_read_data(ai, magic, FSA_SIZEOF_MAGIC))!=FSAERR_SUCCESS) { msgprintf(MSG_STACK, "cannot read header magic: res=%d\n", res); return OLDERR_FATAL; } } // read the archive id if ((res=archreader_read_data(ai, &temp32, sizeof(temp32)))!=FSAERR_SUCCESS) { msgprintf(MSG_STACK, "cannot read archive-id in header: res=%d\n", res); return OLDERR_FATAL; } archid=le32_to_cpu(temp32); if (ai->archid) // only check archive-id if it's known (when main header has been read) { if (archid!=ai->archid) { errprintf("archive-id in header does not match: archid=[%.8x], expected=[%.8x]\n", archid, ai->archid); return OLDERR_MINOR; } } // read the filesystem id if ((res=archreader_read_data(ai, &temp16, sizeof(temp16)))!=FSAERR_SUCCESS) { msgprintf(MSG_STACK, "cannot read filesystem-id in header: res=%d\n", res); return OLDERR_FATAL; } *fsid=le16_to_cpu(temp16); // read the dico of the header if ((res=archreader_read_dico(ai, *d))!=FSAERR_SUCCESS) { msgprintf(MSG_STACK, "imgdisk_read_dico() failed\n"); return res; } return FSAERR_SUCCESS; } int archreader_read_volheader(carchreader *ai) { char creatver[FSA_MAX_PROGVERLEN]; char filefmt[FSA_MAX_FILEFMTLEN]; char magic[FSA_SIZEOF_MAGIC]; cdico *d; u32 volnum; u32 readid; u16 fsid; int res; int ret=0; // init assert(ai); memset(magic, 0, sizeof(magic)); // ---- a. read header from archive file if ((res=archreader_read_header(ai, magic, &d, false, &fsid))!=FSAERR_SUCCESS) { errprintf("archreader_read_header() failed to read the archive header\n"); return -1; } // ---- b. check the magic is what we expected if (strncmp(magic, FSA_MAGIC_VOLH, FSA_SIZEOF_MAGIC)!=0) { errprintf("magic is not what we expected: found=[%s] and expected=[%s]\n", magic, FSA_MAGIC_VOLH); ret=-1; goto archio_read_volheader_error; } if (dico_get_u32(d, 0, VOLUMEHEADKEY_ARCHID, &readid)!=0) { errprintf("cannot get VOLUMEHEADKEY_ARCHID from the volume header\n"); ret=-1; goto archio_read_volheader_error; } // ---- c. check the archive id if (ai->archid==0) // archid not know: this is the first volume { ai->archid=readid; } else if (readid!=ai->archid) // archid known: not the first volume { errprintf("wrong header id: found=%.8x and expected=%.8x\n", readid, ai->archid); ret=-1; goto archio_read_volheader_error; } // ---- d. check the volnum if (dico_get_u32(d, 0, VOLUMEHEADKEY_VOLNUM, &volnum)!=0) { errprintf("cannot get VOLUMEHEADKEY_VOLNUM from the volume header\n"); ret=-1; goto archio_read_volheader_error; } if (volnum!=ai->curvol) // not the right volume number { errprintf("wrong volume number in [%s]: volnum is %d and we need volnum %d\n", ai->volpath, (int)volnum, (int)ai->curvol); ret=-1; goto archio_read_volheader_error; } // ---- d. check the the file format if (dico_get_data(d, 0, VOLUMEHEADKEY_FILEFORMATVER, filefmt, FSA_MAX_FILEFMTLEN, NULL)!=0) { errprintf("cannot find VOLUMEHEADKEY_FILEFORMATVER in main-header\n"); ret=-1; goto archio_read_volheader_error; } if (ai->filefmt[0]==0) // filefmt not know: this is the first volume { memcpy(ai->filefmt, filefmt, FSA_MAX_FILEFMTLEN); } else if (strncmp(filefmt, ai->filefmt, FSA_MAX_FILEFMTLEN)!=0) { errprintf("This archive is based on a different file format: [%s]. Cannot continue.\n", ai->filefmt); errprintf("It has been created with fsarchiver [%s], you should extrat the archive using that version.\n", ai->creatver); errprintf("The current version of the program is [%s], and it's based on format [%s]\n", FSA_VERSION, FSA_FILEFORMAT); ret=-1; goto archio_read_volheader_error; } if (dico_get_data(d, 0, VOLUMEHEADKEY_PROGVERCREAT, creatver, FSA_MAX_PROGVERLEN, NULL)!=0) { errprintf("cannot find VOLUMEHEADKEY_PROGVERCREAT in main-header\n"); ret=-1; goto archio_read_volheader_error; } if (ai->creatver[0]==0) memcpy(ai->creatver, creatver, FSA_MAX_PROGVERLEN); archio_read_volheader_error: dico_destroy(d); return ret; } int archreader_read_block(carchreader *ai, cdico *in_blkdico, int in_skipblock, int *out_sumok, struct s_blockinfo *out_blkinfo) { u32 arblockcsumorig; u32 arblockcsumcalc; u32 curblocksize; // data size u64 blockoffset; // offset of the block in the file u16 compalgo; // compression algo used u16 cryptalgo; // encryption algo used u32 finalsize; // compressed block size u32 compsize; u8 *buffer; assert(ai); assert(out_sumok); assert(in_blkdico); assert(out_blkinfo); // init memset(out_blkinfo, 0, sizeof(struct s_blockinfo)); *out_sumok=-1; if (dico_get_u64(in_blkdico, 0, BLOCKHEADITEMKEY_BLOCKOFFSET, &blockoffset)!=0) { msgprintf(3, "cannot get blockoffset from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_REALSIZE, &curblocksize)!=0 || curblocksize>FSA_MAX_BLKSIZE) { msgprintf(3, "cannot get blocksize from block-header\n"); return -1; } if (dico_get_u16(in_blkdico, 0, BLOCKHEADITEMKEY_COMPRESSALGO, &compalgo)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_COMPRESSALGO from block-header\n"); return -1; } if (dico_get_u16(in_blkdico, 0, BLOCKHEADITEMKEY_ENCRYPTALGO, &cryptalgo)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_ENCRYPTALGO from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_ARSIZE, &finalsize)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_ARSIZE from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_COMPSIZE, &compsize)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_COMPSIZE from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_ARCSUM, &arblockcsumorig)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_ARCSUM from block-header\n"); return -1; } if (in_skipblock==true) // the main thread does not need that block (block belongs to a filesys we want to skip) { if (lseek64(ai->archfd, (long)finalsize, SEEK_CUR)<0) { sysprintf("cannot skip block (finalsize=%ld) failed\n", (long)finalsize); return -1; } return 0; } // ---- allocate memory if ((buffer=malloc(finalsize))==NULL) { errprintf("cannot allocate block: malloc(%d) failed\n", finalsize); return FSAERR_ENOMEM; } if (read(ai->archfd, buffer, (long)finalsize)!=(long)finalsize) { sysprintf("cannot read block (finalsize=%ld) failed\n", (long)finalsize); free(buffer); return -1; } // prepare blkinfo out_blkinfo->blkdata=(char*)buffer; out_blkinfo->blkrealsize=curblocksize; out_blkinfo->blkoffset=blockoffset; out_blkinfo->blkarcsum=arblockcsumorig; out_blkinfo->blkcompalgo=compalgo; out_blkinfo->blkcryptalgo=cryptalgo; out_blkinfo->blkarsize=finalsize; out_blkinfo->blkcompsize=compsize; // ---- checksum arblockcsumcalc=fletcher32(buffer, finalsize); if (arblockcsumcalc!=arblockcsumorig) // bad checksum { errprintf("block is corrupt at offset=%ld, blksize=%ld\n", (long)blockoffset, (long)curblocksize); free(out_blkinfo->blkdata); if ((out_blkinfo->blkdata=malloc(curblocksize))==NULL) { errprintf("cannot allocate block: malloc(%d) failed\n", curblocksize); return FSAERR_ENOMEM; } memset(out_blkinfo->blkdata, 0, curblocksize); *out_sumok=false; // go to the beginning of the corrupted contents so that the next header is searched here if (lseek64(ai->archfd, -(long long)finalsize, SEEK_CUR)<0) { errprintf("lseek64() failed\n"); } } else // no corruption detected { *out_sumok=true; } return 0; } fsarchiver-0.8.5/src/types.h0000644000176100017610000000440213242523705012714 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __TYPES_H__ #define __TYPES_H__ #include #include #include #include #include typedef uint8_t u8; typedef int8_t s8; typedef uint16_t u16; typedef int16_t s16; typedef uint32_t u32; typedef int32_t s32; typedef uint64_t u64; typedef int64_t s64; #define le8_to_cpu(v) (v) #define cpu_to_le8(v) (v) #if __BYTE_ORDER == __BIG_ENDIAN // CPU == big endian (sparc, ppc, ...) # define cpu_to_le16(x) ((u16)(bswap_16(x))) # define le16_to_cpu(x) ((u16)(bswap_16(x))) # define cpu_to_le32(x) ((u32)(bswap_32(x))) # define le32_to_cpu(x) ((u32)(bswap_32(x))) # define cpu_to_le64(x) ((u64)(bswap_64(x))) # define le64_to_cpu(x) ((u64)(bswap_64(x))) # define be16_to_cpu(x) ((u16)(x)) # define cpu_to_be16(x) ((u16)(x)) # define be32_to_cpu(x) ((u32)(x)) # define cpu_to_be32(x) ((u32)(x)) # define be64_to_cpu(x) ((u64)(x)) # define cpu_to_be64(x) ((u64)(x)) #else // CPU == little endian (intel) # define cpu_to_le16(x) ((u16)(x)) # define le16_to_cpu(x) ((u16)(x)) # define cpu_to_le32(x) ((u32)(x)) # define le32_to_cpu(x) ((u32)(x)) # define cpu_to_le64(x) ((u64)(x)) # define le64_to_cpu(x) ((u64)(x)) # define be16_to_cpu(x) ((bswap_16(x))) # define cpu_to_be16(x) ((bswap_16(x))) # define be32_to_cpu(x) ((bswap_32(x))) # define cpu_to_be32(x) ((bswap_32(x))) # define be64_to_cpu(x) ((bswap_64(x))) # define cpu_to_be64(x) ((bswap_64(x))) #endif // atomic type. typedef struct { volatile int counter; } atomic_t; // read atomic variable #define atomic_read(v) ((v)->counter) // Set atomic variable #define atomic_set(v,i) (((v)->counter) = (i)) #endif // __TYPES_H__ fsarchiver-0.8.5/src/fs_reiserfs.c0000644000176100017610000001363313242523705014063 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include "fsarchiver.h" #include "fsarchiver.h" #include "dico.h" #include "common.h" #include "fs_reiserfs.h" #include "filesys.h" #include "strlist.h" #include "error.h" int reiserfs_mkfs(cdico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid) { char command[2048]; char buffer[2048]; char options[2048]; int exitst; u64 temp64; // ---- check mkreiserfs is available if (exec_command(command, sizeof(command), NULL, NULL, 0, NULL, 0, "mkreiserfs -V")!=0) { errprintf("mkreiserfs not found. please install reiserfsprogs-3.6 on your system or check the PATH.\n"); return -1; } // ---- set the advanced filesystem settings from the dico memset(options, 0, sizeof(options)); strlcatf(options, sizeof(options), " %s ", fsoptions); if (strlen(mkfslabel) > 0) strlcatf(options, sizeof(options), " -l '%.16s' ", mkfslabel); else if (dico_get_string(d, 0, FSYSHEADKEY_FSLABEL, buffer, sizeof(buffer))==0 && strlen(buffer)>0) strlcatf(options, sizeof(options), " -l '%.16s' ", buffer); if (dico_get_u64(d, 0, FSYSHEADKEY_FSREISERBLOCKSIZE, &temp64)==0) strlcatf(options, sizeof(options), " -b %ld ", (long)temp64); if (strlen(mkfsuuid) > 0) strlcatf(options, sizeof(options), " -u %s ", mkfsuuid); else if (dico_get_string(d, 0, FSYSHEADKEY_FSUUID, buffer, sizeof(buffer))==0 && strlen(buffer)==36) strlcatf(options, sizeof(options), " -u %s ", buffer); if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "mkreiserfs -f %s %s", partition, options)!=0 || exitst!=0) { errprintf("command [%s] failed\n", command); return -1; } return 0; } int reiserfs_getinfo(cdico *d, char *devname) { struct reiserfs_super_block sb; char uuid[512]; u16 temp16; int ret=0; int fd=-1; int res; if ((fd=open64(devname, O_RDONLY|O_LARGEFILE))<0) { ret=-1; errprintf("cannot open(%s, O_RDONLY)\n", devname); goto reiserfs_read_sb_return; } if (lseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET)!=REISERFS_DISK_OFFSET_IN_BYTES) { ret=-2; errprintf("cannot lseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET) on %s\n", devname); goto reiserfs_read_sb_close; } res=read(fd, &sb, sizeof(sb)); if (res!=sizeof(sb)) { ret=-3; errprintf("cannot read the reiserfs superblock on device [%s]\n", devname); goto reiserfs_read_sb_close; } if (strncmp(sb.s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING, strlen(REISERFS_SUPER_MAGIC_STRING)) == 0) dico_add_string(d, 0, FSYSHEADKEY_FSVERSION, "reiserfs-3.5"); else if (strncmp(sb.s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING, strlen(REISER2FS_SUPER_MAGIC_STRING)) == 0) dico_add_string(d, 0, FSYSHEADKEY_FSVERSION, "reiserfs-3.6"); else { ret=-4; errprintf("magic different from expectations superblock on %s: magic=[%s]\n", devname, sb.s_v1.s_magic); goto reiserfs_read_sb_close; } msgprintf(MSG_DEBUG1, "reiserfs_magic=[%s]\n", sb.s_v1.s_magic); // ---- label msgprintf(MSG_DEBUG1, "reiserfs_label=[%s]\n", sb.s_label); dico_add_string(d, 0, FSYSHEADKEY_FSLABEL, (char*)sb.s_label); // ---- uuid /*if ((str=e2p_uuid2str(sb.s_uuid))!=NULL) dico_add_string(d, 0, FSYSHEADKEY_FSUUID, str);*/ memset(uuid, 0, sizeof(uuid)); uuid_unparse_lower((u8*)sb.s_uuid, uuid); dico_add_string(d, 0, FSYSHEADKEY_FSUUID, uuid); msgprintf(MSG_DEBUG1, "reiserfs_uuid=[%s]\n", uuid); // ---- block size temp16=le16_to_cpu(sb.s_v1.s_blocksize); dico_add_u64(d, 0, FSYSHEADKEY_FSREISERBLOCKSIZE, temp16); msgprintf(MSG_DEBUG1, "reiserfs_blksize=[%ld]\n", (long)temp16); // ---- minimum fsarchiver version required to restore dico_add_u64(d, 0, FSYSHEADKEY_MINFSAVERSION, FSA_VERSION_BUILD(0, 6, 4, 0)); reiserfs_read_sb_close: close(fd); reiserfs_read_sb_return: return ret; } int reiserfs_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo) { return generic_mount(partition, mntbuf, fsbuf, "user_xattr,acl", flags); } int reiserfs_umount(char *partition, char *mntbuf) { return generic_umount(mntbuf); } int reiserfs_test(char *devname) { struct reiserfs_super_block sb; int fd=-1; if ((fd=open64(devname, O_RDONLY|O_LARGEFILE))<0) return false; if (lseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET)!=REISERFS_DISK_OFFSET_IN_BYTES) { close(fd); return false; } if (read(fd, &sb, sizeof(sb))!=sizeof(sb)) { close(fd); return false; } if ((strncmp(sb.s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING, strlen(REISERFS_SUPER_MAGIC_STRING)) != 0) && (strncmp(sb.s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING, strlen(REISER2FS_SUPER_MAGIC_STRING)) != 0)) { close(fd); return false; } close(fd); return true; } int reiserfs_get_reqmntopt(char *partition, cstrlist *reqopt, cstrlist *badopt) { if (!reqopt || !badopt) return -1; strlist_add(badopt, "nouser_xattr"); strlist_add(badopt, "noacl"); return 0; } fsarchiver-0.8.5/src/common.h0000644000176100017610000000442613242523705013046 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __COMMON_H__ #define __COMMON_H__ #include struct timeval; struct s_strlist; struct s_stats; int exec_command(char *command, int cmdbufsize, int *exitst, char *stdoutbuf, int stdoutsize, char *stderrbuf, int stderrsize, char *format, ...); int get_parent_dir_time_attrib(char *filepath, char *parentdirbuf, int bufsize, struct timeval *tv); void concatenate_paths(char *buffer, int maxbufsize, char *p1, char *p2); int path_force_extension(char *buf, int bufsize, char *origpath, char *ext); char *format_size(u64 size, char *text, int max, char units); int image_write_data(int fdarch, char *buffer, int buflen); int extract_dirpath(char *filepath, char *dirbuf, int dirbufsize); int extract_basename(char *filepath, char *basenamebuf, int basenamebufsize); int generate_random_tmpdir(char *buffer, int bufsize, int n); char *format_time(char *buffer, int bufsize, u64 t); int stream_readline(FILE *f, char *buf, int buflen); char *format_md5(char *buf, int maxbuf, u8 *md5bin); int getpathtoprog(char *buffer, int bufsize, char *prog); int mkdir_recursive(char *path); char *get_objtype_name(int objtype); int is_dir_empty(char *path); u32 generate_random_u32_id(void); u32 fletcher32(u8 *data, u32 len); int regfile_exists(char *filepath); int is_magic_valid(char *magic); char *strlcatf(char *dest, int destbufsize, char *format, ...) __attribute__ ((format (printf, 3, 4))); int format_stacktrace(char *buffer, int bufsize); int stats_show(struct s_stats, int fsid); u64 stats_errcount(struct s_stats stats); int exclude_check(struct s_strlist *patlist, char *string); int get_path_to_volume(char *newvolbuf, int bufsize, char *basepath, long curvol); s64 get_device_size(char *partition); #endif // __COMMON_H__ fsarchiver-0.8.5/src/comp_gzip.h0000644000176100017610000000156113242523705013542 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __COMPRESS_GZIP_H__ #define __COMPRESS_GZIP_H__ int compress_block_gzip(u64 origsize, u64 *compsize, u8 *origbuf, u8 *compbuf, u64 compbufsize, int level); int uncompress_block_gzip(u64 compsize, u64 *origsize, u8 *origbuf, u64 origbufsize, u8 *compbuf); #endif // __COMPRESS_GZIP_H__ fsarchiver-0.8.5/src/archwriter.h0000644000176100017610000000503713242523705013727 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __ARCHWRITER_H__ #define __ARCHWRITER_H__ #include #include "strlist.h" struct s_writebuf; struct s_blockinfo; struct s_headinfo; struct s_strlist; struct s_archwriter; typedef struct s_archwriter carchwriter; struct s_archwriter { int archfd; // file descriptor of the current volume (set to -1 when closed) u32 archid; // 32bit archive id for checking (random number generated at creation) u32 curvol; // current volume number, starts at 0, incremented when we change the volume bool newarch; // true when the archive has been created by then current process char filefmt[FSA_MAX_FILEFMTLEN]; // file format of that archive char creatver[FSA_MAX_PROGVERLEN]; // fsa version used to create archive char label[FSA_MAX_LABELLEN]; // archive label defined by the user char basepath[PATH_MAX]; // path of the first volume of an archive char volpath[PATH_MAX]; // path of the current volume of an archive cstrlist vollist; // paths to all volumes of an archive }; int archwriter_init(carchwriter *ai); int archwriter_destroy(carchwriter *ai); int archwriter_create(carchwriter *ai); int archwriter_close(carchwriter *ai); int archwriter_remove(carchwriter *ai); int archwriter_generate_id(carchwriter *ai); s64 archwriter_get_currentpos(carchwriter *ai); int archwriter_is_path_to_curvol(carchwriter *ai, char *path); int archwriter_write_buffer(carchwriter *ai, struct s_writebuf *wb); int archwriter_incvolume(carchwriter *ai, bool waitkeypress); int archwriter_volpath(carchwriter *ai); int archwriter_write_volheader(carchwriter *ai); int archwriter_write_volfooter(carchwriter *ai, bool lastvol); int archwriter_split_check(carchwriter *ai, struct s_writebuf *wb); int archwriter_split_if_necessary(carchwriter *ai, struct s_writebuf *wb); int archwriter_dowrite_block(carchwriter *ai, struct s_blockinfo *blkinfo); int archwriter_dowrite_header(carchwriter *ai, struct s_headinfo *headinfo); #endif // __ARCHWRITER_H__ fsarchiver-0.8.5/src/fs_ext2.c0000644000176100017610000006653613270012765013135 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include "fsarchiver.h" #include "dico.h" #include "common.h" #include "strlist.h" #include "filesys.h" #include "fs_ext2.h" #include "error.h" // e2fsprogs version required to work on ext2, ext3, ext4 u64 e2fsprogs_minver[]={PROGVER(1,39,0), PROGVER(1,39,0), PROGVER(1,41,0)}; struct mntopt { unsigned int mask; const char *string; }; struct s_features { char *name; // name of that feature int mask; // identifier for that feature int compat; // compat type for that feature (see e2p.h) int firstfs; // type of the first filesystem to support it u64 firste2p; // first e2fsprogs version that supports that feature }; // These are the features to be passed on the command line (cf "man ext4") struct s_features mkfeatures[] = // cf e2fsprogs-1.44.0/lib/e2p/feature.c { {"has_journal", FSA_EXT3_FEATURE_COMPAT_HAS_JOURNAL, E2P_FEATURE_COMPAT, EXTFSTYPE_EXT3, PROGVER(1,39,0)}, {"ext_attr", FSA_EXT2_FEATURE_COMPAT_EXT_ATTR, E2P_FEATURE_COMPAT, EXTFSTYPE_EXT2, PROGVER(1,40,5)}, {"resize_inode", FSA_EXT2_FEATURE_COMPAT_RESIZE_INODE, E2P_FEATURE_COMPAT, EXTFSTYPE_EXT2, PROGVER(1,39,0)}, {"dir_index", FSA_EXT2_FEATURE_COMPAT_DIR_INDEX, E2P_FEATURE_COMPAT, EXTFSTYPE_EXT2, PROGVER(1,33,0)}, {"sparse_super2", FSA_EXT4_FEATURE_COMPAT_SPARSE_SUPER2, E2P_FEATURE_COMPAT, EXTFSTYPE_EXT4, PROGVER(1,42,10)}, {"filetype", FSA_EXT2_FEATURE_INCOMPAT_FILETYPE, E2P_FEATURE_INCOMPAT, EXTFSTYPE_EXT2, PROGVER(1,16,0)}, {"extent", FSA_EXT4_FEATURE_INCOMPAT_EXTENTS, E2P_FEATURE_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,41,0)}, {"journal_dev", FSA_EXT3_FEATURE_INCOMPAT_JOURNAL_DEV, E2P_FEATURE_INCOMPAT, EXTFSTYPE_EXT3, PROGVER(1,39,0)}, {"flex_bg", FSA_EXT4_FEATURE_INCOMPAT_FLEX_BG, E2P_FEATURE_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,41,0)}, {"meta_bg", FSA_EXT2_FEATURE_INCOMPAT_META_BG, E2P_FEATURE_INCOMPAT, EXTFSTYPE_EXT2, PROGVER(1,39,0)}, {"mmp", FSA_EXT4_FEATURE_INCOMPAT_MMP, E2P_FEATURE_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,42,0)}, {"64bit", FSA_EXT4_FEATURE_INCOMPAT_64BIT, E2P_FEATURE_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,42,0)}, {"inline_data", FSA_EXT4_FEATURE_INCOMPAT_INLINEDATA, E2P_FEATURE_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,43,0)}, {"ea_inode", FSA_EXT4_FEATURE_INCOMPAT_EA_INODE, E2P_FEATURE_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,44,0)}, {"large_dir", FSA_EXT4_FEATURE_INCOMPAT_LARGEDIR, E2P_FEATURE_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,44,0)}, {"large_file", FSA_EXT2_FEATURE_RO_COMPAT_LARGE_FILE, E2P_FEATURE_RO_INCOMPAT, EXTFSTYPE_EXT2, PROGVER(1,40,7)}, {"huge_file", FSA_EXT4_FEATURE_RO_COMPAT_HUGE_FILE, E2P_FEATURE_RO_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,41,0)}, {"sparse_super", FSA_EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER, E2P_FEATURE_RO_INCOMPAT, EXTFSTYPE_EXT2, PROGVER(1,8,0)}, {"uninit_bg", FSA_EXT4_FEATURE_RO_COMPAT_GDT_CSUM, E2P_FEATURE_RO_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,41,0)}, {"dir_nlink", FSA_EXT4_FEATURE_RO_COMPAT_DIR_NLINK, E2P_FEATURE_RO_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,41,0)}, {"extra_isize", FSA_EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE, E2P_FEATURE_RO_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,41,0)}, {"bigalloc", FSA_EXT4_FEATURE_RO_COMPAT_BIGALLOC, E2P_FEATURE_RO_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,42,0)}, {"metadata_csum", FSA_EXT4_FEATURE_RO_COMPAT_METADATA_CSUM, E2P_FEATURE_RO_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,43,0)}, {"project", FSA_EXT4_FEATURE_RO_COMPAT_PROJECT, E2P_FEATURE_RO_INCOMPAT, EXTFSTYPE_EXT4, PROGVER(1,43,0)}, {NULL, 0, 0, 0, 0}, }; char *format_fstype(int fstype) { switch (fstype) { case EXTFSTYPE_EXT2: return "ext2"; case EXTFSTYPE_EXT3: return "ext3"; case EXTFSTYPE_EXT4: return "ext4"; default: return "invalid"; } } int ext2_mkfs(cdico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid) { return extfs_mkfs(d, partition, EXTFSTYPE_EXT2, fsoptions, mkfslabel, mkfsuuid); } int ext3_mkfs(cdico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid) { return extfs_mkfs(d, partition, EXTFSTYPE_EXT3, fsoptions, mkfslabel, mkfsuuid); } int ext4_mkfs(cdico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid) { return extfs_mkfs(d, partition, EXTFSTYPE_EXT4, fsoptions, mkfslabel, mkfsuuid); } int extfs_get_fstype_from_compat_flags(u32 compat, u32 incompat, u32 ro_compat) { int fstype=EXTFSTYPE_EXT2; // distinguish between ext3 and ext2 if (compat & FSA_EXT3_FEATURE_COMPAT_HAS_JOURNAL) fstype=EXTFSTYPE_EXT3; // any features which ext2 doesn't understand if ((ro_compat & FSA_EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) || (incompat & FSA_EXT2_FEATURE_INCOMPAT_UNSUPPORTED)) fstype=EXTFSTYPE_EXT3; // ext4 has at least one feature which ext3 doesn't understand if ((ro_compat & FSA_EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) || (incompat & FSA_EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) fstype=EXTFSTYPE_EXT4; return fstype; } int extfs_check_compatibility(u64 compat, u64 incompat, u64 ro_compat) { // to preserve the filesystem attributes, fsa must know all the features including the COMPAT ones if (compat & ~FSA_FEATURE_COMPAT_SUPP) return -1; if (incompat & ~FSA_FEATURE_INCOMPAT_SUPP) return -1; if (ro_compat & ~FSA_FEATURE_RO_COMPAT_SUPP) return -1; // TODO: check journal features /*if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) && (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) goto check_support_for_features_error;*/ return 0; } int extfs_mkfs(cdico *d, char *partition, int extfstype, char *fsoptions, char *mkfslabel, char *mkfsuuid) { cstrlist strfeatures; u64 features_tab[3]; u64 fsextrevision; int origextfstype; char buffer[2048]; char command[2048]; char options[2048]; char uuid[64]; bool mke2fsuuid=false; char temp[1024]; char progname[64]; u64 e2fstoolsver; int compat_type; s64 devblkcount; u64 devblksize; u64 devisize; s64 threshold64bit; s64 devsize; u64 temp64; int exitst; int ret=0; int res; int i; // init memset(options, 0, sizeof(options)); memset(uuid, 0, sizeof(uuid)); snprintf(progname, sizeof(progname), "mke2fs"); strlist_init(&strfeatures); // ---- check that mkfs is installed and get its version if (exec_command(command, sizeof(command), NULL, NULL, 0, NULL, 0, "%s -V", progname)!=0) { errprintf("%s not found. please install a recent e2fsprogs on your system or check the PATH.\n", progname); ret=-1; goto extfs_mkfs_cleanup; } e2fstoolsver=check_prog_version(progname); // ---- check what is the extfs block size to use if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTBLOCKSIZE, &devblksize)!=0) devblksize=4096; // ---- check what is the extfs inode size to use if (dico_get_u64(d, 0, FSYSHEADKEY_FSINODESIZE, &devisize)!=0) devisize=256; // ---- filesystem revision (good-old-rev or dynamic) if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTREVISION, &fsextrevision)!=0) fsextrevision=EXT2_DYNAMIC_REV; // don't fail (case of fs conversion to extfs) // "mke2fs -q" prevents problems in exec_command when too many output details printed strlcatf(options, sizeof(options), " -q "); // "mke2fs -F" removes confirmation prompt when device is a whole disk such as /dev/sda strlcatf(options, sizeof(options), " -F "); strlcatf(options, sizeof(options), " %s ", fsoptions); strlcatf(options, sizeof(options), " -b %ld ", (long)devblksize); // ---- set the advanced filesystem settings from the dico if (strlen(mkfslabel) > 0) strlcatf(options, sizeof(options), " -L '%.16s' ", mkfslabel); else if (dico_get_string(d, 0, FSYSHEADKEY_FSLABEL, buffer, sizeof(buffer))==0 && strlen(buffer)>0) strlcatf(options, sizeof(options), " -L '%.16s' ", buffer); // ---- determine which UUID must be set on this filesystem if (strlen(mkfsuuid) > 0) snprintf(uuid, sizeof(uuid), "%s", mkfsuuid); else if (dico_get_string(d, 0, FSYSHEADKEY_FSUUID, buffer, sizeof(buffer))==0) snprintf(uuid, sizeof(uuid), "%s", buffer); // ---- set UUID with mke2fs if supported if (e2fstoolsver>=PROGVER(1,41,4) && strlen(uuid)==36) { strlcatf(options, sizeof(options), " -U %s ", uuid); mke2fsuuid=true; } // ---- get original filesystem features (if the original filesystem was an ext{2,3,4}) if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFEATURECOMPAT, &features_tab[E2P_FEATURE_COMPAT])!=0 || dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFEATUREINCOMPAT, &features_tab[E2P_FEATURE_INCOMPAT])!=0 || dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFEATUREROCOMPAT, &features_tab[E2P_FEATURE_RO_INCOMPAT])!=0 || fsextrevision==EXT2_GOOD_OLD_REV) { // dont fail the original filesystem may not be ext{2,3,4}. in that case set defaults features // ext2 revision 0 does not have features, set defaults too in case user wants to upgrade it features_tab[E2P_FEATURE_COMPAT]=EXT2_FEATURE_COMPAT_RESIZE_INODE|\ EXT2_FEATURE_COMPAT_DIR_INDEX|\ EXT2_FEATURE_COMPAT_EXT_ATTR; features_tab[E2P_FEATURE_INCOMPAT]=EXT2_FEATURE_INCOMPAT_FILETYPE; features_tab[E2P_FEATURE_RO_INCOMPAT]=EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; } // ---- check that fsarchiver is aware of all the filesystem features used on that filesystem if (extfs_check_compatibility(features_tab[E2P_FEATURE_COMPAT], features_tab[E2P_FEATURE_INCOMPAT], features_tab[E2P_FEATURE_RO_INCOMPAT])!=0) { errprintf("this filesystem has ext{2,3,4} features which are not supported by this fsarchiver version.\n"); ret=-1; goto extfs_mkfs_cleanup; } // ---- get original filesystem type origextfstype=extfs_get_fstype_from_compat_flags(features_tab[E2P_FEATURE_COMPAT], features_tab[E2P_FEATURE_INCOMPAT], features_tab[E2P_FEATURE_RO_INCOMPAT]); msgprintf(MSG_VERB2, "the filesystem type determined by the original filesystem features is [%s]\n", format_fstype(origextfstype)); // remove all the features not supported by the filesystem to create (conversion = downgrade fs) for (i=0; mkfeatures[i].name; i++) { compat_type=mkfeatures[i].compat; if (mkfeatures[i].firstfs > extfstype) features_tab[compat_type] &= ~mkfeatures[i].mask; } // add new features if the filesystem to create is newer than the filesystem type that was backed up // eg: user did a "savefs" of an ext3 and does a "restfs mkfs=ext4" --> add features to force ext4 // it's a bit more difficult because we only want to add such a feature if no feature of the new // filesystem is currently enabled. msgprintf(MSG_VERB2, "the filesystem type to create considering the command options is [%s]\n", format_fstype(extfstype)); if (origextfstype==EXTFSTYPE_EXT2 && extfstype>EXTFSTYPE_EXT2) // upgrade ext2 to ext{3,4} { fsextrevision=EXT2_DYNAMIC_REV; features_tab[E2P_FEATURE_COMPAT]|=EXT3_FEATURE_COMPAT_HAS_JOURNAL; } if (origextfstype=EXTFSTYPE_EXT4) // upgrade ext{2,3} to ext4 { // ext4 default features from mke2fs 1.41: // extents,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize // recent mke2fs versions enable more features, but we are conservative here fsextrevision=EXT2_DYNAMIC_REV; devisize=256; features_tab[E2P_FEATURE_INCOMPAT]|=EXT3_FEATURE_INCOMPAT_EXTENTS|\ EXT4_FEATURE_INCOMPAT_FLEX_BG; features_tab[E2P_FEATURE_RO_INCOMPAT]|=EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\ EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\ EXT4_FEATURE_RO_COMPAT_HUGE_FILE; } // get size of the target device if ((devsize=get_device_size(partition))<0) { errprintf("failed to check the size of the target device: [%s]\n", partition); ret=-1; goto extfs_mkfs_cleanup; } // special logic required if the target device is equal or more than 2^32 blocks long devblkcount=devsize/devblksize; threshold64bit=(1LL<<32LL); msgprintf(MSG_VERB2, "the filesystem block size is %ld bytes long\n", (long)devblksize); msgprintf(MSG_VERB2, "device [%s] size is %lld bytes (%lld blocks) long\n", partition, (long long)devsize, (long long)devblkcount); if (devblkcount >= threshold64bit) { msgprintf(MSG_VERB1, "device [%s] is at least %lld blocks long and requires ext4\n" "with the [64bit] feature\n", partition, (long long)threshold64bit); if (extfstype feature [%s]=YES\n", mkfeatures[i].name); strlist_add(&strfeatures, mkfeatures[i].name); } else { msgprintf(MSG_VERB2, "--> feature [%s]=NO\n", mkfeatures[i].name); snprintf(temp, sizeof(temp), "^%s", mkfeatures[i].name); // exclude feature strlist_add(&strfeatures, temp); } } } // inode size strlcatf(options, sizeof(options), " -I %ld ", (long)devisize); // filesystem revision: good-old-rev or dynamic strlcatf(options, sizeof(options), " -r %d ", (int)fsextrevision); // if extfs revision is dynamic and there are features in the list if (fsextrevision!=EXT2_GOOD_OLD_REV && strlist_count(&strfeatures)>0) { strlist_merge(&strfeatures, temp, sizeof(temp), ','); strlcatf(options, sizeof(options), " -O %s ", temp); msgprintf(MSG_VERB2, "features: mkfs_options+=[-O %s]\n", temp); } // ---- check mke2fs version requirement msgprintf(MSG_VERB2, "mke2fs version detected: %s\n", format_prog_version(e2fstoolsver, temp, sizeof(temp))); msgprintf(MSG_VERB2, "mke2fs version required: %s\n", format_prog_version(e2fsprogs_minver[extfstype], temp, sizeof(temp))); if (e2fstoolsver < e2fsprogs_minver[extfstype]) { errprintf("mke2fs was found but is too old, please upgrade to a version %s or more recent.\n", format_prog_version(e2fsprogs_minver[extfstype], temp, sizeof(temp))); ret=-1; goto extfs_mkfs_cleanup; } // ---- extended options if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTEOPTRAIDSTRIDE, &temp64)==0) strlcatf(options, sizeof(options), " -E stride=%ld ", (long)temp64); if ((dico_get_u64(d, 0, FSYSHEADKEY_FSEXTEOPTRAIDSTRIPEWIDTH, &temp64)==0) && e2fstoolsver>=PROGVER(1,40,7)) strlcatf(options, sizeof(options), " -E stripe-width=%ld ", (long)temp64); // ---- execute mke2fs msgprintf(MSG_VERB2, "exec: %s\n", command); if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "%s %s %s", progname, partition, options)!=0 || exitst!=0) { errprintf("command [%s] failed with return status=%d\n", command, exitst); ret=-1; goto extfs_mkfs_cleanup; } // ---- use tune2fs to set the other advanced options memset(options, 0, sizeof(options)); if (!mke2fsuuid && strlen(uuid)==36) strlcatf(options, sizeof(options), " -U %s ", uuid); if (dico_get_string(d, 0, FSYSHEADKEY_FSEXTDEFMNTOPT, buffer, sizeof(buffer))==0 && strlen(buffer)>0) strlcatf(options, sizeof(options), " -o %s ", buffer); if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFSCKMAXMNTCOUNT, &temp64)==0) strlcatf(options, sizeof(options), " -c %ld ", (long)temp64); if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFSCKCHECKINTERVAL, &temp64)==0) strlcatf(options, sizeof(options), " -i %ldd ", (long)(temp64/86400L)); if (options[0]) { if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "tune2fs %s %s", partition, options)!=0 || exitst!=0) { errprintf("command [%s] failed with return status=%d\n", command, exitst); ret=-1; goto extfs_mkfs_cleanup; } // if UUID was not set by mke2fs, we have e2fsprogs < 1.41.4 // tune2fs will mess up ext4 filesystem when changing its UUID // http://marc.info/?l=linux-ext4&m=123246035924487&w=2 if (extfstype==EXTFSTYPE_EXT4 && !mke2fsuuid) { if ( ((res=exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "e2fsck -fy %s", partition))!=0) || ((exitst!=0) && (exitst!=1)) ) { errprintf("command [%s] failed with return status=%d\n", command, exitst); ret=-1; goto extfs_mkfs_cleanup; } } } extfs_mkfs_cleanup: strlist_destroy(&strfeatures); return ret; } int extfs_getinfo(cdico *d, char *devname) { struct fsa_ext2_sb *super; blk_t use_superblock=0; int use_blocksize=0; char uuid[512]; ext2_filsys fs; int origextfstype; char mntopt[1024]; char label[80]; u32 mask, m; int count; int i; // ---- open partition if (ext2fs_open(devname, EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES, use_superblock, use_blocksize, unix_io_manager, &fs)!=0) { errprintf("ext2fs_open(%s) failed\n", devname); return -1; } super=(struct fsa_ext2_sb *)fs->super; // --- label memset(label, 0, sizeof(label)); if (super->s_volume_name[0]) { memset(label, 0, sizeof(label)); strncpy(label, super->s_volume_name, sizeof(super->s_volume_name)); } dico_add_string(d, 0, FSYSHEADKEY_FSLABEL, label); // ---- uuid /*if ((str=e2p_uuid2str(super->s_uuid))!=NULL) dico_add_string(d, 0, FSYSHEADKEY_FSUUID, str);*/ memset(uuid, 0, sizeof(uuid)); uuid_unparse_lower((u8*)super->s_uuid, uuid); dico_add_string(d, 0, FSYSHEADKEY_FSUUID, uuid); msgprintf(MSG_DEBUG1, "extfs_uuid=[%s]\n", uuid); // ---- block size dico_add_u64(d, 0, FSYSHEADKEY_FSEXTBLOCKSIZE, EXT2_BLOCK_SIZE(super)); // ---- filesystem revision (good-old-rev or dynamic) dico_add_u64(d, 0, FSYSHEADKEY_FSEXTREVISION, super->s_rev_level); // ---- inode size if (super->s_rev_level >= EXT2_DYNAMIC_REV) dico_add_u64(d, 0, FSYSHEADKEY_FSINODESIZE, super->s_inode_size); else dico_add_u64(d, 0, FSYSHEADKEY_FSINODESIZE, EXT2_GOOD_OLD_INODE_SIZE); // Good old rev // ---- extended options if (super->s_raid_stride > 0) { dico_add_u64(d, 0, FSYSHEADKEY_FSEXTEOPTRAIDSTRIDE, super->s_raid_stride); msgprintf(MSG_DEBUG1, "extfs_raid_stride: %u\n", super->s_raid_stride); } if (super->s_raid_stripe_width > 0) { dico_add_u64(d, 0, FSYSHEADKEY_FSEXTEOPTRAIDSTRIPEWIDTH, super->s_raid_stripe_width); msgprintf(MSG_DEBUG1, "extfs_raid_stripe_width: %u\n", super->s_raid_stripe_width); } // ---- fsck details: max_mount_count and check_interval dico_add_u64(d, 0, FSYSHEADKEY_FSEXTFSCKMAXMNTCOUNT, max(super->s_max_mnt_count,0)); dico_add_u64(d, 0, FSYSHEADKEY_FSEXTFSCKCHECKINTERVAL, super->s_checkinterval); msgprintf(MSG_DEBUG1, "extfs_max_mount_count: %ld\n", (long)max(super->s_max_mnt_count,0)); msgprintf(MSG_DEBUG1, "extfs_check_interval: %ld\n", (long)super->s_checkinterval); // ---- default mount options memset(mntopt, 0, sizeof(mntopt)); count=0; mask=super->s_default_mount_opts; if (mask & EXT3_DEFM_JMODE) { strlcatf(mntopt, sizeof(mntopt), "%s", e2p_mntopt2string(mask & EXT3_DEFM_JMODE)); count++; } for (i=0, m=1; i < 32; i++, m<<=1) { if (m & EXT3_DEFM_JMODE) continue; if (mask & m) { if (count++) strlcatf(mntopt, sizeof(mntopt), ","); strlcatf(mntopt, sizeof(mntopt), "%s", e2p_mntopt2string(m)); } } dico_add_string(d, 0, FSYSHEADKEY_FSEXTDEFMNTOPT, mntopt); msgprintf(MSG_DEBUG1, "default mount options: [%s]\n", mntopt); // ---- filesystem features dico_add_u64(d, 0, FSYSHEADKEY_FSEXTFEATURECOMPAT, (u64)super->s_feature_compat); dico_add_u64(d, 0, FSYSHEADKEY_FSEXTFEATUREINCOMPAT, (u64)super->s_feature_incompat); dico_add_u64(d, 0, FSYSHEADKEY_FSEXTFEATUREROCOMPAT, (u64)super->s_feature_ro_compat); origextfstype=extfs_get_fstype_from_compat_flags((u64)super->s_feature_compat, (u64)super->s_feature_incompat, (u64)super->s_feature_ro_compat); msgprintf(MSG_DEBUG1, "the filesystem type determined by the features is [%s]\n", format_fstype(origextfstype)); // ---- check that fsarchiver is aware of all the filesystem features used on that filesystem if (extfs_check_compatibility((u64)super->s_feature_compat, (u64)super->s_feature_incompat, (u64)super->s_feature_ro_compat)!=0) { errprintf("this filesystem has ext{2,3,4} features which are not supported by this fsarchiver version.\n"); return -1; } // ---- minimum fsarchiver version required to restore dico_add_u64(d, 0, FSYSHEADKEY_MINFSAVERSION, FSA_VERSION_BUILD(0, 6, 4, 0)); ext2fs_close(fs); return 0; } int extfs_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo) { blk_t use_superblock=0; int use_blocksize=0; ext2_filsys fs; int origextfstype; char fsname[32]; msgprintf(MSG_DEBUG1, "extfs_mount(partition=[%s], mnt=[%s], fsbuf=[%s])\n", partition, mntbuf, fsbuf); if (ext2fs_open(partition, EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES, use_superblock, use_blocksize, unix_io_manager, &fs)!=0) { msgprintf(MSG_DEBUG1, "ext2fs_open(%s) failed\n", partition); return -1; } origextfstype=extfs_get_fstype_from_compat_flags((u64)fs->super->s_feature_compat, (u64)fs->super->s_feature_incompat, (u64)fs->super->s_feature_ro_compat); snprintf(fsname, sizeof(fsname), "%s", format_fstype(origextfstype)); msgprintf(MSG_VERB2, "the filesystem of [%s] type determined by the features is [%s]\n", partition, fsname); ext2fs_close(fs); if (strcmp(fsname, fsbuf)!=0) { msgprintf(MSG_DEBUG1, "extfs_mount: the filesystem requested [%s] does not match the filesystem detected [%s]\n", fsbuf, fsname); return -1; } return generic_mount(partition, mntbuf, fsbuf, "user_xattr,acl", flags); } int extfs_umount(char *partition, char *mntbuf) { return generic_umount(mntbuf); } int extfs_test(char *partition, int extfstype) // returns true if it's that sort of filesystem { blk_t use_superblock=0; int use_blocksize=0; int extfstypedetected; ext2_filsys fs; if (ext2fs_open(partition, EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES, use_superblock, use_blocksize, unix_io_manager, &fs)!=0) return false; extfstypedetected=extfs_get_fstype_from_compat_flags((u64)fs->super->s_feature_compat, (u64)fs->super->s_feature_incompat, (u64)fs->super->s_feature_ro_compat); msgprintf(MSG_DEBUG1, "the filesystem type determined by the extfs features is [%s]\n", format_fstype(extfstypedetected)); ext2fs_close(fs); // if detected is what is tested, say yes return (extfstypedetected==extfstype); } int ext2_test(char *partition) { return extfs_test(partition, EXTFSTYPE_EXT2); } int ext3_test(char *partition) { return extfs_test(partition, EXTFSTYPE_EXT3); } int ext4_test(char *partition) { return extfs_test(partition, EXTFSTYPE_EXT4); } int extfs_get_reqmntopt(char *partition, cstrlist *reqopt, cstrlist *badopt) { if (!reqopt || !badopt) return -1; strlist_add(badopt, "nouser_xattr"); strlist_add(badopt, "noacl"); return 0; } u64 check_prog_version(char *prog) { char stderrbuf[2048]; char command[2048]; char options[1024]; char temp1[1024]; char delims[]="\n\r"; char *saveptr; char *result; int foundversion; int x, y, z; // init memset(options, 0, sizeof(options)); memset(stderrbuf, 0, sizeof(stderrbuf)); if (exec_command(command, sizeof(command), NULL, NULL, 0, stderrbuf, sizeof(stderrbuf), "%s -V", prog)!=0) { errprintf("program %s was not found or has bad permissions.\n", prog); return -1; } foundversion=false; result=strtok_r(stderrbuf, delims, &saveptr); while (result != NULL && foundversion==false) { if ((memcmp(result, prog, strlen(prog))==0)) foundversion=true; else result = strtok_r(NULL, delims, &saveptr); } if (foundversion==false) { errprintf("can't parse %s version number: no match\n", prog); return 0; } x=y=z=0; sscanf(result, "%1023s %d.%d.%d", temp1, &x, &y, &z); if (x==0 && y==0) { errprintf("can't parse %s version number: x=y=0\n", prog); return 0; } return PROGVER(x,y,z); } fsarchiver-0.8.5/src/oper_restore.h0000644000176100017610000000136413242523705014264 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __OPER_RESTORE_H__ #define __OPER_RESTORE_H__ #include "dico.h" int oper_restore(char *archive, int argc, char **argv, int oper); #endif // __OPER_RESTORE_H__ fsarchiver-0.8.5/src/thread_archio.h0000644000176100017610000000140213242523705014341 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __THREAD_WRITER_H__ #define __THREAD_WRITER_H__ #include void *thread_writer_fct(void *args); void *thread_reader_fct(void *args); #endif // __THREAD_WRITER_H__ fsarchiver-0.8.5/src/dico.c0000644000176100017610000002073013242523705012463 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include "fsarchiver.h" #include "dico.h" #include "common.h" #include "error.h" cdico *dico_alloc() { cdico *d; if ((d=malloc(sizeof(cdico)))==NULL) return NULL; d->head=NULL; return d; } int dico_destroy(cdico *d) { cdicoitem *item, *next; if (d==NULL) return -1; item=d->head; while (item!=NULL) { next=item->next; if (item->data!=NULL) free(item->data); free(item); item=next; } free(d); return 0; } int dico_add_data(cdico *d, u8 section, u16 key, const void *data, u16 size) { return dico_add_generic(d, section, key, data, size, DICTYPE_DATA); } // add an item to the dico, fails if an item with that (section,key) already exists int dico_add_generic(cdico *d, u8 section, u16 key, const void *data, u16 size, u8 type) { cdicoitem *item, *lnew, *last; assert (d); // allocate object lnew=malloc(sizeof(cdicoitem)); if (!lnew) { errprintf("malloc(%ld) failed: out of memory\n", (long)sizeof(cdicoitem)); return -3; } memset(lnew, 0, sizeof(cdicoitem)); // go to the end of the item and check for duplicates if (d->head==NULL) // item is empty { d->head=lnew; } else // item is not empty { for (item=d->head; item!=NULL; item=item->next) { last=item; if (item->section==section && item->key==key) { errprintf("dico_add_generic(): item with key=%ld is already in dico\n", (long)item->key); return -3; } } last->next=lnew; } // copy key lnew->key=key; lnew->section=section; lnew->size=size; lnew->type=type; lnew->data=NULL; // allocate memory for data if (size > 0) { lnew->data=malloc(size); if (!lnew->data) { errprintf("malloc(%ld) failed: out of memory\n", (long)size); return -3; } // copy data memcpy(lnew->data, data, size); } return 0; } int dico_get_data(cdico *d, u8 section, u16 key, void *data, u16 maxsize, u16 *size) { return dico_get_generic(d, section, key, data, maxsize, size); } int dico_get_generic(cdico *d, u8 section, u16 key, void *data, u16 maxsize, u16 *size) { cdicoitem *item; assert(d); assert(data); // size can be NULL if the user does not want to know the size if (size!=NULL) *size=0; if (d->head==NULL) { msgprintf(MSG_DEBUG1, "dico is empty\n"); return -1; } if (maxsize<1) { msgprintf(MSG_DEBUG1, "case1: maxsize=%d\n", maxsize); return -3; } for (item=d->head; item!=NULL; item=item->next) { if ((item!=NULL) && (item->key==key && item->section==section)) { if (item->size > maxsize) // item is too big { msgprintf(MSG_DEBUG1, "case2: (item->size > maxsize): item->size =%d, maxsize=%d\n", item->size, maxsize); return -4; } if ((item->size>0) && (item->data!=NULL)) // there may be no data (size==0) memcpy(data, item->data, item->size); if (size!=NULL) *size=item->size; return 0; } } msgprintf(MSG_DEBUG1, "case3: not found\n"); return -5; // not found } int dico_count_one_section(cdico *d, u8 section) { cdicoitem *item; int count; assert(d); count=0; for (item=d->head; item!=NULL; item=item->next) if (item->section==section) count++; return count; } int dico_count_all_sections(cdico *d) { cdicoitem *item; int count; assert(d); count=0; for (item=d->head; item!=NULL; item=item->next) count++; return count; } int dico_add_u16(cdico *d, u8 section, u16 key, u16 data) { u16 ledata; assert(d); ledata=cpu_to_le16(data); return dico_add_generic(d, section, key, &ledata, sizeof(ledata), DICTYPE_U16); } int dico_add_u32(cdico *d, u8 section, u16 key, u32 data) { u32 ledata; assert(d); ledata=cpu_to_le32(data); return dico_add_generic(d, section, key, &ledata, sizeof(ledata), DICTYPE_U32); } int dico_add_u64(cdico *d, u8 section, u16 key, u64 data) { u64 ledata; assert (d); ledata=cpu_to_le64(data); return dico_add_generic(d, section, key, &ledata, sizeof(ledata), DICTYPE_U64); } int dico_add_string(cdico *d, u8 section, u16 key, const char *szstring) { u16 len; assert(d); assert(szstring); len=strlen(szstring); return dico_add_generic(d, section, key, szstring, len+1, DICTYPE_STRING); } int dico_get_u16(cdico *d, u8 section, u16 key, u16 *data) { u16 ledata; u16 size; assert(d); assert(data); *data=0; if (dico_get_data(d, section, key, &ledata, sizeof(ledata), &size)!=0) return -1; *data=le16_to_cpu(ledata); return 0; } int dico_get_u32(cdico *d, u8 section, u16 key, u32 *data) { u32 ledata; u16 size; assert(d); assert(data); *data=0; if (dico_get_data(d, section, key, &ledata, sizeof(ledata), &size)!=0) return -1; *data=le32_to_cpu(ledata); return 0; } int dico_get_u64(cdico *d, u8 section, u16 key, u64 *data) { u64 ledata; u16 size; assert(d); assert(data); *data=0; if (dico_get_data(d, section, key, &ledata, sizeof(ledata), &size)!=0) return -1; *data=le64_to_cpu(ledata); return 0; } int dico_get_string(cdico *d, u8 section, u16 key, char *buffer, u16 bufsize) { u16 size; assert(d); assert(buffer); memset(buffer, 0, bufsize); return dico_get_data(d, section, key, buffer, bufsize, &size); } int dico_show(cdico *d, u8 section, char *debugtxt) { char buffer[2048]; char text[2048]; cdicoitem *item; assert(d); msgprintf(MSG_FORCE, "\n-----------------debug-dico-begin(%s)---------------\n", debugtxt); if (d->head) { for (item=d->head; item!=NULL; item=item->next) { if (item->section==section) { snprintf(buffer, sizeof(buffer), "key=[%ld], sizeof(data)=[%d], ", (long)item->key, (int)item->size); switch (item->type) { case DICTYPE_U8: snprintf(text, sizeof(text), "type=u8, size=[%d]", (int)item->size); break; case DICTYPE_U16: snprintf(text, sizeof(text), "type=u16, size=[%d]", (int)item->size); break; case DICTYPE_U32: snprintf(text, sizeof(text), "type=u32, size=[%d]", (int)item->size); break; case DICTYPE_U64: snprintf(text, sizeof(text), "type=u64, size=[%d]", (int)item->size); break; case DICTYPE_STRING: snprintf(text, sizeof(text), "type=str, size=[%d], data=[%s]", (int)item->size, (char*)item->data); break; case DICTYPE_DATA: snprintf(text, sizeof(text), "type=dat, size=[%d]", (int)item->size); break; default: snprintf(text, sizeof(text), "type=unknown"); break; } strlcatf(buffer, sizeof(buffer) ,"%s", text); msgprintf(MSG_FORCE, "%s\n", buffer); } } } else { msgprintf(MSG_FORCE, "dico is empty\n"); } msgprintf(MSG_FORCE, "-----------------debug-dico-end(%s)------------------\n\n", debugtxt); return 0; } fsarchiver-0.8.5/src/archreader.h0000644000176100017610000000567013242523705013660 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __ARCHREADER_H__ #define __ARCHREADER_H__ #include struct s_blockinfo; struct s_headinfo; struct s_dico; struct s_archreader; typedef struct s_archreader carchreader; struct s_archreader { int archfd; // file descriptor of the current volume (set to -1 when closed) u32 archid; // 32bit archive id for checking (random number generated at creation) u64 fscount; // how many filesystems in archive (valid only if archtype=filesystems) u32 archtype; // what has been saved in the archive: filesystems or directories u32 curvol; // current volume number, starts at 0, incremented when we change the volume u32 compalgo; // compression algorithm which has been used to create the archive u32 cryptalgo; // encryption algorithm which has been used to create the archive u32 complevel; // compression level which is specific to the compression algorithm u32 fsacomp; // fsa compression level given on the command line by the user u64 creattime; // archive create time (number of seconds since epoch) u64 minfsaver; // minimum fsarchiver version required to restore that archive u32 hasdirsinfohead; // true if the archive has a "DiRs" header (introduced in 0.6.7) int filefmtver; // set to 1 for "FsArCh_001" or 2 for "FsArCh_002" char filefmt[FSA_MAX_FILEFMTLEN]; // file format of that archive char creatver[FSA_MAX_PROGVERLEN]; // fsa version used to create archive char label[FSA_MAX_LABELLEN]; // archive label defined by the user char basepath[PATH_MAX]; // path of the first volume of an archive char volpath[PATH_MAX]; // path of the current volume of an archive }; int archreader_init(carchreader *ai); int archreader_destroy(carchreader *ai); int archreader_open(carchreader *ai); int archreader_close(carchreader *ai); int archreader_incvolume(carchreader *ai, bool waitkeypress); int archreader_volpath(carchreader *ai); int archreader_read_data(carchreader *ai, void *data, u64 size); int archreader_read_dico(carchreader *ai, struct s_dico *d); int archreader_read_volheader(carchreader *ai); int archreader_read_header(carchreader *ai, char *magic, struct s_dico **d, bool allowseek, u16 *fsid); int archreader_read_block(carchreader *ai, struct s_dico *in_blkdico, int in_skipblock, int *out_sumok, struct s_blockinfo *out_blkinfo); #endif // __ARCHREADER_H__ fsarchiver-0.8.5/src/oper_restore.c0000644000176100017610000017254513242767463014304 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "fsarchiver.h" #include "strdico.h" #include "dico.h" #include "common.h" #include "options.h" #include "oper_restore.h" #include "archreader.h" #include "archinfo.h" #include "filesys.h" #include "fs_ext2.h" #include "fs_reiserfs.h" #include "fs_reiser4.h" #include "fs_btrfs.h" #include "fs_xfs.h" #include "fs_jfs.h" #include "fs_ntfs.h" #include "thread_comp.h" #include "thread_archio.h" #include "syncthread.h" #include "regmulti.h" #include "crypto.h" #include "error.h" #include "datafile.h" #include "queue.h" typedef struct s_extractar { carchreader ai; int fsid; cstats stats; u64 cost_global; u64 cost_current; } cextractar; // returns true if this file of a parent directory has been excluded int is_filedir_excluded(char *relpath) { char dirpath[PATH_MAX]; char basename[PATH_MAX]; int pos; // check if that particular file has been excluded extract_basename(relpath, basename, sizeof(basename)); if ((exclude_check(&g_options.exclude, basename)==true) // is filename excluded ? || (exclude_check(&g_options.exclude, relpath)==true)) // is filepath excluded ? { msgprintf(MSG_VERB2, "file/dir=[%s] excluded because of its own name/path\n", relpath); return true; } // check if that file belongs to a directory which has been excluded snprintf(dirpath, sizeof(dirpath), "%s", relpath); for (pos=0; dirpath[pos]; pos++); // go to the end of the string while (pos>0) { // dirpath=parent_directory(dirpath) while ((pos>=0) && (dirpath[pos]!='/')) dirpath[pos--]=0; if ((pos>0) && (dirpath[pos]=='/')) dirpath[pos]=0; extract_basename(dirpath, basename, sizeof(basename)); if (strlen(dirpath)>1 && strlen(basename)>0) { if ((exclude_check(&g_options.exclude, basename)==true) || (exclude_check(&g_options.exclude, dirpath)==true)) { msgprintf(MSG_VERB2, "file/dir=[%s] excluded because of its parent=[%s]\n", relpath, dirpath); return true; // a parent directory is excluded } } } return false; // no exclusion found for that file } // convert an array of strings "id=x,dest=/dev/xxx,..." to an array of strdico int convert_argv_to_strdicos(cstrdico *dicoargv[], int argc, char *cmdargv[]) { cstrdico *tmpdico=NULL; char buffer[1024]; struct stat64 st; s64 temp64; int fsid; int i; for (i=0; (iFSA_MAX_FSPERARCH-1)) { errprintf("invalid filesystem id [%d]: it must match a valid filesystem id as shown by archinfo\n", fsid); strdico_destroy(tmpdico); return -1; } // read and check "dest=" key in the argument if (strdico_get_string(tmpdico, buffer, sizeof(buffer), "dest")!=0) { errprintf("cannot find \"dest=\" key in \"%s\"\n", cmdargv[i]); strdico_destroy(tmpdico); return -1; } if ((stat64(buffer, &st)!=0) || (!S_ISBLK(st.st_mode))) { errprintf("\"%s\" is not a valid block device\n", buffer); strdico_destroy(tmpdico); return -1; } // add the current argument to the list of the strdico objects if (dicoargv[fsid]!=NULL) { errprintf("you mentioned filesystem with id=%d multiple times, cannot continue\n", fsid); strdico_destroy(tmpdico); return -1; } dicoargv[fsid]=tmpdico; } return 0; } int extractar_listing_print_file(cextractar *exar, int objtype, char *relpath) { char strprogress[256]; s64 progress; memset(strprogress, 0, sizeof(strprogress)); if (exar->cost_global>0) { progress=(((exar->cost_current)*100)/(exar->cost_global)); if (progress>=0 && progress<=100) snprintf(strprogress, sizeof(strprogress), "[%3d%%]", (int)progress); } msgprintf(MSG_VERB1, "-[%.2d]%s[%s] %s\n", exar->fsid, strprogress, get_objtype_name(objtype), relpath); return 0; } int extractar_restore_attr_xattr(cextractar *exar, u32 objtype, char *fullpath, char *relpath, cdico *dicoattr) { char xattrname[2048]; char xattrvalue[65535]; u16 xattrdatasize; int xattrdicsize; int ret=0; int res; int i; // ---- restore extended attributes xattrdicsize=dico_count_one_section(dicoattr, DICO_OBJ_SECTION_XATTR); for (i=0; i < xattrdicsize; i+=2) { if (dico_get_string(dicoattr, DICO_OBJ_SECTION_XATTR, (u64)(i+0), xattrname, sizeof(xattrname))!=0) { errprintf("Cannot retrieve the name of an xattr for file %s: DICO_OBJ_SECTION_XATTR, key=%ld\n", relpath, (long)(i+0)); dico_show(dicoattr, DICO_OBJ_SECTION_XATTR, "xattr"); ret=-1; continue; } memset(xattrvalue, 0, sizeof(xattrvalue)); if (dico_get_data(dicoattr, DICO_OBJ_SECTION_XATTR, (u64)(i+1), xattrvalue, sizeof(xattrvalue), &xattrdatasize)!=0) { errprintf("Cannot retrieve the value of an xattr for file %s: DICO_OBJ_SECTION_XATTR, key=%ld\n", relpath, (long)(i+1)); dico_show(dicoattr, DICO_OBJ_SECTION_XATTR, "xattr"); ret=-1; continue; } if ((res=lsetxattr(fullpath, xattrname, xattrvalue, xattrdatasize, 0))!=0) { sysprintf("xattr:lsetxattr(%s,%s) failed\n", relpath, xattrname); ret=-1; } else // success { msgprintf(MSG_VERB2, " xattr:lsetxattr(%s, %s)=%d\n", relpath, xattrname, res); } } return ret; } int extractar_restore_attr_windows(cextractar *exar, u32 objtype, char *fullpath, char *relpath, cdico *dicoattr) { char xattrname[2048]; char xattrvalue[65535]; u16 xattrdatasize; int xattrdicsize; int ret=0; int res; int i; xattrdicsize=dico_count_one_section(dicoattr, DICO_OBJ_SECTION_WINATTR); for (i=0; i < xattrdicsize; i+=2) { if (dico_get_string(dicoattr, DICO_OBJ_SECTION_WINATTR, (u64)(i+0), xattrname, sizeof(xattrname))!=0) { errprintf("Cannot retrieve the name of an winattr for file %s\n", relpath); dico_show(dicoattr, DICO_OBJ_SECTION_WINATTR, "winattr"); ret=-1; continue; } memset(xattrvalue, 0, sizeof(xattrvalue)); if (dico_get_data(dicoattr, DICO_OBJ_SECTION_WINATTR, (u64)(i+1), xattrvalue, sizeof(xattrvalue), &xattrdatasize)!=0) { errprintf("Cannot retrieve the value of an winattr for file %s\n", relpath); ret=-1; continue; } if ((res=lsetxattr(fullpath, xattrname, xattrvalue, xattrdatasize, 0))!=0) { sysprintf("winattr:lsetxattr(%s,%s) failed\n", relpath, xattrname); ret=-1; } else // success { msgprintf(MSG_VERB2, " winattr:lsetxattr(%s, %s)=%d\n", relpath, xattrname, res); } } return ret; } int extractar_restore_attr_std(cextractar *exar, u32 objtype, char *fullpath, char *relpath, cdico *dicoattr) { u32 mode, uid, gid; u64 atime, mtime; // ---- restore standard attributes (permissions, owner, ...) if (dico_get_u32(dicoattr, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_MODE, &mode)!=0) return -1; if (dico_get_u32(dicoattr, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_UID, &uid)!=0) return -2; if (dico_get_u32(dicoattr, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_GID, &gid)!=0) return -3; if (dico_get_u64(dicoattr, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_ATIME, &atime)!=0) return -4; if (dico_get_u64(dicoattr, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_MTIME, &mtime)!=0) return -5; if (lchown(fullpath, (uid_t)uid, (gid_t)gid)!=0) { sysprintf("Cannot lchown(%s) which is %s\n", fullpath, get_objtype_name(objtype)); return -6; } if (objtype!=OBJTYPE_SYMLINK) { if (chmod(fullpath, (mode_t)mode)!=0) { sysprintf("chmod(%s, %lld) failed\n", fullpath, (long long)mode); return -7; } } // set the values for atime/mtime struct timeval tv[2]; tv[0].tv_usec=0; tv[0].tv_sec=atime; tv[1].tv_usec=0; tv[1].tv_sec=mtime; if (objtype!=OBJTYPE_SYMLINK) // not a symlink { if (utimes(fullpath, tv)!=0) { sysprintf("utimes(%s) failed\n", relpath); return -8; } } #ifdef HAVE_LUTIMES else // object is a symlink { // lutimes not implemented on rhel5: don't fail for symlinks lutimes(fullpath, tv); } #endif // HAVE_LUTIMES return 0; } int extractar_restore_attr_everything(cextractar *exar, int objtype, char *fullpath, char *relpath, cdico *dicoattr) { int res=0; // ---- restore standard attributes res+=extractar_restore_attr_std(exar, objtype, fullpath, relpath, dicoattr); // ---- restore extended attributes res+=extractar_restore_attr_xattr(exar, objtype, fullpath, relpath, dicoattr); // ---- restore windows attributes res+=extractar_restore_attr_windows(exar, objtype, fullpath, relpath, dicoattr); return (res==0)?(0):(-1); } int extractar_restore_obj_symlink(cextractar *exar, char *fullpath, char *relpath, char *destdir, cdico *d, int objtype, int fstype) { char parentdir[PATH_MAX]; struct timeval tv[2]; char buffer[PATH_MAX]; u64 targettype; int fdtemp; // update cost statistics and progress bar exar->cost_current+=FSA_COST_PER_FILE; // check the list of excluded files/dirs if (is_filedir_excluded(relpath)==true) goto extractar_restore_obj_symlink_err; // update progress bar extractar_listing_print_file(exar, objtype, relpath); // create parent directory first extract_dirpath(fullpath, parentdir, sizeof(parentdir)); mkdir_recursive(parentdir); // backup parent dir atime/mtime get_parent_dir_time_attrib(fullpath, parentdir, sizeof(parentdir), tv); if (dico_get_string(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_SYMLINK, buffer, PATH_MAX)<0) { errprintf("Cannot read field=symlink for file=[%s]\n", fullpath); goto extractar_restore_obj_symlink_err; } // in ntfs a symlink has to be recreated as a standard file or directory (depending on what the target is) if ((dico_get_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_LINKTARGETTYPE, &targettype)==0) && (strcmp(filesys[fstype].name, "ntfs")==0)) { switch (targettype) { case OBJTYPE_DIR: msgprintf(MSG_DEBUG1, "LINK: mklink=[%s], target=[%s], targettype=DIR\n", relpath, buffer); if (mkdir_recursive(fullpath)!=0) { errprintf("Cannot create directory for ntfs symlink: path=[%s]\n", fullpath); goto extractar_restore_obj_symlink_err; } break; case OBJTYPE_REGFILEUNIQUE: msgprintf(MSG_DEBUG1, "LINK: mklink=[%s], target=[%s], targettype=REGFILE\n", relpath, buffer); if ( (fdtemp=creat(fullpath, 0644)) < 0) { errprintf("Cannot create file for ntfs symlink: path=[%s]\n", fullpath); goto extractar_restore_obj_symlink_err; } close(fdtemp); break; default: msgprintf(MSG_DEBUG1, "LINK: mklink=[%s], target=[%s], targettype=UNKNOWN\n", relpath, buffer); errprintf("Unexpected target type for ntfs symlink: path=[%s]\n", fullpath); goto extractar_restore_obj_symlink_err; break; } } else // normal symbolic link for linux filesystems { msgprintf(MSG_DEBUG1, "LINK: symlink=[%s], target=[%s] (normal symlink)\n", relpath, buffer); if (symlink(buffer, fullpath)<0) { sysprintf("symlink(%s, %s) failed\n", buffer, fullpath); goto extractar_restore_obj_symlink_err; } } if (extractar_restore_attr_everything(exar, objtype, fullpath, relpath, d)!=0) { msgprintf(MSG_STACK, "cannot restore file attributes for file [%s]\n", relpath); goto extractar_restore_obj_symlink_err; } // restore parent dir mtime/atime if (utimes(parentdir, tv)!=0) { sysprintf("utimes(%s) failed\n", parentdir); goto extractar_restore_obj_symlink_err; } dico_destroy(d); exar->stats.cnt_symlink++; return 0; // success extractar_restore_obj_symlink_err: dico_destroy(d); exar->stats.err_symlink++; return 0; // non fatal error } int extractar_restore_obj_hardlink(cextractar *exar, char *fullpath, char *relpath, char *destdir, cdico *d, int objtype, int fstype) { char parentdir[PATH_MAX]; struct timeval tv[2]; char buffer[PATH_MAX]; char regfile[PATH_MAX]; int res; // update cost statistics and progress bar exar->cost_current+=FSA_COST_PER_FILE; // check the list of excluded files/dirs if (is_filedir_excluded(relpath)==true) goto extractar_restore_obj_hardlink_err; // create parent directory first extract_dirpath(fullpath, parentdir, sizeof(parentdir)); mkdir_recursive(parentdir); // backup parent dir atime/mtime get_parent_dir_time_attrib(fullpath, parentdir, sizeof(parentdir), tv); // update progress bar extractar_listing_print_file(exar, objtype, relpath); if (dico_get_string(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_HARDLINK, buffer, PATH_MAX)<0) { msgprintf(MSG_STACK, "dico_get_string(DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_HARDLINK) failed\n"); goto extractar_restore_obj_hardlink_err; } concatenate_paths(regfile, PATH_MAX, destdir, buffer); if ((res=link(regfile, fullpath))!=0) { sysprintf("link(%s, %s) failed\n", regfile, fullpath); goto extractar_restore_obj_hardlink_err; } if (extractar_restore_attr_everything(exar, objtype, fullpath, relpath, d)!=0) { msgprintf(MSG_STACK, "cannot restore file attributes for file [%s]\n", relpath); goto extractar_restore_obj_hardlink_err; } // restore parent dir mtime/atime if (utimes(parentdir, tv)!=0) { sysprintf("utimes(%s) failed\n", parentdir); goto extractar_restore_obj_hardlink_err; } dico_destroy(d); exar->stats.cnt_hardlink++; return 0; // success extractar_restore_obj_hardlink_err: dico_destroy(d); exar->stats.err_hardlink++; return 0; // non fatal error } int extractar_restore_obj_devfile(cextractar *exar, char *fullpath, char *relpath, char *destdir, cdico *d, int objtype, int fstype) { char parentdir[PATH_MAX]; struct timeval tv[2]; u64 dev; u32 mode; // update cost statistics and progress bar exar->cost_current+=FSA_COST_PER_FILE; // check the list of excluded files/dirs if (is_filedir_excluded(relpath)==true) goto extractar_restore_obj_devfile_err; // create parent directory first extract_dirpath(fullpath, parentdir, sizeof(parentdir)); mkdir_recursive(parentdir); // backup parent dir atime/mtime get_parent_dir_time_attrib(fullpath, parentdir, sizeof(parentdir), tv); // update progress bar extractar_listing_print_file(exar, objtype, relpath); if (dico_get_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_RDEV, &dev)!=0) goto extractar_restore_obj_devfile_err; if (dico_get_u32(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_MODE, &mode)!=0) goto extractar_restore_obj_devfile_err; if (mknod(fullpath, mode, dev)!=0) { sysprintf("mknod failed on [%s]\n", relpath); goto extractar_restore_obj_devfile_err; } if (extractar_restore_attr_everything(exar, objtype, fullpath, relpath, d)!=0) { msgprintf(MSG_STACK, "cannot restore file attributes for file [%s]\n", relpath); goto extractar_restore_obj_devfile_err; } // restore parent dir mtime/atime if (utimes(parentdir, tv)!=0) { sysprintf("utimes(%s) failed\n", parentdir); goto extractar_restore_obj_devfile_err; } dico_destroy(d); exar->stats.cnt_special++; return 0; // success extractar_restore_obj_devfile_err: dico_destroy(d); exar->stats.err_special++; return 0; // non fatal error } int extractar_restore_obj_directory(cextractar *exar, char *fullpath, char *relpath, char *destdir, cdico *d, int objtype, int fstype) { char parentdir[PATH_MAX]; struct timeval tv[2]; // update cost statistics and progress bar exar->cost_current+=FSA_COST_PER_FILE; // check the list of excluded files/dirs if (is_filedir_excluded(relpath)==true) goto extractar_restore_obj_directory_err; // create parent directory first extract_dirpath(fullpath, parentdir, sizeof(parentdir)); mkdir_recursive(parentdir); // backup parent dir atime/mtime get_parent_dir_time_attrib(fullpath, parentdir, sizeof(parentdir), tv); // update progress bar extractar_listing_print_file(exar, objtype, relpath); mkdir_recursive(fullpath); if (extractar_restore_attr_everything(exar, objtype, fullpath, relpath, d)!=0) { msgprintf(MSG_STACK, "cannot restore file attributes for file [%s]\n", relpath); goto extractar_restore_obj_directory_err; } // restore parent dir mtime/atime if (utimes(parentdir, tv)!=0) { sysprintf("utimes(%s) failed\n", parentdir); goto extractar_restore_obj_directory_err; } dico_destroy(d); exar->stats.cnt_dir++; return 0; // success extractar_restore_obj_directory_err: dico_destroy(d); exar->stats.err_dir++; return 0; // non fatal error } int extractar_restore_obj_regfile_multi(cextractar *exar, char *destdir, cdico *dicofirstfile, int objtype, int fstype) // d = obj-header of first small file { cdatafile *datafile=NULL; char databuf[FSA_MAX_SMALLFILESIZE]; char basename[PATH_MAX]; cdico *filehead=NULL; char magic[FSA_SIZEOF_MAGIC+1]; char fullpath[PATH_MAX]; char relpath[PATH_MAX]; char parentdir[PATH_MAX]; struct timeval tv[2]; struct s_blockinfo blkinfo; cregmulti regmulti; u8 md5sumcalc[16]; u8 md5sumorig[16]; int errors; u32 filescount; u32 tmpobjtype; u64 datsize; s64 lres; int res; int i; // init errors=0; memset(&blkinfo, 0, sizeof(blkinfo)); regmulti_init(®multi, FSA_MAX_BLKSIZE); datafile=datafile_alloc(); // ---- dequeue header for each small file which is part of that group if (dico_get_u32(dicofirstfile, 0, DISKITEMKEY_MULTIFILESCOUNT, &filescount)!=0) { errprintf("cannot read DISKITEMKEY_MULTIFILESCOUNT from header in archive\n"); return -1; } if (regmulti_rest_addheader(®multi, dicofirstfile)!=0) { errprintf("rest_addheader() failed\n"); return -1; } for (i=1; i < filescount; i++) // first header was a special case (received from calling function) { if (queue_dequeue_header(&g_queue, &filehead, magic, NULL)<=0) { errprintf("queue_dequeue_header() failed: cannot read multireg object header\n"); errors++; return -1; } if (memcmp(magic, FSA_MAGIC_OBJT, FSA_SIZEOF_MAGIC)!=0) { errprintf("header is not what we expected: found=[%s] and expected=[%s]\n", magic, FSA_MAGIC_OBJT); return -1; } if (regmulti_rest_addheader(®multi, filehead)!=0) { errprintf("rest_addheader() failed for file %d\n", i); return -1; } } // ---- dequeue the block which contains data for several small files if ((lres=queue_dequeue_block(&g_queue, &blkinfo))<=0) { errprintf("queue_dequeue_block()=%ld=%s failed\n", (long)lres, error_int_to_string(lres)); return -1; } if (regmulti_rest_setdatablock(®multi, blkinfo.blkdata, blkinfo.blkrealsize)!=0) { errprintf("regmulti_rest_setdatablock() failed\n"); return -1; } free(blkinfo.blkdata); // free memory allocated by the thread_io_reader // ---- create the set of small files using the regmulti structure for (i=0; i < filescount; i++) { // get header and data for a small file from the regmulti structure if (regmulti_rest_getfile(®multi, i, &filehead, databuf, &datsize, sizeof(databuf))!=0) { errprintf("rest_addheader() failed for file %d\n", i); filehead=NULL; // else dico_destroy would fail goto extractar_restore_obj_regfile_multi_err; } if (dico_get_u32(filehead, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_OBJTYPE, &tmpobjtype)!=0) { errprintf("Cannot read object type\n"); goto extractar_restore_obj_regfile_multi_err; } if ((res=dico_get_data(filehead, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_PATH, relpath, sizeof(relpath), NULL))!=0) { errprintf("Cannot read DISKITEMKEY_PATH from header, res=%d, key=%d\n", res, DISKITEMKEY_PATH); dico_show(filehead, DICO_OBJ_SECTION_STDATTR, "DISKITEMKEY_PATH"); goto extractar_restore_obj_regfile_multi_err; } concatenate_paths(fullpath, sizeof(fullpath), destdir, relpath); extract_basename(fullpath, basename, sizeof(basename)); // update cost statistics and progress bar exar->cost_current+=FSA_COST_PER_FILE; exar->cost_current+=datsize; // filesize // check the list of excluded files/dirs if (is_filedir_excluded(relpath)!=true) { // create parent directory if necessary extract_dirpath(fullpath, parentdir, sizeof(parentdir)); mkdir_recursive(parentdir); // backup parent dir atime/mtime get_parent_dir_time_attrib(fullpath, parentdir, sizeof(parentdir), tv); extractar_listing_print_file(exar, tmpobjtype, relpath); if (dico_get_data(filehead, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_MD5SUM, md5sumorig, 16, NULL)) { errprintf("cannot get md5sum from file footer for file=[%s]\n", relpath); dico_show(filehead, DICO_OBJ_SECTION_STDATTR, "filehead"); goto extractar_restore_obj_regfile_multi_err; } if (datafile_open_write(datafile, fullpath, false, false)<0) goto extractar_restore_obj_regfile_multi_err; res=datafile_write(datafile, databuf, datsize); datafile_close(datafile, md5sumcalc, sizeof(md5sumcalc)); if (res!=FSAERR_SUCCESS) { errprintf("removing %s\n", fullpath); unlink(fullpath); return -1; } if (memcmp(md5sumcalc, md5sumorig, 16)!=0) { errprintf("cannot restore file %s, the data block (which is shared by multiple files) is corrupt\n", relpath); res=truncate(fullpath, 0); // don't leave corrupt data in the file goto extractar_restore_obj_regfile_multi_err; } if (extractar_restore_attr_everything(exar, objtype, fullpath, relpath, filehead)!=0) { msgprintf(MSG_STACK, "cannot restore file attributes for file [%s]\n", relpath); goto extractar_restore_obj_regfile_multi_err; } // restore parent dir mtime/atime if (utimes(parentdir, tv)!=0) { sysprintf("utimes(%s) failed\n", parentdir); goto extractar_restore_obj_regfile_multi_err; } exar->stats.cnt_regfile++; } dico_destroy(filehead); continue; // success on that file extractar_restore_obj_regfile_multi_err: dico_destroy(filehead); exar->stats.err_regfile++; continue; } datafile_destroy(datafile); return 0; } int extractar_restore_obj_regfile_unique(cextractar *exar, char *fullpath, char *relpath, char *destdir, cdico *d, int objtype, int fstype) // large or empty files { char magic[FSA_SIZEOF_MAGIC+1]; struct s_blockinfo blkinfo; char parentdir[PATH_MAX]; cdatafile *datafile=NULL; cdico *footerdico=NULL; bool fatalerr=false; // error for restoration globally bool minorerr=false; // error for current file only bool delfile=false; struct timeval tv[2]; u8 md5sumcalc[16]; u8 md5sumorig[16]; int excluded=false; bool sparse=false; u64 filesize=0; u64 filepos=0; u64 flags=0; s64 lres; // init memset(&blkinfo, 0, sizeof(blkinfo)); memset(magic, 0, sizeof(magic)); datafile=datafile_alloc(); if (dico_get_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_SIZE, &filesize)!=0) { errprintf("Cannot read filesize DISKITEMKEY_SIZE from archive for file=[%s]\n", relpath); minorerr=true; } sparse=((dico_get_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_FLAGS, &flags)==0) && (flags&FSA_FILEFLAGS_SPARSE)); // update cost statistics and progress bar exar->cost_current+=FSA_COST_PER_FILE; exar->cost_current+=filesize; // check the list of excluded files/dirs if (is_filedir_excluded(relpath)==true) { excluded=true; } else if (minorerr==false) // file not excluded and no error yet { // create parent directory first extract_dirpath(fullpath, parentdir, sizeof(parentdir)); mkdir_recursive(parentdir); // backup parent dir atime/mtime get_parent_dir_time_attrib(fullpath, parentdir, sizeof(parentdir), tv); // show progress bar extractar_listing_print_file(exar, objtype, relpath); } if ((minorerr==false) && (datafile_open_write(datafile, fullpath, excluded, sparse)<0)) minorerr=true; msgprintf(MSG_DEBUG2, "restore_obj_regfile_unique(file=%s, size=%lld)\n", relpath, (long long)filesize); for (filepos=0; (minorerr==false) && (filesize>0) && (filepos < filesize) && (get_interrupted()==false); filepos+=blkinfo.blkrealsize) { if ((lres=queue_dequeue_block(&g_queue, &blkinfo))<=0) { errprintf("queue_dequeue_block()=%ld=%s for file(%s) failed\n", (long)lres, error_int_to_string(lres), relpath); delfile=true; minorerr=true; break; } if (blkinfo.blkoffset!=filepos) { errprintf("file offset do not match for file(%s) failed: filepos=%lld, blkinfo.blkoffset=%lld, blkinfo.blkrealsize=%lld\n", relpath, (long long)filepos, (long long)blkinfo.blkoffset, (long long)blkinfo.blkrealsize); free(blkinfo.blkdata); delfile=true; minorerr=true; break; } if (datafile_write(datafile, blkinfo.blkdata, blkinfo.blkrealsize)!=FSAERR_SUCCESS) { free(blkinfo.blkdata); delfile=true; minorerr=true; fatalerr=true; break; } free(blkinfo.blkdata); } if ((minorerr==false) && (datafile_close(datafile, md5sumcalc, sizeof(md5sumcalc))!=0)) minorerr=true; if ((minorerr==false) && (excluded==false)) { if (extractar_restore_attr_everything(exar, objtype, fullpath, relpath, d)!=0) { msgprintf(MSG_STACK, "cannot restore file attributes for file [%s]\n", relpath); minorerr=true; } // restore parent dir mtime/atime if (utimes(parentdir, tv)!=0) { sysprintf("utimes(%s) failed\n", parentdir); minorerr=true; } } // empty files have no footer (no need for a checksum) if ((fatalerr==false) && (filesize>0)) { if (queue_dequeue_header(&g_queue, &footerdico, magic, NULL)<=0) { errprintf("queue_dequeue_header() failed: cannot read footer dico\n"); minorerr=true; goto restore_obj_regfile_unique_end; } if (excluded!=true) { if (memcmp(magic, FSA_MAGIC_FILF, FSA_SIZEOF_MAGIC)!=0) { errprintf("header is not what we expected: found=[%s] and expected=[%s]\n", magic, FSA_MAGIC_FILF); minorerr=true; goto restore_obj_regfile_unique_end; } if (dico_get_data(footerdico, 0, BLOCKFOOTITEMKEY_MD5SUM, md5sumorig, 16, NULL)) { errprintf("cannot get md5sum from file footer for file=[%s]\n", relpath); minorerr=true; goto restore_obj_regfile_unique_end; } if (memcmp(md5sumcalc, md5sumorig, 16)!=0) { errprintf("cannot restore file %s, file is corrupt\n", relpath); delfile=true; // don't leave corrupt data in the file minorerr=true; goto restore_obj_regfile_unique_end; } } } restore_obj_regfile_unique_end: if (delfile==true) { errprintf("removing %s\n", fullpath); unlink(fullpath); } if (excluded!=true) { if (minorerr==true) exar->stats.err_regfile++; else exar->stats.cnt_regfile++; } if (get_interrupted()==true) errprintf("operation has been interrupted\n"); dico_destroy(footerdico); dico_destroy(d); datafile_destroy(datafile); return (fatalerr==false)?(0):(-1); } int extractar_restore_object(cextractar *exar, int *errors, char *destdir, cdico *dicoattr, int fstype) { char relpath[PATH_MAX]; char fullpath[PATH_MAX]; u64 filesize; u32 objtype; int res; // init *errors=0; if (dico_get_data(dicoattr, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_PATH, relpath, sizeof(relpath), NULL)!=0) return -1; if (dico_get_u32(dicoattr, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_OBJTYPE, &objtype)!=0) return -2; if (dico_get_u64(dicoattr, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_SIZE, &filesize)!=0) return -3; concatenate_paths(fullpath, sizeof(fullpath), destdir, relpath); // ---- recreate specific object on the filesystem switch (objtype) { case OBJTYPE_DIR: msgprintf(MSG_DEBUG2, "objtype=OBJTYPE_DIR, path=[%s]\n", relpath); res=extractar_restore_obj_directory(exar, fullpath, relpath, destdir, dicoattr, objtype, fstype); break; case OBJTYPE_SYMLINK: msgprintf(MSG_DEBUG2, "objtype=OBJTYPE_SYMLINK, path=[%s]\n", relpath); res=extractar_restore_obj_symlink(exar, fullpath, relpath, destdir, dicoattr, objtype, fstype); break; case OBJTYPE_HARDLINK: msgprintf(MSG_DEBUG2, "objtype=OBJTYPE_HARDLINK, path=[%s]\n", relpath); res=extractar_restore_obj_hardlink(exar, fullpath, relpath, destdir, dicoattr, objtype, fstype); break; case OBJTYPE_CHARDEV: msgprintf(MSG_DEBUG2, "objtype=OBJTYPE_CHARDEV, path=[%s]\n", relpath); res=extractar_restore_obj_devfile(exar, fullpath, relpath, destdir, dicoattr, objtype, fstype); break; case OBJTYPE_BLOCKDEV: msgprintf(MSG_DEBUG2, "objtype=OBJTYPE_BLOCKDEV, path=[%s]\n", relpath); res=extractar_restore_obj_devfile(exar, fullpath, relpath, destdir, dicoattr, objtype, fstype); break; case OBJTYPE_FIFO: msgprintf(MSG_DEBUG2, "objtype=OBJTYPE_FIFO, path=[%s]\n", relpath); res=extractar_restore_obj_devfile(exar, fullpath, relpath, destdir, dicoattr, objtype, fstype); break; case OBJTYPE_SOCKET: msgprintf(MSG_DEBUG2, "objtype=OBJTYPE_SOCKET, path=[%s]\n", relpath); res=extractar_restore_obj_devfile(exar, fullpath, relpath, destdir, dicoattr, objtype, fstype); break; case OBJTYPE_REGFILEUNIQUE: msgprintf(MSG_DEBUG2, "objtype=OBJTYPE_REGFILEUNIQUE, path=[%s]\n", relpath); if ((res=extractar_restore_obj_regfile_unique(exar, fullpath, relpath, destdir, dicoattr, objtype, fstype))<0) { msgprintf(MSG_STACK, "restore_obj_regfile_unique(%s) failed with res=%d\n", relpath, res); return -1; } break; case OBJTYPE_REGFILEMULTI: msgprintf(MSG_DEBUG2, "objtype=OBJTYPE_REGFILEMULTI, path=[%s]\n", relpath); if ((res=extractar_restore_obj_regfile_multi(exar, destdir, dicoattr, objtype, fstype))<0) { msgprintf(MSG_STACK, "restore_obj_regfile_multi(%s) failed with res=%d\n", relpath, res); return -1; } break; default: errprintf("Unknown objtype %d\n", objtype); return -3; } if (res!=0) // value returned by restore_obj_xxx() { errprintf("Restoring file=[%s], objtype=[%s] failed\n", fullpath, get_objtype_name(objtype)); return -1; } return 0; } int extractar_extract_read_objects(cextractar *exar, int *errors, char *destdir, int fstype) { char magic[FSA_SIZEOF_MAGIC+1]; cdico *dicoattr=NULL; int headerisend; int headerisobj; u16 checkfsid; int curerr; int type; int res; // init memset(magic, 0, sizeof(magic)); *errors=0; do { // skip the garbage (just ignore everything until the next FSA_MAGIC_OBJT) // in case the archive is corrupt and random data has been added / removed in the archive do { if (queue_check_next_item(&g_queue, &type, magic)!=0) { errprintf("queue_check_next_item() failed: cannot read object from archive\n"); return -1; } headerisobj=(memcmp(magic, FSA_MAGIC_OBJT, FSA_SIZEOF_MAGIC)==0); headerisend=(memcmp(magic, FSA_MAGIC_DATF, FSA_SIZEOF_MAGIC)==0); if (headerisobj!=true && headerisend!=true) // did not find expected header: skip garbage in archive { errprintf("unexpected header found in archive, skipping it: type=%d, magic=[%s]\n", type, (type==QITEM_TYPE_HEADER)?(magic):"-block-"); if (queue_destroy_first_item(&g_queue)!=0) { errprintf("queue_destroy_first_item() failed: cannot read object from archive\n"); return -1; } } } while ((headerisobj!=true) && (headerisend!=true)); if (headerisobj==true) // if it's an object header { // read object header from archive while (queue_dequeue_header(&g_queue, &dicoattr, magic, &checkfsid)<=0) { errprintf("queue_dequeue_header() failed\n"); (*errors)++; } if (checkfsid==exar->fsid) // if filesystem-id is correct { if ((res=extractar_restore_object(exar, &curerr, destdir, dicoattr, fstype))!=0) { msgprintf(MSG_STACK, "restore_object() failed with res=%d\n", res); //dico_destroy(dicoattr); return -1; // fatal error } } else // wrong filesystem-id { errprintf("restore_object(): object has a wrong filesystem id: found=[%d], expected=[%d]\n", checkfsid, exar->fsid); (*errors)++; } //dico_destroy(dicoattr); } } while ((headerisend!=true) && (get_abort()==false)); return 0; } int extractar_read_mainhead(cextractar *exar, cdico **dicomainhead) { u8 bufcheckclear[FSA_CHECKPASSBUF_SIZE+8]; u8 bufcheckcrypt[FSA_CHECKPASSBUF_SIZE+8]; char magic[FSA_SIZEOF_MAGIC+1]; u16 cryptbufsize; u8 md5sumar[16]; u8 md5sumnew[16]; u64 clearsize; int passlen; u32 temp32; assert(exar); assert(dicomainhead); // init memset(magic, 0, sizeof(magic)); if (queue_dequeue_header(&g_queue, dicomainhead, magic, NULL)<=0) { errprintf("queue_dequeue_header() failed: cannot read main header\n"); return -1; } if (memcmp(magic, FSA_MAGIC_MAIN, FSA_SIZEOF_MAGIC)!=0) { errprintf("header is not what we expected: found=[%s] and expected=[%s]\n", magic, FSA_MAGIC_MAIN); return -1; } if (dico_get_u32(*dicomainhead, 0, MAINHEADKEY_ARCHTYPE, &exar->ai.archtype)!=0) { errprintf("cannot find MAINHEADKEY_ARCHTYPE in main-header\n"); return -1; } if (exar->ai.archtype==ARCHTYPE_FILESYSTEMS && dico_get_u64(*dicomainhead, 0, MAINHEADKEY_FSCOUNT, &exar->ai.fscount)!=0) { errprintf("cannot find MAINHEADKEY_FSCOUNT in main-header\n"); return -1; } if (dico_get_u32(*dicomainhead, 0, MAINHEADKEY_ARCHIVEID, &exar->ai.archid)!=0) { errprintf("cannot find MAINHEADKEY_ARCHIVEID in main-header\n"); return -1; } if (dico_get_data(*dicomainhead, 0, MAINHEADKEY_FILEFORMATVER, exar->ai.filefmt, FSA_MAX_FILEFMTLEN, NULL)!=0) { errprintf("cannot find MAINHEADKEY_FILEFORMATVER in main-header\n"); return -1; } if (dico_get_data(*dicomainhead, 0, MAINHEADKEY_PROGVERCREAT, exar->ai.creatver, FSA_MAX_PROGVERLEN, NULL)!=0) { errprintf("cannot find MAINHEADKEY_PROGVERCREAT in main-header\n"); return -1; } if (dico_get_data(*dicomainhead, 0, MAINHEADKEY_ARCHLABEL, exar->ai.label, FSA_MAX_LABELLEN, NULL)!=0) { errprintf("cannot find MAINHEADKEY_ARCHLABEL in main-header\n"); return -1; } if (dico_get_u32(*dicomainhead, 0, MAINHEADKEY_COMPRESSALGO, &exar->ai.compalgo)!=0) { errprintf("cannot find MAINHEADKEY_COMPRESSALGO in main-header\n"); return -1; } if (dico_get_u32(*dicomainhead, 0, MAINHEADKEY_ENCRYPTALGO, &exar->ai.cryptalgo)!=0) { errprintf("cannot find MAINHEADKEY_ENCRYPTALGO in main-header\n"); return -1; } if (dico_get_u32(*dicomainhead, 0, MAINHEADKEY_COMPRESSLEVEL, &exar->ai.complevel)!=0) { errprintf("cannot find MAINHEADKEY_COMPRESSLEVEL in main-header\n"); return -1; } if (dico_get_u32(*dicomainhead, 0, MAINHEADKEY_FSACOMPLEVEL, &exar->ai.fsacomp)!=0) { errprintf("cannot find MAINHEADKEY_FSACOMPLEVEL in main-header\n"); return -1; } if (dico_get_u64(*dicomainhead, 0, MAINHEADKEY_CREATTIME, &exar->ai.creattime)!=0) { errprintf("cannot find MAINHEADKEY_CREATTIME in main-header\n"); return -1; } // MAINHEADKEY_HASDIRSINFOHEAD has been introduced in fsarchiver-0.6.7: don't fail if missing if (dico_get_u32(*dicomainhead, 0, MAINHEADKEY_HASDIRSINFOHEAD, &temp32)==0) exar->ai.hasdirsinfohead=temp32; // check the file format. New versions based on "FsArCh_002" also understand "FsArCh_001" which is very close (and "FsArCh_00Y"=="FsArCh_001") if (strcmp(exar->ai.filefmt, FSA_FILEFORMAT)!=0 && strcmp(exar->ai.filefmt, "FsArCh_00Y")!=0 && strcmp(exar->ai.filefmt, "FsArCh_001")!=0) { errprintf("This archive is based on a different file format: [%s]. Cannot continue.\n", exar->ai.filefmt); errprintf("It has been created with fsarchiver [%s], you should extrat the archive using that version.\n", exar->ai.creatver); errprintf("The current version of the program is [%s], and it's based on format [%s]\n", FSA_VERSION, FSA_FILEFORMAT); return -1; } // read minimum fsarchiver version requirement if (dico_get_u64(*dicomainhead, 0, MAINHEADKEY_MINFSAVERSION, &exar->ai.minfsaver)!=0) exar->ai.minfsaver=FSA_VERSION_BUILD(0, 0, 0, 0); // not defined // if encryption is enabled, check the password is correct using the encrypted random buffer saved in the archive if (exar->ai.cryptalgo!=ENCRYPT_NONE) { memset(md5sumar, 0, sizeof(md5sumar)); memset(md5sumnew, 0, sizeof(md5sumnew)); if (dico_get_data(*dicomainhead, 0, MAINHEADKEY_BUFCHECKPASSCRYPTBUF, bufcheckcrypt, sizeof(bufcheckcrypt), &cryptbufsize)!=0) { errprintf("cannot find MAINHEADKEY_BUFCHECKPASSCRYPTBUF in main-header\n"); return -1; } if (dico_get_data(*dicomainhead, 0, MAINHEADKEY_BUFCHECKPASSCLEARMD5, md5sumar, sizeof(md5sumar)+99, NULL)!=0) { errprintf("cannot find MAINHEADKEY_BUFCHECKPASSCLEARMD5 in main-header\n"); return -1; } passlen=(g_options.encryptpass==NULL)?(0):(strlen((char*)g_options.encryptpass)); if ((g_options.encryptpass==NULL) || (passlenFSA_MAX_PASSLEN)) { errprintf("you have to provide the password which was used to create archive, no password given on the command line\n"); return -1; } if (crypto_blowfish(cryptbufsize, &clearsize, bufcheckcrypt, bufcheckclear, g_options.encryptpass, strlen((char*)g_options.encryptpass), false)==0) gcry_md_hash_buffer(GCRY_MD_MD5, md5sumnew, bufcheckclear, clearsize); if (memcmp(md5sumar, md5sumnew, 16)!=0) { errprintf("you have to provide the password which was used to create archive, cannot decrypt the test buffer.\n"); return -1; } } return 0; } int extractar_filesystem_extract(cextractar *exar, cdico *dicofs, cstrdico *dicocmdline) { char filesystem[FSA_MAX_FSNAMELEN]; char text[FSA_MAX_FSNAMELEN]; char fsbuf[FSA_MAX_FSNAMELEN]; char magic[FSA_SIZEOF_MAGIC+1]; char mountinfo[4096]; char partition[1024]; char mkfsoptions[1024]; char mkfslabel[1024]; char mkfsuuid[1024]; char tempbuf[1024]; cdico *dicobegin=NULL; cdico *dicoend=NULL; char mntbuf[PATH_MAX]; u64 fsbytestotal; u64 fsbytesused; char optbuf[128]; int readwrite; int errors=0; u64 minver; u64 curver; int fstype; int ret=0; int res; // init memset(magic, 0, sizeof(magic)); memset(partition, 0, sizeof(partition)); memset(mkfslabel, 0, sizeof(mkfslabel)); memset(mkfsuuid, 0, sizeof(mkfsuuid)); // read destination partition from dicocmdline if (strdico_get_string(dicocmdline, partition, sizeof(partition), "dest")!=0) { errprintf("strdico_get_string(dicocmdline, 'dest') failed\n"); return -1; } // check that the minimum fsarchiver version required is ok if (dico_get_u64(dicofs, 0, FSYSHEADKEY_MINFSAVERSION, &minver)!=0) minver=FSA_VERSION_BUILD(0, 6, 4, 0); // fsarchiver-0.6.4 is the first fsa version having fileformat="FsArCh_002" curver=FSA_VERSION_BUILD(PACKAGE_VERSION_A, PACKAGE_VERSION_B, PACKAGE_VERSION_C, PACKAGE_VERSION_D); msgprintf(MSG_VERB2, "Current fsarchiver version: %d.%d.%d.%d\n", (int)FSA_VERSION_GET_A(curver), (int)FSA_VERSION_GET_B(curver), (int)FSA_VERSION_GET_C(curver), (int)FSA_VERSION_GET_D(curver)); msgprintf(MSG_VERB2, "Minimum fsarchiver version for that filesystem: %d.%d.%d.%d\n", (int)FSA_VERSION_GET_A(minver), (int)FSA_VERSION_GET_B(minver), (int)FSA_VERSION_GET_C(minver), (int)FSA_VERSION_GET_D(minver)); if (curver < minver) { errprintf("This filesystem can only be restored with fsarchiver %d.%d.%d.%d or more recent\n", (int)FSA_VERSION_GET_A(minver), (int)FSA_VERSION_GET_B(minver), (int)FSA_VERSION_GET_C(minver), (int)FSA_VERSION_GET_D(minver)); return -1; } // check the partition is not mounted res=generic_get_mntinfo(partition, &readwrite, mntbuf, sizeof(mntbuf), optbuf, sizeof(optbuf), fsbuf, sizeof(fsbuf)); if (res==0) { errprintf("partition [%s] is mounted on [%s].\ncannot restore an archive to a partition " "which is mounted, unmount it first: umount %s\n", partition, mntbuf, mntbuf); return -1; } // ---- read filesystem-header from archive if (queue_dequeue_header(&g_queue, &dicobegin, magic, NULL)<=0) { errprintf("queue_dequeue_header() failed: cannot read file system dico\n"); return -1; } dico_destroy(dicobegin); if (memcmp(magic, FSA_MAGIC_FSYB, FSA_SIZEOF_MAGIC)!=0) { errprintf("header is not what we expected: found=[%s] and expected=[%s]\n", magic, FSA_MAGIC_FSYB); return -1; } // if a filesystem to use was specified: overwrite the default one if (strdico_get_string(dicocmdline, tempbuf, sizeof(tempbuf), "mkfs")==0) { snprintf(filesystem, sizeof(filesystem), "%s", tempbuf); } else if ((dico_get_string(dicofs, 0, FSYSHEADKEY_FILESYSTEM, filesystem, sizeof(filesystem)))<0) { errprintf("dico_get_string(FSYSHEADKEY_FILESYSTEM) failed\n"); return -1; } // read make file system options from dicocmdline if (strdico_get_string(dicocmdline, mkfsoptions, sizeof(mkfsoptions), "mkfsopt")!=0) { msgprintf(MSG_VERB2,"strdico_get_string(dicocmdline, 'mkfsopt') doesn't exist\n"); } if (strdico_get_string(dicocmdline, mkfslabel, sizeof(mkfslabel), "label")!=0) { msgprintf(MSG_VERB2,"strdico_get_string(dicocmdline, 'label') doesn't exist\n"); } if (strdico_get_string(dicocmdline, mkfsuuid, sizeof(mkfsuuid), "uuid")!=0) { msgprintf(MSG_VERB2,"strdico_get_string(dicocmdline, 'uuid') doesn't exist\n"); } if (dico_get_u64(dicofs, 0, FSYSHEADKEY_BYTESTOTAL, &fsbytestotal)!=0) { errprintf("dico_get_string(FSYSHEADKEY_BYTESTOTAL) failed\n"); return -1; } if (dico_get_u64(dicofs, 0, FSYSHEADKEY_BYTESUSED, &fsbytesused)!=0) { errprintf("dico_get_string(FSYSHEADKEY_BYTESUSED) failed\n"); return -1; } msgprintf(MSG_VERB2, "filesystem_type=[%s]\n", filesystem); msgprintf(MSG_VERB2, "filesystem_mkfsoptions=[%s]\n", mkfsoptions); msgprintf(MSG_VERB2, "filesystem_mkfslabel=[%s]\n", mkfslabel); msgprintf(MSG_VERB2, "filesystem_mkfsuuid=[%s]\n", mkfsuuid); msgprintf(MSG_VERB2, "filesystem_space_total=[%s]\n", format_size(fsbytestotal, text, sizeof(text), 'h')); msgprintf(MSG_VERB2, "filesystem_space_used=[%s]\n", format_size(fsbytesused, text, sizeof(text), 'h')); // get index of the filesystem in the filesystem table if (generic_get_fstype(filesystem, &fstype)!=0) { errprintf("filesystem [%s] is not supported by fsarchiver\n", filesystem); return -1; } // ---- make the filesystem if (filesys[fstype].mkfs(dicofs, partition, mkfsoptions, mkfslabel, mkfsuuid)!=0) { errprintf("cannot make filesystem %s on partition %s\n", filesystem, partition); return -1; } // ---- mount the new filesystem mkdir_recursive(mntbuf); generate_random_tmpdir(mntbuf, sizeof(mntbuf), 0); mkdir_recursive(mntbuf); if ((dico_get_string(dicofs, 0, FSYSHEADKEY_MOUNTINFO, mountinfo, sizeof(mountinfo)))<0) memset(mountinfo, 0, sizeof(mountinfo)); msgprintf(MSG_VERB1, "Mount information: [%s]\n", mountinfo); if (filesys[fstype].mount(partition, mntbuf, filesys[fstype].name, 0, mountinfo)!=0) { errprintf("partition [%s] cannot be mounted on %s. cannot continue.\n", partition, mntbuf); return -1; } if (extractar_extract_read_objects(exar, &errors, mntbuf, fstype)!=0) { msgprintf(MSG_STACK, "extract_read_objects(%s) failed\n", mntbuf); ret=-1; goto filesystem_extract_umount; } else if (errors>0) { msgprintf(MSG_DEBUG1, "extract_read_objects(%s) worked with errors\n", mntbuf); ret=-1; goto filesystem_extract_umount; } // read "end of file-system" header from archive if (queue_dequeue_header(&g_queue, &dicoend, magic, NULL)<=0) { errprintf("queue_dequeue_header() failed\n"); ret=-1; goto filesystem_extract_umount; } dico_destroy(dicoend); if ((get_interrupted()==false) && (memcmp(magic, FSA_MAGIC_DATF, FSA_SIZEOF_MAGIC)!=0)) { errprintf("header is not what we expected: found=[%s] and expected=[%s]\n", magic, FSA_MAGIC_DATF); goto filesystem_extract_umount; } filesystem_extract_umount: if (filesys[fstype].umount(partition, mntbuf)!=0) { sysprintf("cannot umount %s\n", mntbuf); ret=-1; } else { rmdir(mntbuf); // remove temp dir created by fsarchiver } return ret; } int oper_restore(char *archive, int argc, char **argv, int oper) { cdico *dicofsinfo[FSA_MAX_FSPERARCH]; cstrdico *dicoargv[FSA_MAX_FSPERARCH]; pthread_t thread_decomp[FSA_MAX_COMPJOBS]; char magic[FSA_SIZEOF_MAGIC+1]; cdico *dicomainhead=NULL; cdico *dirsinfo=NULL; pthread_t thread_reader; struct stat64 st; char *destdir; cextractar exar; u64 totalerr=0; u64 fscost; u64 curver; int errors=0; int ret=0; int i; // init memset(&exar, 0, sizeof(exar)); exar.cost_global=0; exar.cost_current=0; archreader_init(&exar.ai); // init misc data struct to zero for (i=0; i 0) { msgprintf(MSG_VERB2, "Current fsarchiver version: %d.%d.%d.%d\n", (int)FSA_VERSION_GET_A(curver), (int)FSA_VERSION_GET_B(curver), (int)FSA_VERSION_GET_C(curver), (int)FSA_VERSION_GET_D(curver)); msgprintf(MSG_VERB2, "Minimum fsarchiver version for that archive: %d.%d.%d.%d\n", (int)FSA_VERSION_GET_A(exar.ai.minfsaver), (int)FSA_VERSION_GET_B(exar.ai.minfsaver), (int)FSA_VERSION_GET_C(exar.ai.minfsaver), (int)FSA_VERSION_GET_D(exar.ai.minfsaver)); } if (((oper==OPER_RESTFS) || (oper==OPER_RESTDIR)) && (curver < exar.ai.minfsaver)) { errprintf("This archive can only be restored with fsarchiver %d.%d.%d.%d or more recent\n", (int)FSA_VERSION_GET_A(exar.ai.minfsaver), (int)FSA_VERSION_GET_B(exar.ai.minfsaver), (int)FSA_VERSION_GET_C(exar.ai.minfsaver), (int)FSA_VERSION_GET_D(exar.ai.minfsaver)); goto do_extract_error; } // show archive information if command is OPER_ARCHINFO if (oper==OPER_ARCHINFO && archinfo_show_mainhead(&exar.ai, dicomainhead)!=0) { errprintf("archinfo_show_mainhead(%s) failed\n", archive); goto do_extract_error; } // check that the operation requested on the command line matches the archive type switch (exar.ai.archtype) { case ARCHTYPE_DIRECTORIES: if (oper==OPER_RESTFS) { errprintf("this archive does not contain filesystems, cannot use \"restfs\". Try \"restdir\" instead.\n"); goto do_extract_error; } break; case ARCHTYPE_FILESYSTEMS: if (oper==OPER_RESTDIR) { errprintf("this archive does not contain simple directories, cannot use \"restdir\". Try \"restfs\" instead.\n"); goto do_extract_error; } break; default: errprintf("this archive has an unknown type: %d, cannot continue\n", exar.ai.archtype); goto do_extract_error; } // check the user did not specify an invalid filesystem id (id >= fscount) for (i=0; (i= exar.ai.fscount)) { errprintf("invalid filesystem id: [%d]. the filesystem id must be an integer between 0 and %d\n", (int)i, (int)(exar.ai.fscount-1)); goto do_extract_error; } } // read the fsinfo header for each filesystem for (i=0; (exar.ai.archtype==ARCHTYPE_FILESYSTEMS) && (i < exar.ai.fscount) && (i= 0.6.7 // so that they don't have error when they try to restore an archive which has that header if ((exar.ai.archtype==ARCHTYPE_DIRECTORIES) && (exar.ai.hasdirsinfohead==true)) { if (queue_dequeue_header(&g_queue, &dirsinfo, magic, NULL)<=0) { errprintf("queue_dequeue_header() failed: cannot read the dirsinfo header\n"); goto do_extract_error; } if (memcmp(magic, FSA_MAGIC_DIRS, FSA_SIZEOF_MAGIC)!=0) { errprintf("header is not what we expected: found=[%s] and expected=[%s]\n", magic, FSA_MAGIC_DIRS); goto do_extract_error; } if ((dirsinfo!=NULL) && (dico_get_u64(dirsinfo, 0, DIRSINFOKEY_TOTALCOST, &exar.cost_global)!=0)) { errprintf("cannot read DIRSINFOKEY_TOTALCOST in dirsinfo\n"); goto do_extract_error; } } if ((oper==OPER_RESTFS) || (oper==OPER_RESTDIR)) { if ((exar.ai.cryptalgo!=ENCRYPT_NONE) && (g_options.encryptalgo!=ENCRYPT_BLOWFISH)) { errprintf("this archive has been encrypted, you have to provide a password on the command line using option '-c'\n"); goto do_extract_error; } if (exar.ai.archtype==ARCHTYPE_FILESYSTEMS) { // extract filesystem contents for (i=0; (i < exar.ai.fscount) && (i < FSA_MAX_FSPERARCH) && (get_abort()==false); i++) { if (dicoargv[i]!=NULL) // that filesystem has been requested on the command line { exar.fsid=i; memset(&exar.stats, 0, sizeof(exar.stats)); // init stats to zero msgprintf(MSG_VERB1, "============= extracting filesystem %d =============\n", i); if (extractar_filesystem_extract(&exar, dicofsinfo[i], dicoargv[i])!=0) { msgprintf(MSG_STACK, "extract_filesystem(%d) failed\n", i); goto do_extract_error; } if (get_abort()==false) stats_show(exar.stats, i); totalerr+=stats_errcount(exar.stats); } // else: the thread_archio automatically skips filesystem when g_fsbitmap[fsid]==0 } } else if (exar.ai.archtype==ARCHTYPE_DIRECTORIES) { exar.fsid=0; destdir=argv[0]; if (stat64(destdir, &st)!=0) { switch (errno) { case ENOENT: sysprintf("%s does not exist, cannot continue\n", destdir); break; default: sysprintf("fstat64(%s) failed\n", destdir); break; } goto do_extract_error; } if (!S_ISDIR(st.st_mode)) { errprintf("%s is not a valid directory, cannot continue\n", destdir); goto do_extract_error; } memset(&exar.stats, 0, sizeof(exar.stats)); // init stats to zero if (extractar_extract_read_objects(&exar, &errors, destdir, 0)!=0) // TODO: get the right fstype { errprintf("extract_read_objects(%s) failed\n", destdir); goto do_extract_error; } stats_show(exar.stats, 0); totalerr+=stats_errcount(exar.stats); } else { errprintf("unsupported archtype: %d\n", exar.ai.archtype); goto do_extract_error; } } if (get_abort()==true) msgprintf(MSG_FORCE, "operation aborted by user\n"); if (get_abort()==false && get_stopfillqueue()==false) goto do_extract_success; do_extract_error: msgprintf(MSG_DEBUG1, "THREAD-MAIN2: exit error\n"); ret=-1; do_extract_success: msgprintf(MSG_DEBUG1, "THREAD-MAIN2: exit\n"); set_stopfillqueue(); // ask thread-archio to terminate msgprintf(MSG_DEBUG2, "queue_count_items_todo(&g_queue)=%d\n", (int)queue_count_items_todo(&g_queue)); while (queue_count_items_todo(&g_queue)>0) // let thread_compress process all the pending blocks { msgprintf(MSG_DEBUG2, "queue_count_items_todo(): %ld\n", (long)queue_count_items_todo(&g_queue)); usleep(10000); } msgprintf(MSG_DEBUG2, "queue_count_items_todo(&g_queue)=%d\n", (int)queue_count_items_todo(&g_queue)); // now we are sure that thread_compress is not working on an item in the queue so we can empty the queue while (get_secthreads()>0 && queue_get_end_of_queue(&g_queue)==false) queue_destroy_first_item(&g_queue); msgprintf(MSG_DEBUG1, "THREAD-MAIN2: queue is now empty\n"); // the queue is empty, so thread_compress should now exit for (i=0; (i0) ret=-1; dico_destroy(dicomainhead); archreader_destroy(&exar.ai); return ret; } fsarchiver-0.8.5/src/archwriter.c0000644000176100017610000002664713242523705013734 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include "fsarchiver.h" #include "dico.h" #include "common.h" #include "options.h" #include "archwriter.h" #include "queue.h" #include "writebuf.h" #include "comp_gzip.h" #include "comp_bzip2.h" #include "error.h" #define FSA_SMB_SUPER_MAGIC 0x517B #define FSA_CIFS_MAGIC_NUMBER 0xFF534D42 int archwriter_init(carchwriter *ai) { assert(ai); memset(ai, 0, sizeof(struct s_archwriter)); strlist_init(&ai->vollist); ai->newarch=false; ai->archfd=-1; ai->archid=0; ai->curvol=0; return 0; } int archwriter_destroy(carchwriter *ai) { assert(ai); strlist_destroy(&ai->vollist); return 0; } int archwriter_generate_id(carchwriter *ai) { assert(ai); ai->archid=generate_random_u32_id(); return 0; } int archwriter_create(carchwriter *ai) { //char testpath[PATH_MAX]; //struct statfs svfs; //int tempfd; struct stat64 st; long archflags=0; long archperm; int res; assert(ai); // init memset(&st, 0, sizeof(st)); archflags=O_RDWR|O_CREAT|O_TRUNC|O_LARGEFILE; archperm=S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; // if the archive already exists and is a not regular file res=stat64(ai->volpath, &st); if (res==0 && !S_ISREG(st.st_mode)) { errprintf("%s already exists, and is not a regular file.\n", ai->basepath); return -1; } else if ((g_options.overwrite==0) && (res==0) && S_ISREG(st.st_mode)) // archive exists and is a regular file { errprintf("%s already exists, please remove it first.\n", ai->basepath); return -1; } // check if it's a network filesystem /*snprintf(testpath, sizeof(testpath), "%s.test", ai->volpath); if (((tempfd=open64(testpath, basicflags, archperm))<0) || (fstatfs(tempfd, &svfs)!=0) || (close(tempfd)!=0) || (unlink(testpath)!=0)) { errprintf("Cannot check the filesystem type on file %s\n", testpath); return -1; } if (svfs.f_type==FSA_CIFS_MAGIC_NUMBER || svfs.f_type==FSA_SMB_SUPER_MAGIC) { sysprintf ("writing an archive on a smbfs/cifs filesystem is " "not allowed, since it can produce corrupt archives.\n"); return -1; }*/ ai->archfd=open64(ai->volpath, archflags, archperm); if (ai->archfd < 0) { sysprintf ("cannot create archive %s\n", ai->volpath); return -1; } ai->newarch=true; strlist_add(&ai->vollist, ai->volpath); /* lockf is causing corruption when the archive is written on a smbfs/cifs filesystem */ /*if (lockf(ai->archfd, F_LOCK, 0)!=0) { sysprintf("Cannot lock archive file: %s\n", ai->volpath); close(ai->archfd); return -1; }*/ return 0; } int archwriter_close(carchwriter *ai) { assert(ai); if (ai->archfd<0) return -1; //res=lockf(ai->archfd, F_ULOCK, 0); fsync(ai->archfd); // just in case the user reboots after it exits close(ai->archfd); ai->archfd=-1; return 0; } int archwriter_remove(carchwriter *ai) { char volpath[PATH_MAX]; int count; int i; assert(ai); if (ai->archfd >= 0) { archwriter_close(ai); } if (ai->newarch==true) { count=strlist_count(&ai->vollist); for (i=0; i < count; i++) { if (strlist_getitem(&ai->vollist, i, volpath, sizeof(volpath))==0) { if (unlink(volpath)==0) msgprintf(MSG_FORCE, "removed %s\n", volpath); else errprintf("cannot remove %s\n", volpath); } } } return 0; } s64 archwriter_get_currentpos(carchwriter *ai) { assert(ai); return (s64)lseek64(ai->archfd, 0, SEEK_CUR); } int archwriter_write_buffer(carchwriter *ai, struct s_writebuf *wb) { struct statvfs64 statvfsbuf; char textbuf[128]; long lres; assert(ai); assert(wb); if (wb->size == 0) { errprintf("wb->size=%ld\n", (long)wb->size); return -1; } if ((lres=write(ai->archfd, (char*)wb->data, (long)wb->size))!=(long)wb->size) { errprintf("write(size=%ld) returned %ld\n", (long)wb->size, (long)lres); if ((lres>0) && (lres < (long)wb->size)) // probably "no space left" { if (fstatvfs64(ai->archfd, &statvfsbuf)!=0) { sysprintf("fstatvfs(fd=%d) failed\n", ai->archfd); return -1; } u64 freebytes = statvfsbuf.f_bfree * statvfsbuf.f_bsize; errprintf("Can't write to the archive file. Space on device is %s. \n" "If the archive is being written to a FAT filesystem, you may have reached \n" "the maximum filesize that it can handle (in general 2 GB)\n", format_size(freebytes, textbuf, sizeof(textbuf), 'h')); return -1; } else // another error { sysprintf("write(size=%ld) failed\n", (long)wb->size); return -1; } } return 0; } int archwriter_volpath(carchwriter *ai) { int res; res=get_path_to_volume(ai->volpath, PATH_MAX, ai->basepath, ai->curvol); return res; } int archwriter_is_path_to_curvol(carchwriter *ai, char *path) { assert(ai); assert(path); return strncmp(ai->volpath, path, PATH_MAX)==0 ? true : false; } int archwriter_incvolume(carchwriter *ai, bool waitkeypress) { assert(ai); ai->curvol++; return archwriter_volpath(ai); } int archwriter_write_volheader(carchwriter *ai) { struct s_writebuf *wb=NULL; cdico *voldico; assert(ai); if ((wb=writebuf_alloc())==NULL) { msgprintf(MSG_STACK, "writebuf_alloc() failed\n"); return -1; } if ((voldico=dico_alloc())==NULL) { msgprintf(MSG_STACK, "voldico=dico_alloc() failed\n"); return -1; } // prepare header dico_add_u32(voldico, 0, VOLUMEHEADKEY_VOLNUM, ai->curvol); dico_add_u32(voldico, 0, VOLUMEHEADKEY_ARCHID, ai->archid); dico_add_string(voldico, 0, VOLUMEHEADKEY_FILEFORMATVER, FSA_FILEFORMAT); dico_add_string(voldico, 0, VOLUMEHEADKEY_PROGVERCREAT, FSA_VERSION); // write header to buffer if (writebuf_add_header(wb, voldico, FSA_MAGIC_VOLH, ai->archid, FSA_FILESYSID_NULL)!=0) { errprintf("archio_write_header() failed\n"); return -1; } // write header to file if (archwriter_write_buffer(ai, wb)!=0) { errprintf("archwriter_write_buffer() failed\n"); return -1; } dico_destroy(voldico); writebuf_destroy(wb); return 0; } int archwriter_write_volfooter(carchwriter *ai, bool lastvol) { struct s_writebuf *wb=NULL; cdico *voldico; assert(ai); if ((wb=writebuf_alloc())==NULL) { errprintf("writebuf_alloc() failed\n"); return -1; } if ((voldico=dico_alloc())==NULL) { errprintf("voldico=dico_alloc() failed\n"); return -1; } // prepare header dico_add_u32(voldico, 0, VOLUMEFOOTKEY_VOLNUM, ai->curvol); dico_add_u32(voldico, 0, VOLUMEFOOTKEY_ARCHID, ai->archid); dico_add_u32(voldico, 0, VOLUMEFOOTKEY_LASTVOL, lastvol); // write header to buffer if (writebuf_add_header(wb, voldico, FSA_MAGIC_VOLF, ai->archid, FSA_FILESYSID_NULL)!=0) { msgprintf(MSG_STACK, "archio_write_header() failed\n"); return -1; } // write header to file if (archwriter_write_buffer(ai, wb)!=0) { msgprintf(MSG_STACK, "archwriter_write_data(size=%ld) failed\n", (long)wb->size); return -1; } dico_destroy(voldico); writebuf_destroy(wb); return 0; } int archwriter_split_check(carchwriter *ai, struct s_writebuf *wb) { s64 cursize; assert(ai); if (((cursize=archwriter_get_currentpos(ai))>=0) && (g_options.splitsize>0 && cursize+wb->size > g_options.splitsize)) { msgprintf(MSG_DEBUG4, "splitchk: YES --> cursize=%lld, g_options.splitsize=%lld, cursize+wb->size=%lld, wb->size=%lld\n", (long long)cursize, (long long)g_options.splitsize, (long long)cursize+wb->size, (long long)wb->size); return true; } else { msgprintf(MSG_DEBUG4, "splitchk: NO --> cursize=%lld, g_options.splitsize=%lld, cursize+wb->size=%lld, wb->size=%lld\n", (long long)cursize, (long long)g_options.splitsize, (long long)cursize+wb->size, (long long)wb->size); return false; } } int archwriter_split_if_necessary(carchwriter *ai, struct s_writebuf *wb) { assert(ai); if (archwriter_split_check(ai, wb)==true) { if (archwriter_write_volfooter(ai, false)!=0) { msgprintf(MSG_STACK, "cannot write volume footer: archio_write_volfooter() failed\n"); return -1; } archwriter_close(ai); archwriter_incvolume(ai, false); msgprintf(MSG_VERB2, "Creating new volume: [%s]\n", ai->volpath); if (archwriter_create(ai)!=0) { msgprintf(MSG_STACK, "archwriter_create() failed\n"); return -1; } if (archwriter_write_volheader(ai)!=0) { msgprintf(MSG_STACK, "cannot write volume header: archio_write_volheader() failed\n"); return -1; } } return 0; } int archwriter_dowrite_block(carchwriter *ai, struct s_blockinfo *blkinfo) { struct s_writebuf *wb=NULL; assert(ai); if ((wb=writebuf_alloc())==NULL) { errprintf("writebuf_alloc() failed\n"); return -1; } if (writebuf_add_block(wb, blkinfo, ai->archid, blkinfo->blkfsid)!=0) { msgprintf(MSG_STACK, "archio_write_block() failed\n"); return -1; } if (archwriter_split_if_necessary(ai, wb)!=0) { msgprintf(MSG_STACK, "archwriter_split_if_necessary() failed\n"); return -1; } if (archwriter_write_buffer(ai, wb)!=0) { msgprintf(MSG_STACK, "archwriter_write_buffer() failed\n"); return -1; } writebuf_destroy(wb); return 0; } int archwriter_dowrite_header(carchwriter *ai, struct s_headinfo *headinfo) { struct s_writebuf *wb=NULL; assert(ai); if ((wb=writebuf_alloc())==NULL) { errprintf("writebuf_alloc() failed\n"); return -1; } if (writebuf_add_header(wb, headinfo->dico, headinfo->magic, ai->archid, headinfo->fsid)!=0) { msgprintf(MSG_STACK, "archio_write_block() failed\n"); return -1; } if (archwriter_split_if_necessary(ai, wb)!=0) { msgprintf(MSG_STACK, "archwriter_split_if_necessary() failed\n"); return -1; } if (archwriter_write_buffer(ai, wb)!=0) { msgprintf(MSG_STACK, "archwriter_write_buffer() failed\n"); return -1; } writebuf_destroy(wb); return 0; } fsarchiver-0.8.5/src/oper_probe.c0000644000176100017610000001620713242523705013705 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include "fsarchiver.h" #include "devinfo.h" #include "oper_probe.h" #include "common.h" #include "error.h" struct s_diskinfo { bool detailed; char format[256]; char title[256]; }; int partlist_getlist(struct s_devinfo *blkdev, int maxblkdev, int *diskcount, int *partcount) { struct s_devinfo blkdev1[FSA_MAX_BLKDEVICES]; struct s_devinfo tmpdev; int best; // index of the best item found in old array int pos=0; // pos of latest item in new array char devname[1024]; char longname[1024]; char delims[]=" \t\n"; char line[1024]; char *saveptr; char *result; char major[256]; char minor[256]; FILE *fpart; int count=0; int i, j; // init *diskcount=0; *partcount=0; // browse list in "/proc/partitions" if ((fpart=fopen("/proc/partitions","rb"))==NULL) return -1; while(!feof(fpart) && (count < FSA_MAX_BLKDEVICES) && (count < maxblkdev)) { if (stream_readline(fpart, line, sizeof(line))>1) { minor[0]=major[0]=0; devname[0]=0; result=strtok_r(line, delims, &saveptr); for(i=0; result != NULL && i<=4; i++) { switch(i) { case 0: // col0 = major snprintf(major, sizeof(major), "%s", result); break; case 1: // col1 = minor snprintf(minor, sizeof(minor), "%s", result); break; case 3: // col3 = devname snprintf(devname, sizeof(devname), "%s", result); break; } result = strtok_r(NULL, delims, &saveptr); } // ignore invalid entries if ((strlen(devname)==0) || (atoi(major)==0 && atoi(minor)==0)) continue; snprintf(longname, sizeof(longname), "/dev/%s", devname); if (get_devinfo(&tmpdev, longname, atoi(minor), atoi(major))!=0) continue; // to to the next part // check that this device is not already in the list for (i=0; i < count; i++) if (blkdev1[i].rdev==tmpdev.rdev) continue; // to to the next part // add the device to list if it is a real device and it's not already in the list blkdev1[count++]=tmpdev; } } fclose(fpart); // ---- 2. sort the devices for (pos=0, i=0; i 0) && (blkdev1[j].rdev < blkdev1[best].rdev)) best=j; // update counters switch (blkdev1[best].devtype) { case BLKDEV_FILESYSDEV: (*partcount)++; break; case BLKDEV_PHYSDISK: (*diskcount)++; break; } // move item to the new array blkdev[pos++]=blkdev1[best]; blkdev1[best].rdev=0; } return count; } struct s_diskinfo partinfo[]= { {false, "[%-16s] ", "[=====DEVICE=====] "}, {false, "[%-11.11s] ", "[==FILESYS==] "}, {false, "[%-17.17s] ", "[======LABEL======] "}, {false, "[%12s] ", "[====SIZE====] "}, {false, "[%3s] ", "[MAJ] "}, {false, "[%3s] ", "[MIN] "}, {true, "[%-36s] ", "[==============LONGNAME==============] "}, {true, "[%-38s] ", "[=================UUID=================] "}, {false, "", ""} }; char *partlist_getinfo(char *bufdat, int bufsize, struct s_devinfo *blkdev, int item) { memset(bufdat, 0, bufsize); switch (item) { case 0: snprintf(bufdat, bufsize, "%s", blkdev->devname); break; case 1: snprintf(bufdat, bufsize, "%s", blkdev->fsname); break; case 2: snprintf(bufdat, bufsize, "%s", blkdev->label); break; case 3: snprintf(bufdat, bufsize, "%s", blkdev->txtsize); break; case 4: snprintf(bufdat, bufsize, "%d", blkdev->major); break; case 5: snprintf(bufdat, bufsize, "%d", blkdev->minor); break; case 6: snprintf(bufdat, bufsize, "%s", blkdev->longname); break; case 7: snprintf(bufdat, bufsize, "%s", blkdev->uuid); break; }; return bufdat; } int oper_probe(bool details) { struct s_devinfo blkdev[FSA_MAX_BLKDEVICES]; int diskcount; int partcount; char temp[1024]; int res; int i, j; // ---- 0. get info from /proc/partitions + libblkid if ((res=partlist_getlist(blkdev, FSA_MAX_BLKDEVICES, &diskcount, &partcount))<1) { msgprintf(MSG_FORCE, "Failed to detect disks and filesystems\n"); return -1; } // ---- 1. show physical disks if (diskcount>0) { msgprintf(MSG_FORCE, "[======DISK======] [=============NAME==============] [====SIZE====] [MAJ] [MIN]\n"); for (i=0; i < res; i++) if (blkdev[i].devtype==BLKDEV_PHYSDISK) msgprintf(MSG_FORCE, "[%-16s] [%-31s] [%12s] [%3d] [%3d]\n", blkdev[i].devname, blkdev[i].name, blkdev[i].txtsize, blkdev[i].major, blkdev[i].minor); msgprintf(MSG_FORCE, "\n"); } else { msgprintf(MSG_FORCE, "No physical disk found\n"); } // ---- 2. show filesystem information if (partcount>0) { // show title for filesystems for (j=0; partinfo[j].title[0]; j++) { if (details==true || partinfo[j].detailed==false) msgprintf(MSG_FORCE, "%s", partinfo[j].title); } msgprintf(MSG_FORCE, "\n"); // show filesystems data for (i=0; i < res; i++) { if (blkdev[i].devtype==BLKDEV_FILESYSDEV) { for (j=0; partinfo[j].title[0]; j++) { if (details==true || partinfo[j].detailed==false) msgprintf(MSG_FORCE, partinfo[j].format, partlist_getinfo(temp, sizeof(temp), &blkdev[i], j)); } msgprintf(MSG_FORCE, "\n"); } } } else { msgprintf(MSG_FORCE, "No filesystem found\n"); } return 0; } fsarchiver-0.8.5/src/dichl.h0000644000176100017610000000214213242523705012632 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __DICHL_H__ #define __DICHL_H__ #include "types.h" struct s_dichl; typedef struct s_dichl cdichl; struct s_dichlitem; typedef struct s_dichlitem cdichlitem; struct s_dichl { cdichlitem *head; }; struct s_dichlitem { u64 key1; u64 key2; char *str; cdichlitem *next; }; cdichl *dichl_alloc(); int dichl_destroy(cdichl *d); int dichl_add(cdichl *d, u64 key1, u64 key2, char *str); int dichl_get(cdichl *d, u64 key1, u64 key2, char *buf, int bufsize); #endif // __DICHL_H__ fsarchiver-0.8.5/src/fs_ntfs.h0000644000176100017610000000300113242523705013204 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __FS_NTFS_H__ #define __FS_NTFS_H__ struct s_dico; struct s_strlist; #define NTFS3G_VERSION(year, month, day) ((u64)((((u64)year&0xFFFF)<<48)+(((u64)month&0xFFFF)<<32)+(((u64)day&0xFFFF)<<16))) #define NTFS3G_MINVER_Y 2009 #define NTFS3G_MINVER_M 11 #define NTFS3G_MINVER_D 14 struct s_ntfsinfo { u32 bytes_per_sector; u32 sectors_per_clusters; u32 bytes_per_cluster; u64 uuid; }; int ntfs_mkfs(struct s_dico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid); int ntfs_getinfo(struct s_dico *d, char *devname); int ntfs_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo); int ntfs_get_reqmntopt(char *partition, struct s_strlist *reqopt, struct s_strlist *badopt); int ntfs_replace_uuid(char *devname, u64 uuid); int ntfs_umount(char *partition, char *mntbuf); int ntfs_test(char *devname); #endif // __FS_NTFS_H__ fsarchiver-0.8.5/src/comp_zstd.c0000644000176100017610000000306713242523705013553 00000000000000 /* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "fsarchiver.h" #include "common.h" #include "comp_zstd.h" #include "error.h" #ifdef OPTION_ZSTD_SUPPORT int compress_block_zstd(u64 origsize, u64 *compsize, u8 *origbuf, u8 *compbuf, u64 compbufsize, int level) { int res=0; if (ZSTD_isError((res=ZSTD_compress((char*)compbuf, compbufsize, (const char*)origbuf, (int)origsize, level)))) { errprintf("ZSTD_compress(): failed: res=%d\n", res); return FSAERR_UNKNOWN; } else { *compsize=(u64)res; return FSAERR_SUCCESS; } } int uncompress_block_zstd(u64 compsize, u64 *origsize, u8 *origbuf, u64 origbufsize, u8 *compbuf) { int res=0; if (ZSTD_isError((res=ZSTD_decompress((char*)origbuf, origbufsize, (char*)compbuf, compsize)))) { errprintf("ZSTD_decompress(): failed: res=%d\n", res); return FSAERR_UNKNOWN; } else { *origsize=(u64)res; return FSAERR_SUCCESS; } } #endif // OPTION_ZSTD_SUPPORT fsarchiver-0.8.5/src/fs_jfs.h0000644000176100017610000001105613242523705013025 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __FS_JFS_H__ #define __FS_JFS_H__ struct s_dico; struct s_strlist; int jfs_mkfs(struct s_dico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid); int jfs_getinfo(struct s_dico *d, char *devname); int jfs_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo); int jfs_get_reqmntopt(char *partition, struct s_strlist *reqopt, struct s_strlist *badopt); int jfs_umount(char *partition, char *mntbuf); int jfs_test(char *devname); // make the magic number something a human could read #define JFS_MAGIC "JFS1" /* Magic word */ #define LV_NAME_SIZE 11 /* MUST BE 11 for OS/2 boot sector */ #define JFS_SUPER1_OFF 0x8000 /* primary superblock */ /* * physical xd (pxd) */ typedef struct { unsigned len:24; unsigned addr1:8; u32 addr2; } pxd_t; /* * Almost identical to Linux's timespec, but not quite */ struct timestruc_t { u32 tv_sec; u32 tv_nsec; }; /* * aggregate superblock * * The name superblock is too close to super_block, so the name has been * changed to jfs_superblock. The utilities are still using the old name. */ struct jfs_superblock { char s_magic[4]; /* 4: magic number */ u32 s_version; /* 4: version number */ u64 s_size; /* 8: aggregate size in hardware/LVM blocks; * VFS: number of blocks */ u32 s_bsize; /* 4: aggregate block size in bytes; * VFS: fragment size */ u16 s_l2bsize; /* 2: log2 of s_bsize */ u16 s_l2bfactor; /* 2: log2(s_bsize/hardware block size) */ u32 s_pbsize; /* 4: hardware/LVM block size in bytes */ u16 s_l2pbsize; /* 2: log2 of s_pbsize */ u16 pad; /* 2: padding necessary for alignment */ u32 s_agsize; /* 4: allocation group size in aggr. blocks */ u32 s_flag; /* 4: aggregate attributes: * see jfs_filsys.h */ u32 s_state; /* 4: mount/unmount/recovery state: * see jfs_filsys.h */ u32 s_compress; /* 4: > 0 if data compression */ pxd_t s_ait2; /* 8: first extent of secondary * aggregate inode table */ pxd_t s_aim2; /* 8: first extent of secondary * aggregate inode map */ u32 s_logdev; /* 4: device address of log */ u32 s_logserial; /* 4: log serial number at aggregate mount */ pxd_t s_logpxd; /* 8: inline log extent */ pxd_t s_fsckpxd; /* 8: inline fsck work space extent */ struct timestruc_t s_time; /* 8: time last updated */ u32 s_fsckloglen; /* 4: Number of filesystem blocks reserved for * the fsck service log. * N.B. These blocks are divided among the * versions kept. This is not a per * version size. * N.B. These blocks are included in the * length field of s_fsckpxd. */ s8 s_fscklog; /* 1: which fsck service log is most recent * 0 => no service log data yet * 1 => the first one * 2 => the 2nd one */ char s_fpack[11]; /* 11: file system volume name * N.B. This must be 11 bytes to * conform with the OS/2 BootSector * requirements * Only used when s_version is 1 */ /* extendfs() parameter under s_state & FM_EXTENDFS */ u64 s_xsize; /* 8: extendfs s_size */ pxd_t s_xfsckpxd; /* 8: extendfs fsckpxd */ pxd_t s_xlogpxd; /* 8: extendfs logpxd */ /* - 128 byte boundary - */ char s_uuid[16]; /* 16: 128-bit uuid for volume */ char s_label[16]; /* 16: volume label */ char s_loguuid[16]; /* 16: 128-bit uuid for log device */ }; #endif // __FS_JFS_H__ fsarchiver-0.8.5/src/Makefile.in0000644000176100017610000027602413321212503013444 00000000000000# Makefile.in generated by automake 1.15.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2017 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = fsarchiver$(EXEEXT) subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am_fsarchiver_OBJECTS = fsarchiver-fsarchiver.$(OBJEXT) \ fsarchiver-oper_save.$(OBJEXT) \ fsarchiver-oper_restore.$(OBJEXT) \ fsarchiver-oper_probe.$(OBJEXT) \ fsarchiver-thread_archio.$(OBJEXT) \ fsarchiver-archreader.$(OBJEXT) \ fsarchiver-archwriter.$(OBJEXT) fsarchiver-writebuf.$(OBJEXT) \ fsarchiver-archinfo.$(OBJEXT) fsarchiver-thread_comp.$(OBJEXT) \ fsarchiver-comp_gzip.$(OBJEXT) fsarchiver-comp_bzip2.$(OBJEXT) \ fsarchiver-comp_lzma.$(OBJEXT) fsarchiver-comp_lzo.$(OBJEXT) \ fsarchiver-comp_lz4.$(OBJEXT) fsarchiver-comp_zstd.$(OBJEXT) \ fsarchiver-crypto.$(OBJEXT) fsarchiver-fs_ntfs.$(OBJEXT) \ fsarchiver-fs_ext2.$(OBJEXT) fsarchiver-fs_reiserfs.$(OBJEXT) \ fsarchiver-fs_reiser4.$(OBJEXT) fsarchiver-fs_btrfs.$(OBJEXT) \ fsarchiver-fs_xfs.$(OBJEXT) fsarchiver-fs_jfs.$(OBJEXT) \ fsarchiver-fs_vfat.$(OBJEXT) fsarchiver-common.$(OBJEXT) \ fsarchiver-dico.$(OBJEXT) fsarchiver-strdico.$(OBJEXT) \ fsarchiver-dichl.$(OBJEXT) fsarchiver-queue.$(OBJEXT) \ fsarchiver-error.$(OBJEXT) fsarchiver-syncthread.$(OBJEXT) \ fsarchiver-datafile.$(OBJEXT) fsarchiver-strlist.$(OBJEXT) \ fsarchiver-regmulti.$(OBJEXT) fsarchiver-options.$(OBJEXT) \ fsarchiver-logfile.$(OBJEXT) fsarchiver-filesys.$(OBJEXT) \ fsarchiver-devinfo.$(OBJEXT) fsarchiver_OBJECTS = $(am_fsarchiver_OBJECTS) am__DEPENDENCIES_1 = fsarchiver_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) fsarchiver_LINK = $(CCLD) $(fsarchiver_CFLAGS) $(CFLAGS) \ $(fsarchiver_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(fsarchiver_SOURCES) DIST_SOURCES = $(fsarchiver_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BLKID_CFLAGS = @BLKID_CFLAGS@ BLKID_LIBS = @BLKID_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ COM_ERR_CFLAGS = @COM_ERR_CFLAGS@ COM_ERR_LIBS = @COM_ERR_LIBS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_DEBUG_LEVEL = @DEFAULT_DEBUG_LEVEL@ DEFS = @DEFS@ -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_GNU_SOURCE DEPDIR = @DEPDIR@ E2P_CFLAGS = @E2P_CFLAGS@ E2P_LIBS = @E2P_LIBS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT2FS_CFLAGS = @EXT2FS_CFLAGS@ EXT2FS_LIBS = @EXT2FS_LIBS@ FSARCHIVER_LDFLAGS = @FSARCHIVER_LDFLAGS@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LOGDIR = @LOGDIR@ LTLIBOBJS = @LTLIBOBJS@ LZMA_CFLAGS = @LZMA_CFLAGS@ LZMA_LIBS = @LZMA_LIBS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ UUID_CFLAGS = @UUID_CFLAGS@ UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ fsarchiver_SOURCES = fsarchiver.c oper_save.c oper_restore.c oper_probe.c \ thread_archio.c archreader.c archwriter.c writebuf.c archinfo.c \ thread_comp.c comp_gzip.c comp_bzip2.c comp_lzma.c comp_lzo.c comp_lz4.c \ comp_zstd.c crypto.c fs_ntfs.c fs_ext2.c fs_reiserfs.c fs_reiser4.c \ fs_btrfs.c fs_xfs.c fs_jfs.c fs_vfat.c common.c dico.c strdico.c dichl.c \ queue.c error.c syncthread.c datafile.c strlist.c regmulti.c options.c \ logfile.c filesys.c devinfo.c noinst_HEADERS = fsarchiver.h oper_save.h oper_restore.h oper_probe.h \ thread_archio.h archreader.h archwriter.h writebuf.h archinfo.h \ thread_comp.h comp_gzip.h comp_bzip2.h comp_lzma.h comp_lzo.h comp_lz4.h \ comp_zstd.h crypto.h fs_ntfs.h fs_ext2.h fs_reiserfs.h fs_reiser4.h \ fs_btrfs.h fs_xfs.h fs_jfs.h fs_vfat.h common.h dico.h strdico.h dichl.h \ queue.h error.h syncthread.h datafile.h strlist.h regmulti.h options.h \ logfile.h types.h filesys.h devinfo.h fsarchiver_LDADD = -lpthread -lrt \ $(LZMA_LIBS) \ $(EXT2FS_LIBS) \ $(COM_ERR_LIBS) \ $(E2P_LIBS) \ $(BLKID_LIBS) \ $(UUID_LIBS) fsarchiver_CFLAGS = @CFLAGS@ -Wall -std=gnu99 -rdynamic -ggdb \ $(LZMA_CFLAGS) \ $(EXT2FS_CFLAGS) \ $(COM_ERR_CFLAGS) \ $(E2P_CFLAGS) \ $(BLKID_CFLAGS) \ $(UUID_CFLAGS) fsarchiver_LDFLAGS = @FSARCHIVER_LDFLAGS@ MAINTAINERCLEANFILES = Makefile.in all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) fsarchiver$(EXEEXT): $(fsarchiver_OBJECTS) $(fsarchiver_DEPENDENCIES) $(EXTRA_fsarchiver_DEPENDENCIES) @rm -f fsarchiver$(EXEEXT) $(AM_V_CCLD)$(fsarchiver_LINK) $(fsarchiver_OBJECTS) $(fsarchiver_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-archinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-archreader.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-archwriter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-comp_bzip2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-comp_gzip.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-comp_lz4.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-comp_lzma.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-comp_lzo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-comp_zstd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-crypto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-datafile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-devinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-dichl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-dico.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-error.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-filesys.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-fs_btrfs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-fs_ext2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-fs_jfs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-fs_ntfs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-fs_reiser4.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-fs_reiserfs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-fs_vfat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-fs_xfs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-fsarchiver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-logfile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-oper_probe.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-oper_restore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-oper_save.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-options.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-queue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-regmulti.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-strdico.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-strlist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-syncthread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-thread_archio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-thread_comp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsarchiver-writebuf.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` fsarchiver-fsarchiver.o: fsarchiver.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fsarchiver.o -MD -MP -MF $(DEPDIR)/fsarchiver-fsarchiver.Tpo -c -o fsarchiver-fsarchiver.o `test -f 'fsarchiver.c' || echo '$(srcdir)/'`fsarchiver.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fsarchiver.Tpo $(DEPDIR)/fsarchiver-fsarchiver.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fsarchiver.c' object='fsarchiver-fsarchiver.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fsarchiver.o `test -f 'fsarchiver.c' || echo '$(srcdir)/'`fsarchiver.c fsarchiver-fsarchiver.obj: fsarchiver.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fsarchiver.obj -MD -MP -MF $(DEPDIR)/fsarchiver-fsarchiver.Tpo -c -o fsarchiver-fsarchiver.obj `if test -f 'fsarchiver.c'; then $(CYGPATH_W) 'fsarchiver.c'; else $(CYGPATH_W) '$(srcdir)/fsarchiver.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fsarchiver.Tpo $(DEPDIR)/fsarchiver-fsarchiver.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fsarchiver.c' object='fsarchiver-fsarchiver.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fsarchiver.obj `if test -f 'fsarchiver.c'; then $(CYGPATH_W) 'fsarchiver.c'; else $(CYGPATH_W) '$(srcdir)/fsarchiver.c'; fi` fsarchiver-oper_save.o: oper_save.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-oper_save.o -MD -MP -MF $(DEPDIR)/fsarchiver-oper_save.Tpo -c -o fsarchiver-oper_save.o `test -f 'oper_save.c' || echo '$(srcdir)/'`oper_save.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-oper_save.Tpo $(DEPDIR)/fsarchiver-oper_save.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oper_save.c' object='fsarchiver-oper_save.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-oper_save.o `test -f 'oper_save.c' || echo '$(srcdir)/'`oper_save.c fsarchiver-oper_save.obj: oper_save.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-oper_save.obj -MD -MP -MF $(DEPDIR)/fsarchiver-oper_save.Tpo -c -o fsarchiver-oper_save.obj `if test -f 'oper_save.c'; then $(CYGPATH_W) 'oper_save.c'; else $(CYGPATH_W) '$(srcdir)/oper_save.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-oper_save.Tpo $(DEPDIR)/fsarchiver-oper_save.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oper_save.c' object='fsarchiver-oper_save.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-oper_save.obj `if test -f 'oper_save.c'; then $(CYGPATH_W) 'oper_save.c'; else $(CYGPATH_W) '$(srcdir)/oper_save.c'; fi` fsarchiver-oper_restore.o: oper_restore.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-oper_restore.o -MD -MP -MF $(DEPDIR)/fsarchiver-oper_restore.Tpo -c -o fsarchiver-oper_restore.o `test -f 'oper_restore.c' || echo '$(srcdir)/'`oper_restore.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-oper_restore.Tpo $(DEPDIR)/fsarchiver-oper_restore.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oper_restore.c' object='fsarchiver-oper_restore.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-oper_restore.o `test -f 'oper_restore.c' || echo '$(srcdir)/'`oper_restore.c fsarchiver-oper_restore.obj: oper_restore.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-oper_restore.obj -MD -MP -MF $(DEPDIR)/fsarchiver-oper_restore.Tpo -c -o fsarchiver-oper_restore.obj `if test -f 'oper_restore.c'; then $(CYGPATH_W) 'oper_restore.c'; else $(CYGPATH_W) '$(srcdir)/oper_restore.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-oper_restore.Tpo $(DEPDIR)/fsarchiver-oper_restore.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oper_restore.c' object='fsarchiver-oper_restore.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-oper_restore.obj `if test -f 'oper_restore.c'; then $(CYGPATH_W) 'oper_restore.c'; else $(CYGPATH_W) '$(srcdir)/oper_restore.c'; fi` fsarchiver-oper_probe.o: oper_probe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-oper_probe.o -MD -MP -MF $(DEPDIR)/fsarchiver-oper_probe.Tpo -c -o fsarchiver-oper_probe.o `test -f 'oper_probe.c' || echo '$(srcdir)/'`oper_probe.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-oper_probe.Tpo $(DEPDIR)/fsarchiver-oper_probe.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oper_probe.c' object='fsarchiver-oper_probe.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-oper_probe.o `test -f 'oper_probe.c' || echo '$(srcdir)/'`oper_probe.c fsarchiver-oper_probe.obj: oper_probe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-oper_probe.obj -MD -MP -MF $(DEPDIR)/fsarchiver-oper_probe.Tpo -c -o fsarchiver-oper_probe.obj `if test -f 'oper_probe.c'; then $(CYGPATH_W) 'oper_probe.c'; else $(CYGPATH_W) '$(srcdir)/oper_probe.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-oper_probe.Tpo $(DEPDIR)/fsarchiver-oper_probe.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oper_probe.c' object='fsarchiver-oper_probe.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-oper_probe.obj `if test -f 'oper_probe.c'; then $(CYGPATH_W) 'oper_probe.c'; else $(CYGPATH_W) '$(srcdir)/oper_probe.c'; fi` fsarchiver-thread_archio.o: thread_archio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-thread_archio.o -MD -MP -MF $(DEPDIR)/fsarchiver-thread_archio.Tpo -c -o fsarchiver-thread_archio.o `test -f 'thread_archio.c' || echo '$(srcdir)/'`thread_archio.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-thread_archio.Tpo $(DEPDIR)/fsarchiver-thread_archio.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thread_archio.c' object='fsarchiver-thread_archio.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-thread_archio.o `test -f 'thread_archio.c' || echo '$(srcdir)/'`thread_archio.c fsarchiver-thread_archio.obj: thread_archio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-thread_archio.obj -MD -MP -MF $(DEPDIR)/fsarchiver-thread_archio.Tpo -c -o fsarchiver-thread_archio.obj `if test -f 'thread_archio.c'; then $(CYGPATH_W) 'thread_archio.c'; else $(CYGPATH_W) '$(srcdir)/thread_archio.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-thread_archio.Tpo $(DEPDIR)/fsarchiver-thread_archio.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thread_archio.c' object='fsarchiver-thread_archio.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-thread_archio.obj `if test -f 'thread_archio.c'; then $(CYGPATH_W) 'thread_archio.c'; else $(CYGPATH_W) '$(srcdir)/thread_archio.c'; fi` fsarchiver-archreader.o: archreader.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-archreader.o -MD -MP -MF $(DEPDIR)/fsarchiver-archreader.Tpo -c -o fsarchiver-archreader.o `test -f 'archreader.c' || echo '$(srcdir)/'`archreader.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-archreader.Tpo $(DEPDIR)/fsarchiver-archreader.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='archreader.c' object='fsarchiver-archreader.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-archreader.o `test -f 'archreader.c' || echo '$(srcdir)/'`archreader.c fsarchiver-archreader.obj: archreader.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-archreader.obj -MD -MP -MF $(DEPDIR)/fsarchiver-archreader.Tpo -c -o fsarchiver-archreader.obj `if test -f 'archreader.c'; then $(CYGPATH_W) 'archreader.c'; else $(CYGPATH_W) '$(srcdir)/archreader.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-archreader.Tpo $(DEPDIR)/fsarchiver-archreader.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='archreader.c' object='fsarchiver-archreader.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-archreader.obj `if test -f 'archreader.c'; then $(CYGPATH_W) 'archreader.c'; else $(CYGPATH_W) '$(srcdir)/archreader.c'; fi` fsarchiver-archwriter.o: archwriter.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-archwriter.o -MD -MP -MF $(DEPDIR)/fsarchiver-archwriter.Tpo -c -o fsarchiver-archwriter.o `test -f 'archwriter.c' || echo '$(srcdir)/'`archwriter.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-archwriter.Tpo $(DEPDIR)/fsarchiver-archwriter.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='archwriter.c' object='fsarchiver-archwriter.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-archwriter.o `test -f 'archwriter.c' || echo '$(srcdir)/'`archwriter.c fsarchiver-archwriter.obj: archwriter.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-archwriter.obj -MD -MP -MF $(DEPDIR)/fsarchiver-archwriter.Tpo -c -o fsarchiver-archwriter.obj `if test -f 'archwriter.c'; then $(CYGPATH_W) 'archwriter.c'; else $(CYGPATH_W) '$(srcdir)/archwriter.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-archwriter.Tpo $(DEPDIR)/fsarchiver-archwriter.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='archwriter.c' object='fsarchiver-archwriter.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-archwriter.obj `if test -f 'archwriter.c'; then $(CYGPATH_W) 'archwriter.c'; else $(CYGPATH_W) '$(srcdir)/archwriter.c'; fi` fsarchiver-writebuf.o: writebuf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-writebuf.o -MD -MP -MF $(DEPDIR)/fsarchiver-writebuf.Tpo -c -o fsarchiver-writebuf.o `test -f 'writebuf.c' || echo '$(srcdir)/'`writebuf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-writebuf.Tpo $(DEPDIR)/fsarchiver-writebuf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='writebuf.c' object='fsarchiver-writebuf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-writebuf.o `test -f 'writebuf.c' || echo '$(srcdir)/'`writebuf.c fsarchiver-writebuf.obj: writebuf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-writebuf.obj -MD -MP -MF $(DEPDIR)/fsarchiver-writebuf.Tpo -c -o fsarchiver-writebuf.obj `if test -f 'writebuf.c'; then $(CYGPATH_W) 'writebuf.c'; else $(CYGPATH_W) '$(srcdir)/writebuf.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-writebuf.Tpo $(DEPDIR)/fsarchiver-writebuf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='writebuf.c' object='fsarchiver-writebuf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-writebuf.obj `if test -f 'writebuf.c'; then $(CYGPATH_W) 'writebuf.c'; else $(CYGPATH_W) '$(srcdir)/writebuf.c'; fi` fsarchiver-archinfo.o: archinfo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-archinfo.o -MD -MP -MF $(DEPDIR)/fsarchiver-archinfo.Tpo -c -o fsarchiver-archinfo.o `test -f 'archinfo.c' || echo '$(srcdir)/'`archinfo.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-archinfo.Tpo $(DEPDIR)/fsarchiver-archinfo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='archinfo.c' object='fsarchiver-archinfo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-archinfo.o `test -f 'archinfo.c' || echo '$(srcdir)/'`archinfo.c fsarchiver-archinfo.obj: archinfo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-archinfo.obj -MD -MP -MF $(DEPDIR)/fsarchiver-archinfo.Tpo -c -o fsarchiver-archinfo.obj `if test -f 'archinfo.c'; then $(CYGPATH_W) 'archinfo.c'; else $(CYGPATH_W) '$(srcdir)/archinfo.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-archinfo.Tpo $(DEPDIR)/fsarchiver-archinfo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='archinfo.c' object='fsarchiver-archinfo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-archinfo.obj `if test -f 'archinfo.c'; then $(CYGPATH_W) 'archinfo.c'; else $(CYGPATH_W) '$(srcdir)/archinfo.c'; fi` fsarchiver-thread_comp.o: thread_comp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-thread_comp.o -MD -MP -MF $(DEPDIR)/fsarchiver-thread_comp.Tpo -c -o fsarchiver-thread_comp.o `test -f 'thread_comp.c' || echo '$(srcdir)/'`thread_comp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-thread_comp.Tpo $(DEPDIR)/fsarchiver-thread_comp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thread_comp.c' object='fsarchiver-thread_comp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-thread_comp.o `test -f 'thread_comp.c' || echo '$(srcdir)/'`thread_comp.c fsarchiver-thread_comp.obj: thread_comp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-thread_comp.obj -MD -MP -MF $(DEPDIR)/fsarchiver-thread_comp.Tpo -c -o fsarchiver-thread_comp.obj `if test -f 'thread_comp.c'; then $(CYGPATH_W) 'thread_comp.c'; else $(CYGPATH_W) '$(srcdir)/thread_comp.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-thread_comp.Tpo $(DEPDIR)/fsarchiver-thread_comp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thread_comp.c' object='fsarchiver-thread_comp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-thread_comp.obj `if test -f 'thread_comp.c'; then $(CYGPATH_W) 'thread_comp.c'; else $(CYGPATH_W) '$(srcdir)/thread_comp.c'; fi` fsarchiver-comp_gzip.o: comp_gzip.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_gzip.o -MD -MP -MF $(DEPDIR)/fsarchiver-comp_gzip.Tpo -c -o fsarchiver-comp_gzip.o `test -f 'comp_gzip.c' || echo '$(srcdir)/'`comp_gzip.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_gzip.Tpo $(DEPDIR)/fsarchiver-comp_gzip.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_gzip.c' object='fsarchiver-comp_gzip.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_gzip.o `test -f 'comp_gzip.c' || echo '$(srcdir)/'`comp_gzip.c fsarchiver-comp_gzip.obj: comp_gzip.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_gzip.obj -MD -MP -MF $(DEPDIR)/fsarchiver-comp_gzip.Tpo -c -o fsarchiver-comp_gzip.obj `if test -f 'comp_gzip.c'; then $(CYGPATH_W) 'comp_gzip.c'; else $(CYGPATH_W) '$(srcdir)/comp_gzip.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_gzip.Tpo $(DEPDIR)/fsarchiver-comp_gzip.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_gzip.c' object='fsarchiver-comp_gzip.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_gzip.obj `if test -f 'comp_gzip.c'; then $(CYGPATH_W) 'comp_gzip.c'; else $(CYGPATH_W) '$(srcdir)/comp_gzip.c'; fi` fsarchiver-comp_bzip2.o: comp_bzip2.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_bzip2.o -MD -MP -MF $(DEPDIR)/fsarchiver-comp_bzip2.Tpo -c -o fsarchiver-comp_bzip2.o `test -f 'comp_bzip2.c' || echo '$(srcdir)/'`comp_bzip2.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_bzip2.Tpo $(DEPDIR)/fsarchiver-comp_bzip2.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_bzip2.c' object='fsarchiver-comp_bzip2.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_bzip2.o `test -f 'comp_bzip2.c' || echo '$(srcdir)/'`comp_bzip2.c fsarchiver-comp_bzip2.obj: comp_bzip2.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_bzip2.obj -MD -MP -MF $(DEPDIR)/fsarchiver-comp_bzip2.Tpo -c -o fsarchiver-comp_bzip2.obj `if test -f 'comp_bzip2.c'; then $(CYGPATH_W) 'comp_bzip2.c'; else $(CYGPATH_W) '$(srcdir)/comp_bzip2.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_bzip2.Tpo $(DEPDIR)/fsarchiver-comp_bzip2.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_bzip2.c' object='fsarchiver-comp_bzip2.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_bzip2.obj `if test -f 'comp_bzip2.c'; then $(CYGPATH_W) 'comp_bzip2.c'; else $(CYGPATH_W) '$(srcdir)/comp_bzip2.c'; fi` fsarchiver-comp_lzma.o: comp_lzma.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_lzma.o -MD -MP -MF $(DEPDIR)/fsarchiver-comp_lzma.Tpo -c -o fsarchiver-comp_lzma.o `test -f 'comp_lzma.c' || echo '$(srcdir)/'`comp_lzma.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_lzma.Tpo $(DEPDIR)/fsarchiver-comp_lzma.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_lzma.c' object='fsarchiver-comp_lzma.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_lzma.o `test -f 'comp_lzma.c' || echo '$(srcdir)/'`comp_lzma.c fsarchiver-comp_lzma.obj: comp_lzma.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_lzma.obj -MD -MP -MF $(DEPDIR)/fsarchiver-comp_lzma.Tpo -c -o fsarchiver-comp_lzma.obj `if test -f 'comp_lzma.c'; then $(CYGPATH_W) 'comp_lzma.c'; else $(CYGPATH_W) '$(srcdir)/comp_lzma.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_lzma.Tpo $(DEPDIR)/fsarchiver-comp_lzma.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_lzma.c' object='fsarchiver-comp_lzma.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_lzma.obj `if test -f 'comp_lzma.c'; then $(CYGPATH_W) 'comp_lzma.c'; else $(CYGPATH_W) '$(srcdir)/comp_lzma.c'; fi` fsarchiver-comp_lzo.o: comp_lzo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_lzo.o -MD -MP -MF $(DEPDIR)/fsarchiver-comp_lzo.Tpo -c -o fsarchiver-comp_lzo.o `test -f 'comp_lzo.c' || echo '$(srcdir)/'`comp_lzo.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_lzo.Tpo $(DEPDIR)/fsarchiver-comp_lzo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_lzo.c' object='fsarchiver-comp_lzo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_lzo.o `test -f 'comp_lzo.c' || echo '$(srcdir)/'`comp_lzo.c fsarchiver-comp_lzo.obj: comp_lzo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_lzo.obj -MD -MP -MF $(DEPDIR)/fsarchiver-comp_lzo.Tpo -c -o fsarchiver-comp_lzo.obj `if test -f 'comp_lzo.c'; then $(CYGPATH_W) 'comp_lzo.c'; else $(CYGPATH_W) '$(srcdir)/comp_lzo.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_lzo.Tpo $(DEPDIR)/fsarchiver-comp_lzo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_lzo.c' object='fsarchiver-comp_lzo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_lzo.obj `if test -f 'comp_lzo.c'; then $(CYGPATH_W) 'comp_lzo.c'; else $(CYGPATH_W) '$(srcdir)/comp_lzo.c'; fi` fsarchiver-comp_lz4.o: comp_lz4.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_lz4.o -MD -MP -MF $(DEPDIR)/fsarchiver-comp_lz4.Tpo -c -o fsarchiver-comp_lz4.o `test -f 'comp_lz4.c' || echo '$(srcdir)/'`comp_lz4.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_lz4.Tpo $(DEPDIR)/fsarchiver-comp_lz4.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_lz4.c' object='fsarchiver-comp_lz4.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_lz4.o `test -f 'comp_lz4.c' || echo '$(srcdir)/'`comp_lz4.c fsarchiver-comp_lz4.obj: comp_lz4.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_lz4.obj -MD -MP -MF $(DEPDIR)/fsarchiver-comp_lz4.Tpo -c -o fsarchiver-comp_lz4.obj `if test -f 'comp_lz4.c'; then $(CYGPATH_W) 'comp_lz4.c'; else $(CYGPATH_W) '$(srcdir)/comp_lz4.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_lz4.Tpo $(DEPDIR)/fsarchiver-comp_lz4.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_lz4.c' object='fsarchiver-comp_lz4.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_lz4.obj `if test -f 'comp_lz4.c'; then $(CYGPATH_W) 'comp_lz4.c'; else $(CYGPATH_W) '$(srcdir)/comp_lz4.c'; fi` fsarchiver-comp_zstd.o: comp_zstd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_zstd.o -MD -MP -MF $(DEPDIR)/fsarchiver-comp_zstd.Tpo -c -o fsarchiver-comp_zstd.o `test -f 'comp_zstd.c' || echo '$(srcdir)/'`comp_zstd.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_zstd.Tpo $(DEPDIR)/fsarchiver-comp_zstd.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_zstd.c' object='fsarchiver-comp_zstd.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_zstd.o `test -f 'comp_zstd.c' || echo '$(srcdir)/'`comp_zstd.c fsarchiver-comp_zstd.obj: comp_zstd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-comp_zstd.obj -MD -MP -MF $(DEPDIR)/fsarchiver-comp_zstd.Tpo -c -o fsarchiver-comp_zstd.obj `if test -f 'comp_zstd.c'; then $(CYGPATH_W) 'comp_zstd.c'; else $(CYGPATH_W) '$(srcdir)/comp_zstd.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-comp_zstd.Tpo $(DEPDIR)/fsarchiver-comp_zstd.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='comp_zstd.c' object='fsarchiver-comp_zstd.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-comp_zstd.obj `if test -f 'comp_zstd.c'; then $(CYGPATH_W) 'comp_zstd.c'; else $(CYGPATH_W) '$(srcdir)/comp_zstd.c'; fi` fsarchiver-crypto.o: crypto.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-crypto.o -MD -MP -MF $(DEPDIR)/fsarchiver-crypto.Tpo -c -o fsarchiver-crypto.o `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-crypto.Tpo $(DEPDIR)/fsarchiver-crypto.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='crypto.c' object='fsarchiver-crypto.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-crypto.o `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c fsarchiver-crypto.obj: crypto.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-crypto.obj -MD -MP -MF $(DEPDIR)/fsarchiver-crypto.Tpo -c -o fsarchiver-crypto.obj `if test -f 'crypto.c'; then $(CYGPATH_W) 'crypto.c'; else $(CYGPATH_W) '$(srcdir)/crypto.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-crypto.Tpo $(DEPDIR)/fsarchiver-crypto.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='crypto.c' object='fsarchiver-crypto.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-crypto.obj `if test -f 'crypto.c'; then $(CYGPATH_W) 'crypto.c'; else $(CYGPATH_W) '$(srcdir)/crypto.c'; fi` fsarchiver-fs_ntfs.o: fs_ntfs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_ntfs.o -MD -MP -MF $(DEPDIR)/fsarchiver-fs_ntfs.Tpo -c -o fsarchiver-fs_ntfs.o `test -f 'fs_ntfs.c' || echo '$(srcdir)/'`fs_ntfs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_ntfs.Tpo $(DEPDIR)/fsarchiver-fs_ntfs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_ntfs.c' object='fsarchiver-fs_ntfs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_ntfs.o `test -f 'fs_ntfs.c' || echo '$(srcdir)/'`fs_ntfs.c fsarchiver-fs_ntfs.obj: fs_ntfs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_ntfs.obj -MD -MP -MF $(DEPDIR)/fsarchiver-fs_ntfs.Tpo -c -o fsarchiver-fs_ntfs.obj `if test -f 'fs_ntfs.c'; then $(CYGPATH_W) 'fs_ntfs.c'; else $(CYGPATH_W) '$(srcdir)/fs_ntfs.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_ntfs.Tpo $(DEPDIR)/fsarchiver-fs_ntfs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_ntfs.c' object='fsarchiver-fs_ntfs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_ntfs.obj `if test -f 'fs_ntfs.c'; then $(CYGPATH_W) 'fs_ntfs.c'; else $(CYGPATH_W) '$(srcdir)/fs_ntfs.c'; fi` fsarchiver-fs_ext2.o: fs_ext2.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_ext2.o -MD -MP -MF $(DEPDIR)/fsarchiver-fs_ext2.Tpo -c -o fsarchiver-fs_ext2.o `test -f 'fs_ext2.c' || echo '$(srcdir)/'`fs_ext2.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_ext2.Tpo $(DEPDIR)/fsarchiver-fs_ext2.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_ext2.c' object='fsarchiver-fs_ext2.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_ext2.o `test -f 'fs_ext2.c' || echo '$(srcdir)/'`fs_ext2.c fsarchiver-fs_ext2.obj: fs_ext2.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_ext2.obj -MD -MP -MF $(DEPDIR)/fsarchiver-fs_ext2.Tpo -c -o fsarchiver-fs_ext2.obj `if test -f 'fs_ext2.c'; then $(CYGPATH_W) 'fs_ext2.c'; else $(CYGPATH_W) '$(srcdir)/fs_ext2.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_ext2.Tpo $(DEPDIR)/fsarchiver-fs_ext2.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_ext2.c' object='fsarchiver-fs_ext2.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_ext2.obj `if test -f 'fs_ext2.c'; then $(CYGPATH_W) 'fs_ext2.c'; else $(CYGPATH_W) '$(srcdir)/fs_ext2.c'; fi` fsarchiver-fs_reiserfs.o: fs_reiserfs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_reiserfs.o -MD -MP -MF $(DEPDIR)/fsarchiver-fs_reiserfs.Tpo -c -o fsarchiver-fs_reiserfs.o `test -f 'fs_reiserfs.c' || echo '$(srcdir)/'`fs_reiserfs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_reiserfs.Tpo $(DEPDIR)/fsarchiver-fs_reiserfs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_reiserfs.c' object='fsarchiver-fs_reiserfs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_reiserfs.o `test -f 'fs_reiserfs.c' || echo '$(srcdir)/'`fs_reiserfs.c fsarchiver-fs_reiserfs.obj: fs_reiserfs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_reiserfs.obj -MD -MP -MF $(DEPDIR)/fsarchiver-fs_reiserfs.Tpo -c -o fsarchiver-fs_reiserfs.obj `if test -f 'fs_reiserfs.c'; then $(CYGPATH_W) 'fs_reiserfs.c'; else $(CYGPATH_W) '$(srcdir)/fs_reiserfs.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_reiserfs.Tpo $(DEPDIR)/fsarchiver-fs_reiserfs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_reiserfs.c' object='fsarchiver-fs_reiserfs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_reiserfs.obj `if test -f 'fs_reiserfs.c'; then $(CYGPATH_W) 'fs_reiserfs.c'; else $(CYGPATH_W) '$(srcdir)/fs_reiserfs.c'; fi` fsarchiver-fs_reiser4.o: fs_reiser4.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_reiser4.o -MD -MP -MF $(DEPDIR)/fsarchiver-fs_reiser4.Tpo -c -o fsarchiver-fs_reiser4.o `test -f 'fs_reiser4.c' || echo '$(srcdir)/'`fs_reiser4.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_reiser4.Tpo $(DEPDIR)/fsarchiver-fs_reiser4.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_reiser4.c' object='fsarchiver-fs_reiser4.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_reiser4.o `test -f 'fs_reiser4.c' || echo '$(srcdir)/'`fs_reiser4.c fsarchiver-fs_reiser4.obj: fs_reiser4.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_reiser4.obj -MD -MP -MF $(DEPDIR)/fsarchiver-fs_reiser4.Tpo -c -o fsarchiver-fs_reiser4.obj `if test -f 'fs_reiser4.c'; then $(CYGPATH_W) 'fs_reiser4.c'; else $(CYGPATH_W) '$(srcdir)/fs_reiser4.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_reiser4.Tpo $(DEPDIR)/fsarchiver-fs_reiser4.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_reiser4.c' object='fsarchiver-fs_reiser4.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_reiser4.obj `if test -f 'fs_reiser4.c'; then $(CYGPATH_W) 'fs_reiser4.c'; else $(CYGPATH_W) '$(srcdir)/fs_reiser4.c'; fi` fsarchiver-fs_btrfs.o: fs_btrfs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_btrfs.o -MD -MP -MF $(DEPDIR)/fsarchiver-fs_btrfs.Tpo -c -o fsarchiver-fs_btrfs.o `test -f 'fs_btrfs.c' || echo '$(srcdir)/'`fs_btrfs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_btrfs.Tpo $(DEPDIR)/fsarchiver-fs_btrfs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_btrfs.c' object='fsarchiver-fs_btrfs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_btrfs.o `test -f 'fs_btrfs.c' || echo '$(srcdir)/'`fs_btrfs.c fsarchiver-fs_btrfs.obj: fs_btrfs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_btrfs.obj -MD -MP -MF $(DEPDIR)/fsarchiver-fs_btrfs.Tpo -c -o fsarchiver-fs_btrfs.obj `if test -f 'fs_btrfs.c'; then $(CYGPATH_W) 'fs_btrfs.c'; else $(CYGPATH_W) '$(srcdir)/fs_btrfs.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_btrfs.Tpo $(DEPDIR)/fsarchiver-fs_btrfs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_btrfs.c' object='fsarchiver-fs_btrfs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_btrfs.obj `if test -f 'fs_btrfs.c'; then $(CYGPATH_W) 'fs_btrfs.c'; else $(CYGPATH_W) '$(srcdir)/fs_btrfs.c'; fi` fsarchiver-fs_xfs.o: fs_xfs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_xfs.o -MD -MP -MF $(DEPDIR)/fsarchiver-fs_xfs.Tpo -c -o fsarchiver-fs_xfs.o `test -f 'fs_xfs.c' || echo '$(srcdir)/'`fs_xfs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_xfs.Tpo $(DEPDIR)/fsarchiver-fs_xfs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_xfs.c' object='fsarchiver-fs_xfs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_xfs.o `test -f 'fs_xfs.c' || echo '$(srcdir)/'`fs_xfs.c fsarchiver-fs_xfs.obj: fs_xfs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_xfs.obj -MD -MP -MF $(DEPDIR)/fsarchiver-fs_xfs.Tpo -c -o fsarchiver-fs_xfs.obj `if test -f 'fs_xfs.c'; then $(CYGPATH_W) 'fs_xfs.c'; else $(CYGPATH_W) '$(srcdir)/fs_xfs.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_xfs.Tpo $(DEPDIR)/fsarchiver-fs_xfs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_xfs.c' object='fsarchiver-fs_xfs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_xfs.obj `if test -f 'fs_xfs.c'; then $(CYGPATH_W) 'fs_xfs.c'; else $(CYGPATH_W) '$(srcdir)/fs_xfs.c'; fi` fsarchiver-fs_jfs.o: fs_jfs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_jfs.o -MD -MP -MF $(DEPDIR)/fsarchiver-fs_jfs.Tpo -c -o fsarchiver-fs_jfs.o `test -f 'fs_jfs.c' || echo '$(srcdir)/'`fs_jfs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_jfs.Tpo $(DEPDIR)/fsarchiver-fs_jfs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_jfs.c' object='fsarchiver-fs_jfs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_jfs.o `test -f 'fs_jfs.c' || echo '$(srcdir)/'`fs_jfs.c fsarchiver-fs_jfs.obj: fs_jfs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_jfs.obj -MD -MP -MF $(DEPDIR)/fsarchiver-fs_jfs.Tpo -c -o fsarchiver-fs_jfs.obj `if test -f 'fs_jfs.c'; then $(CYGPATH_W) 'fs_jfs.c'; else $(CYGPATH_W) '$(srcdir)/fs_jfs.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_jfs.Tpo $(DEPDIR)/fsarchiver-fs_jfs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_jfs.c' object='fsarchiver-fs_jfs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_jfs.obj `if test -f 'fs_jfs.c'; then $(CYGPATH_W) 'fs_jfs.c'; else $(CYGPATH_W) '$(srcdir)/fs_jfs.c'; fi` fsarchiver-fs_vfat.o: fs_vfat.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_vfat.o -MD -MP -MF $(DEPDIR)/fsarchiver-fs_vfat.Tpo -c -o fsarchiver-fs_vfat.o `test -f 'fs_vfat.c' || echo '$(srcdir)/'`fs_vfat.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_vfat.Tpo $(DEPDIR)/fsarchiver-fs_vfat.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_vfat.c' object='fsarchiver-fs_vfat.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_vfat.o `test -f 'fs_vfat.c' || echo '$(srcdir)/'`fs_vfat.c fsarchiver-fs_vfat.obj: fs_vfat.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-fs_vfat.obj -MD -MP -MF $(DEPDIR)/fsarchiver-fs_vfat.Tpo -c -o fsarchiver-fs_vfat.obj `if test -f 'fs_vfat.c'; then $(CYGPATH_W) 'fs_vfat.c'; else $(CYGPATH_W) '$(srcdir)/fs_vfat.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-fs_vfat.Tpo $(DEPDIR)/fsarchiver-fs_vfat.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fs_vfat.c' object='fsarchiver-fs_vfat.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-fs_vfat.obj `if test -f 'fs_vfat.c'; then $(CYGPATH_W) 'fs_vfat.c'; else $(CYGPATH_W) '$(srcdir)/fs_vfat.c'; fi` fsarchiver-common.o: common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-common.o -MD -MP -MF $(DEPDIR)/fsarchiver-common.Tpo -c -o fsarchiver-common.o `test -f 'common.c' || echo '$(srcdir)/'`common.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-common.Tpo $(DEPDIR)/fsarchiver-common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common.c' object='fsarchiver-common.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-common.o `test -f 'common.c' || echo '$(srcdir)/'`common.c fsarchiver-common.obj: common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-common.obj -MD -MP -MF $(DEPDIR)/fsarchiver-common.Tpo -c -o fsarchiver-common.obj `if test -f 'common.c'; then $(CYGPATH_W) 'common.c'; else $(CYGPATH_W) '$(srcdir)/common.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-common.Tpo $(DEPDIR)/fsarchiver-common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common.c' object='fsarchiver-common.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-common.obj `if test -f 'common.c'; then $(CYGPATH_W) 'common.c'; else $(CYGPATH_W) '$(srcdir)/common.c'; fi` fsarchiver-dico.o: dico.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-dico.o -MD -MP -MF $(DEPDIR)/fsarchiver-dico.Tpo -c -o fsarchiver-dico.o `test -f 'dico.c' || echo '$(srcdir)/'`dico.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-dico.Tpo $(DEPDIR)/fsarchiver-dico.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dico.c' object='fsarchiver-dico.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-dico.o `test -f 'dico.c' || echo '$(srcdir)/'`dico.c fsarchiver-dico.obj: dico.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-dico.obj -MD -MP -MF $(DEPDIR)/fsarchiver-dico.Tpo -c -o fsarchiver-dico.obj `if test -f 'dico.c'; then $(CYGPATH_W) 'dico.c'; else $(CYGPATH_W) '$(srcdir)/dico.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-dico.Tpo $(DEPDIR)/fsarchiver-dico.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dico.c' object='fsarchiver-dico.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-dico.obj `if test -f 'dico.c'; then $(CYGPATH_W) 'dico.c'; else $(CYGPATH_W) '$(srcdir)/dico.c'; fi` fsarchiver-strdico.o: strdico.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-strdico.o -MD -MP -MF $(DEPDIR)/fsarchiver-strdico.Tpo -c -o fsarchiver-strdico.o `test -f 'strdico.c' || echo '$(srcdir)/'`strdico.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-strdico.Tpo $(DEPDIR)/fsarchiver-strdico.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strdico.c' object='fsarchiver-strdico.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-strdico.o `test -f 'strdico.c' || echo '$(srcdir)/'`strdico.c fsarchiver-strdico.obj: strdico.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-strdico.obj -MD -MP -MF $(DEPDIR)/fsarchiver-strdico.Tpo -c -o fsarchiver-strdico.obj `if test -f 'strdico.c'; then $(CYGPATH_W) 'strdico.c'; else $(CYGPATH_W) '$(srcdir)/strdico.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-strdico.Tpo $(DEPDIR)/fsarchiver-strdico.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strdico.c' object='fsarchiver-strdico.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-strdico.obj `if test -f 'strdico.c'; then $(CYGPATH_W) 'strdico.c'; else $(CYGPATH_W) '$(srcdir)/strdico.c'; fi` fsarchiver-dichl.o: dichl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-dichl.o -MD -MP -MF $(DEPDIR)/fsarchiver-dichl.Tpo -c -o fsarchiver-dichl.o `test -f 'dichl.c' || echo '$(srcdir)/'`dichl.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-dichl.Tpo $(DEPDIR)/fsarchiver-dichl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dichl.c' object='fsarchiver-dichl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-dichl.o `test -f 'dichl.c' || echo '$(srcdir)/'`dichl.c fsarchiver-dichl.obj: dichl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-dichl.obj -MD -MP -MF $(DEPDIR)/fsarchiver-dichl.Tpo -c -o fsarchiver-dichl.obj `if test -f 'dichl.c'; then $(CYGPATH_W) 'dichl.c'; else $(CYGPATH_W) '$(srcdir)/dichl.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-dichl.Tpo $(DEPDIR)/fsarchiver-dichl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dichl.c' object='fsarchiver-dichl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-dichl.obj `if test -f 'dichl.c'; then $(CYGPATH_W) 'dichl.c'; else $(CYGPATH_W) '$(srcdir)/dichl.c'; fi` fsarchiver-queue.o: queue.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-queue.o -MD -MP -MF $(DEPDIR)/fsarchiver-queue.Tpo -c -o fsarchiver-queue.o `test -f 'queue.c' || echo '$(srcdir)/'`queue.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-queue.Tpo $(DEPDIR)/fsarchiver-queue.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='queue.c' object='fsarchiver-queue.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-queue.o `test -f 'queue.c' || echo '$(srcdir)/'`queue.c fsarchiver-queue.obj: queue.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-queue.obj -MD -MP -MF $(DEPDIR)/fsarchiver-queue.Tpo -c -o fsarchiver-queue.obj `if test -f 'queue.c'; then $(CYGPATH_W) 'queue.c'; else $(CYGPATH_W) '$(srcdir)/queue.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-queue.Tpo $(DEPDIR)/fsarchiver-queue.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='queue.c' object='fsarchiver-queue.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-queue.obj `if test -f 'queue.c'; then $(CYGPATH_W) 'queue.c'; else $(CYGPATH_W) '$(srcdir)/queue.c'; fi` fsarchiver-error.o: error.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-error.o -MD -MP -MF $(DEPDIR)/fsarchiver-error.Tpo -c -o fsarchiver-error.o `test -f 'error.c' || echo '$(srcdir)/'`error.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-error.Tpo $(DEPDIR)/fsarchiver-error.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='error.c' object='fsarchiver-error.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-error.o `test -f 'error.c' || echo '$(srcdir)/'`error.c fsarchiver-error.obj: error.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-error.obj -MD -MP -MF $(DEPDIR)/fsarchiver-error.Tpo -c -o fsarchiver-error.obj `if test -f 'error.c'; then $(CYGPATH_W) 'error.c'; else $(CYGPATH_W) '$(srcdir)/error.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-error.Tpo $(DEPDIR)/fsarchiver-error.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='error.c' object='fsarchiver-error.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-error.obj `if test -f 'error.c'; then $(CYGPATH_W) 'error.c'; else $(CYGPATH_W) '$(srcdir)/error.c'; fi` fsarchiver-syncthread.o: syncthread.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-syncthread.o -MD -MP -MF $(DEPDIR)/fsarchiver-syncthread.Tpo -c -o fsarchiver-syncthread.o `test -f 'syncthread.c' || echo '$(srcdir)/'`syncthread.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-syncthread.Tpo $(DEPDIR)/fsarchiver-syncthread.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='syncthread.c' object='fsarchiver-syncthread.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-syncthread.o `test -f 'syncthread.c' || echo '$(srcdir)/'`syncthread.c fsarchiver-syncthread.obj: syncthread.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-syncthread.obj -MD -MP -MF $(DEPDIR)/fsarchiver-syncthread.Tpo -c -o fsarchiver-syncthread.obj `if test -f 'syncthread.c'; then $(CYGPATH_W) 'syncthread.c'; else $(CYGPATH_W) '$(srcdir)/syncthread.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-syncthread.Tpo $(DEPDIR)/fsarchiver-syncthread.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='syncthread.c' object='fsarchiver-syncthread.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-syncthread.obj `if test -f 'syncthread.c'; then $(CYGPATH_W) 'syncthread.c'; else $(CYGPATH_W) '$(srcdir)/syncthread.c'; fi` fsarchiver-datafile.o: datafile.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-datafile.o -MD -MP -MF $(DEPDIR)/fsarchiver-datafile.Tpo -c -o fsarchiver-datafile.o `test -f 'datafile.c' || echo '$(srcdir)/'`datafile.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-datafile.Tpo $(DEPDIR)/fsarchiver-datafile.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='datafile.c' object='fsarchiver-datafile.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-datafile.o `test -f 'datafile.c' || echo '$(srcdir)/'`datafile.c fsarchiver-datafile.obj: datafile.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-datafile.obj -MD -MP -MF $(DEPDIR)/fsarchiver-datafile.Tpo -c -o fsarchiver-datafile.obj `if test -f 'datafile.c'; then $(CYGPATH_W) 'datafile.c'; else $(CYGPATH_W) '$(srcdir)/datafile.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-datafile.Tpo $(DEPDIR)/fsarchiver-datafile.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='datafile.c' object='fsarchiver-datafile.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-datafile.obj `if test -f 'datafile.c'; then $(CYGPATH_W) 'datafile.c'; else $(CYGPATH_W) '$(srcdir)/datafile.c'; fi` fsarchiver-strlist.o: strlist.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-strlist.o -MD -MP -MF $(DEPDIR)/fsarchiver-strlist.Tpo -c -o fsarchiver-strlist.o `test -f 'strlist.c' || echo '$(srcdir)/'`strlist.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-strlist.Tpo $(DEPDIR)/fsarchiver-strlist.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strlist.c' object='fsarchiver-strlist.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-strlist.o `test -f 'strlist.c' || echo '$(srcdir)/'`strlist.c fsarchiver-strlist.obj: strlist.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-strlist.obj -MD -MP -MF $(DEPDIR)/fsarchiver-strlist.Tpo -c -o fsarchiver-strlist.obj `if test -f 'strlist.c'; then $(CYGPATH_W) 'strlist.c'; else $(CYGPATH_W) '$(srcdir)/strlist.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-strlist.Tpo $(DEPDIR)/fsarchiver-strlist.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strlist.c' object='fsarchiver-strlist.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-strlist.obj `if test -f 'strlist.c'; then $(CYGPATH_W) 'strlist.c'; else $(CYGPATH_W) '$(srcdir)/strlist.c'; fi` fsarchiver-regmulti.o: regmulti.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-regmulti.o -MD -MP -MF $(DEPDIR)/fsarchiver-regmulti.Tpo -c -o fsarchiver-regmulti.o `test -f 'regmulti.c' || echo '$(srcdir)/'`regmulti.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-regmulti.Tpo $(DEPDIR)/fsarchiver-regmulti.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regmulti.c' object='fsarchiver-regmulti.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-regmulti.o `test -f 'regmulti.c' || echo '$(srcdir)/'`regmulti.c fsarchiver-regmulti.obj: regmulti.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-regmulti.obj -MD -MP -MF $(DEPDIR)/fsarchiver-regmulti.Tpo -c -o fsarchiver-regmulti.obj `if test -f 'regmulti.c'; then $(CYGPATH_W) 'regmulti.c'; else $(CYGPATH_W) '$(srcdir)/regmulti.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-regmulti.Tpo $(DEPDIR)/fsarchiver-regmulti.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regmulti.c' object='fsarchiver-regmulti.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-regmulti.obj `if test -f 'regmulti.c'; then $(CYGPATH_W) 'regmulti.c'; else $(CYGPATH_W) '$(srcdir)/regmulti.c'; fi` fsarchiver-options.o: options.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-options.o -MD -MP -MF $(DEPDIR)/fsarchiver-options.Tpo -c -o fsarchiver-options.o `test -f 'options.c' || echo '$(srcdir)/'`options.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-options.Tpo $(DEPDIR)/fsarchiver-options.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='options.c' object='fsarchiver-options.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-options.o `test -f 'options.c' || echo '$(srcdir)/'`options.c fsarchiver-options.obj: options.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-options.obj -MD -MP -MF $(DEPDIR)/fsarchiver-options.Tpo -c -o fsarchiver-options.obj `if test -f 'options.c'; then $(CYGPATH_W) 'options.c'; else $(CYGPATH_W) '$(srcdir)/options.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-options.Tpo $(DEPDIR)/fsarchiver-options.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='options.c' object='fsarchiver-options.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-options.obj `if test -f 'options.c'; then $(CYGPATH_W) 'options.c'; else $(CYGPATH_W) '$(srcdir)/options.c'; fi` fsarchiver-logfile.o: logfile.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-logfile.o -MD -MP -MF $(DEPDIR)/fsarchiver-logfile.Tpo -c -o fsarchiver-logfile.o `test -f 'logfile.c' || echo '$(srcdir)/'`logfile.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-logfile.Tpo $(DEPDIR)/fsarchiver-logfile.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='logfile.c' object='fsarchiver-logfile.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-logfile.o `test -f 'logfile.c' || echo '$(srcdir)/'`logfile.c fsarchiver-logfile.obj: logfile.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-logfile.obj -MD -MP -MF $(DEPDIR)/fsarchiver-logfile.Tpo -c -o fsarchiver-logfile.obj `if test -f 'logfile.c'; then $(CYGPATH_W) 'logfile.c'; else $(CYGPATH_W) '$(srcdir)/logfile.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-logfile.Tpo $(DEPDIR)/fsarchiver-logfile.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='logfile.c' object='fsarchiver-logfile.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-logfile.obj `if test -f 'logfile.c'; then $(CYGPATH_W) 'logfile.c'; else $(CYGPATH_W) '$(srcdir)/logfile.c'; fi` fsarchiver-filesys.o: filesys.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-filesys.o -MD -MP -MF $(DEPDIR)/fsarchiver-filesys.Tpo -c -o fsarchiver-filesys.o `test -f 'filesys.c' || echo '$(srcdir)/'`filesys.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-filesys.Tpo $(DEPDIR)/fsarchiver-filesys.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='filesys.c' object='fsarchiver-filesys.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-filesys.o `test -f 'filesys.c' || echo '$(srcdir)/'`filesys.c fsarchiver-filesys.obj: filesys.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-filesys.obj -MD -MP -MF $(DEPDIR)/fsarchiver-filesys.Tpo -c -o fsarchiver-filesys.obj `if test -f 'filesys.c'; then $(CYGPATH_W) 'filesys.c'; else $(CYGPATH_W) '$(srcdir)/filesys.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-filesys.Tpo $(DEPDIR)/fsarchiver-filesys.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='filesys.c' object='fsarchiver-filesys.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-filesys.obj `if test -f 'filesys.c'; then $(CYGPATH_W) 'filesys.c'; else $(CYGPATH_W) '$(srcdir)/filesys.c'; fi` fsarchiver-devinfo.o: devinfo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-devinfo.o -MD -MP -MF $(DEPDIR)/fsarchiver-devinfo.Tpo -c -o fsarchiver-devinfo.o `test -f 'devinfo.c' || echo '$(srcdir)/'`devinfo.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-devinfo.Tpo $(DEPDIR)/fsarchiver-devinfo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='devinfo.c' object='fsarchiver-devinfo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-devinfo.o `test -f 'devinfo.c' || echo '$(srcdir)/'`devinfo.c fsarchiver-devinfo.obj: devinfo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -MT fsarchiver-devinfo.obj -MD -MP -MF $(DEPDIR)/fsarchiver-devinfo.Tpo -c -o fsarchiver-devinfo.obj `if test -f 'devinfo.c'; then $(CYGPATH_W) 'devinfo.c'; else $(CYGPATH_W) '$(srcdir)/devinfo.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsarchiver-devinfo.Tpo $(DEPDIR)/fsarchiver-devinfo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='devinfo.c' object='fsarchiver-devinfo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(fsarchiver_CFLAGS) $(CFLAGS) -c -o fsarchiver-devinfo.obj `if test -f 'devinfo.c'; then $(CYGPATH_W) 'devinfo.c'; else $(CYGPATH_W) '$(srcdir)/devinfo.c'; fi` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-sbinPROGRAMS .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: fsarchiver-0.8.5/src/devinfo.h0000644000176100017610000000214013242523705013177 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __DEVINFO_H__ #define __DEVINFO_H__ enum {BLKDEV_INVALID=-1, BLKDEV_PHYSDISK=0, BLKDEV_FILESYSDEV=1}; struct s_devinfo { int devtype; char devname[FSA_MAX_DEVLEN]; char longname[FSA_MAX_DEVLEN]; char label[FSA_MAX_LABELLEN]; char uuid[FSA_MAX_UUIDLEN]; char fsname[FSA_MAX_FSNAMELEN]; char name[512]; char txtsize[64]; u64 devsize; int minor; int major; u64 rdev; }; int get_devinfo(struct s_devinfo *outdev, char *indevname, int min, int maj); #endif // __DEVINFO_H__ fsarchiver-0.8.5/src/fs_xfs.c0000644000176100017610000004026013311020201013011 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include "fsarchiver.h" #include "dico.h" #include "common.h" #include "fs_xfs.h" #include "filesys.h" #include "strlist.h" #include "error.h" int xfs_check_compatibility(u64 compat, u64 ro_compat, u64 incompat, u64 log_incompat) { int errors=0; msgprintf(MSG_DEBUG1, "xfs features: compat=[%ld]\n", (long)compat); msgprintf(MSG_DEBUG1, "xfs features: ro_compat=[%ld]\n", (long)ro_compat); msgprintf(MSG_DEBUG1, "xfs features: incompat=[%ld]\n", (long)incompat); msgprintf(MSG_DEBUG1, "xfs features: log_incompat=[%ld]\n", (long)log_incompat); // to preserve the filesystem attributes, fsa must know all the features including the COMPAT ones if (compat & ~FSA_XFS_FEATURE_COMPAT_SUPP) errors++; if (ro_compat & ~FSA_XFS_FEATURE_RO_COMPAT_SUPP) errors++; if (incompat & ~FSA_XFS_FEATURE_INCOMPAT_SUPP) errors++; if (log_incompat & ~FSA_XFS_FEATURE_LOG_INCOMPAT_SUPP) errors++; if (errors > 0) { errprintf("this filesystem has XFS features which are not supported by this fsarchiver version.\n"); return -1; } else { return 0; } } int xfs_mkfs(cdico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid) { char stdoutbuf[2048]; char command[2048]; char buffer[2048]; char mkfsopts[2048]; char xadmopts[2048]; char uuid[64]; u64 xfstoolsver; int exitst; u64 temp64; u64 xfsver; int x, y, z; int optval; u64 sb_features_compat=0; u64 sb_features_ro_compat=0; u64 sb_features_incompat=0; u64 sb_features_log_incompat=0; // ---- check that mkfs is installed and get its version if (exec_command(command, sizeof(command), NULL, stdoutbuf, sizeof(stdoutbuf), NULL, 0, "mkfs.xfs -V")!=0) { errprintf("mkfs.xfs not found. please install xfsprogs on your system or check the PATH.\n"); return -1; } x=y=z=0; sscanf(stdoutbuf, "mkfs.xfs version %d.%d.%d", &x, &y, &z); if (x==0 && y==0) { errprintf("Can't parse mkfs.xfs version number: x=y=0\n"); return -1; } xfstoolsver=PROGVER(x,y,z); msgprintf(MSG_VERB2, "Detected mkfs.xfs version %d.%d.%d\n", x, y, z); memset(mkfsopts, 0, sizeof(mkfsopts)); memset(xadmopts, 0, sizeof(xadmopts)); memset(uuid, 0, sizeof(uuid)); strlcatf(mkfsopts, sizeof(mkfsopts), " %s ", fsoptions); if (strlen(mkfslabel) > 0) strlcatf(mkfsopts, sizeof(mkfsopts), " -L '%.12s' ", mkfslabel); else if (dico_get_string(d, 0, FSYSHEADKEY_FSLABEL, buffer, sizeof(buffer))==0 && strlen(buffer)>0) strlcatf(mkfsopts, sizeof(mkfsopts), " -L '%.12s' ", buffer); if ((dico_get_u64(d, 0, FSYSHEADKEY_FSXFSBLOCKSIZE, &temp64)==0) && (temp64%512==0) && (temp64>=512) && (temp64<=65536)) strlcatf(mkfsopts, sizeof(mkfsopts), " -b size=%ld ", (long)temp64); // ---- get xfs features attributes from the archive dico_get_u64(d, 0, FSYSHEADKEY_FSXFSFEATURECOMPAT, &sb_features_compat); dico_get_u64(d, 0, FSYSHEADKEY_FSXFSFEATUREROCOMPAT, &sb_features_ro_compat); dico_get_u64(d, 0, FSYSHEADKEY_FSXFSFEATUREINCOMPAT, &sb_features_incompat); dico_get_u64(d, 0, FSYSHEADKEY_FSXFSFEATURELOGINCOMPAT, &sb_features_log_incompat); // ---- check fsarchiver is aware of all the filesystem features used on that filesystem if (xfs_check_compatibility(sb_features_compat, sb_features_ro_compat, sb_features_incompat, sb_features_log_incompat)!=0) return -1; // Preserve version 4 of XFS if the original filesystem was an XFSv4 or if // it was saved with fsarchiver <= 0.6.19 which does not store the XFS // version in the metadata: make an XFSv4 if unsure for better compatibility, // as upgrading later is easier than downgrading if ((dico_get_u64(d, 0, FSYSHEADKEY_FSXFSVERSION, &temp64)!=0) || (temp64==XFS_SB_VERSION_4)) xfsver = XFS_SB_VERSION_4; else xfsver = XFS_SB_VERSION_5; // Unfortunately it is impossible to preserve the UUID (stamped on every // metadata block) of an XFSv5 filesystem with mkfs.xfs < 4.3.0. // Restoring with a new random UUID would work but could prevent the system // from booting if this is a boot/root filesystem because grub/fstab often // use the UUID to identify it. Hence it is much safer to restore it as an // XFSv4 and it also provides a better compatibility with older kernels. // Hence this is the safest option. // More details: https://github.com/fdupoux/fsarchiver/issues/4 if ((xfsver==XFS_SB_VERSION_5) && (xfstoolsver < PROGVER(4,3,0))) { xfsver = XFS_SB_VERSION_4; // Do not preserve the XFS version msgprintf(MSG_FORCE, "It is impossible to restore this filesystem as an XFSv5 and preserve its UUID\n" "with mkfs.xfs < 4.3.0. This filesystem will be restored as an XFSv4 instead\n" "as this is a much safer option (preserving the UUID may be required on\n" "boot/root filesystems for the operating system to be able to start). If you\n" "really want to have an XFSv5 filesystem, please upgrade xfsprogs to version\n" "4.3.0 or more recent and rerun this operation to get an XFSv5 with the same\n" "UUID as original filesystem\n"); } // Determine if the "crc" mkfs option should be enabled (checksum) // - checksum must be disabled if we want to recreate an XFSv4 filesystem // - checksum must be enabled if we want to recreate an XFSv5 filesystem if (xfstoolsver >= PROGVER(3,2,0)) // only use "crc" option when it is supported by mkfs { optval = (xfsver==XFS_SB_VERSION_5); strlcatf(mkfsopts, sizeof(mkfsopts), " -m crc=%d ", (int)optval); } // Determine if the "finobt" mkfs option should be enabled (free inode btree) // - starting with linux-3.16 XFS has added a btree that tracks free inodes // - this feature relies on the new v5 on-disk format but it is optional // - this feature is enabled by default when using xfsprogs 3.2.3 or later // - this feature will be enabled if the original filesystem was XFSv5 and had it if (xfstoolsver >= PROGVER(3,2,1)) // only use "finobt" option when it is supported by mkfs { optval = ((xfsver==XFS_SB_VERSION_5) && (sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_FINOBT)); strlcatf(mkfsopts, sizeof(mkfsopts), " -m finobt=%d ", (int)optval); } // Determine if the "rmapbt" mkfs option should be enabled (reverse mapping btree) // - starting with linux-4.8 XFS has added a btree that maps filesystem blocks // to their owner // - this feature relies on the new v5 on-disk format but it is optional // - this feature will be enabled if the original filesystem was XFSv5 and had it if (xfstoolsver >= PROGVER(4,8,0)) // only use "rmapbt" option when it is supported by mkfs { optval = ((xfsver==XFS_SB_VERSION_5) && (sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_RMAPBT)); strlcatf(mkfsopts, sizeof(mkfsopts), " -m rmapbt=%d ", (int)optval); } // Determine if the "reflink" mkfs option should be enabled // - starting with linux-4.9 XFS has added support for reflinked files // - this feature relies on the new v5 on-disk format but it is optional // - this feature will be enabled if the original filesystem was XFSv5 and had it if (xfstoolsver >= PROGVER(4,9,0)) // only use "reflink" option when it is supported by mkfs { optval = ((xfsver==XFS_SB_VERSION_5) && (sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_REFLINK)); strlcatf(mkfsopts, sizeof(mkfsopts), " -m reflink=%d ", (int)optval); } // Attempt to preserve UUID of the filesystem // - the "-m uuid=" option in mkfs.xfs was added in mkfs.xfs 4.3.0 and is the best way to set UUIDs // - the UUID of XFSv4 can be successfully set using either xfs_admin or mkfs.xfs >= 4.3.0 // - it is impossible to set both types of UUIDs of an XFSv5 filesystem using xfsprogs < 4.3.0 // for this reason the XFS version is forced to v4 if xfsprogs version < 4.3.0 if (strlen(mkfsuuid) > 0) snprintf(uuid, sizeof(uuid), "%s", mkfsuuid); else if (dico_get_string(d, 0, FSYSHEADKEY_FSUUID, buffer, sizeof(buffer))==0) snprintf(uuid, sizeof(uuid), "%s", buffer); if (strlen(uuid)==36) { if (xfstoolsver >= PROGVER(4,3,0)) strlcatf(mkfsopts, sizeof(mkfsopts), " -m uuid=%s ", uuid); else strlcatf(xadmopts, sizeof(xadmopts), " -U %s ", uuid); } // Determine if the "ftype" mkfs option should be enabled (filetype in dirent) // - this feature allows the inode type to be stored in the directory structure // - mkfs.xfs 4.2.0 enabled ftype by default (supported since mkfs.xfs 3.2.0) for XFSv4 volumes // - when CRCs are enabled via -m crc=1, the ftype functionality is always enabled // - ftype is madatory in XFSv5 volumes but it is optional for XFSv4 volumes // - the "ftype" option must be specified after the "crc" option in mkfs.xfs < 4.2.0: // https://git.kernel.org/cgit/fs/xfs/xfsprogs-dev.git/commit/?id=b990de8ba4e2df2bc76a140799d3ddb4a0eac4ce // - do not set ftype=1 with crc=1 as mkfs.xfs may fail when both options are enabled (at least with xfsprogs-3.2.2) // - XFSv4 with ftype=1 is supported since linux-3.13. We purposely always // disable ftype for V4 volumes to keep them compatible with older kernels if (xfstoolsver >= PROGVER(3,2,0)) // only use "ftype" option when it is supported by mkfs { // ftype is already set to 1 when it is XFSv5 if (xfsver==XFS_SB_VERSION_4) strlcatf(mkfsopts, sizeof(mkfsopts), " -n ftype=0 "); } // Determine if the "sparse" mkfs option should be enabled (sparse inode allocation) // - starting with linux-4.2 XFS can allocate discontinuous inode chunks // - this feature relies on the new v5 on-disk format but it is optional // - this feature is enabled by default when using xfsprogs 4.16.0 or later // - this feature will be enabled if the original filesystem was XFSv5 and had it // - this feature is supported since mkfs.xfs 4.2.0, but unfortunately // mkfs.xfs 4.5.0 in RHEL 7.3 carries a custom patch removing the option, // hence require mkfs.xfs 4.7.0, next version after 4.5.0 if (xfstoolsver >= PROGVER(4,7,0)) // only use "sparse" option when it is supported by mkfs { optval = ((xfsver==XFS_SB_VERSION_5) && (sb_features_incompat & XFS_SB_FEAT_INCOMPAT_SPINODES)); strlcatf(mkfsopts, sizeof(mkfsopts), " -i sparse=%d ", (int)optval); } // ---- create the new filesystem using mkfs.xfs if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "mkfs.xfs -f %s %s", partition, mkfsopts)!=0 || exitst!=0) { errprintf("command [%s] failed\n", command); return -1; } // ---- use xfs_admin to set the UUID if not already done with mkfs.xfs if (xadmopts[0]) { if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "xfs_admin %s %s", xadmopts, partition)!=0 || exitst!=-0) { errprintf("command [%s] failed\n", command); return -1; } } return 0; } int xfs_getinfo(cdico *d, char *devname) { struct xfs_sb sb; char uuid[512]; u64 xfsver; u32 temp32; int ret=0; int fd; int res; u64 sb_features_compat=0; u64 sb_features_ro_compat=0; u64 sb_features_incompat=0; u64 sb_features_log_incompat=0; if ((fd=open64(devname, O_RDONLY|O_LARGEFILE))<0) { ret=-1; goto xfs_read_sb_return; } res=read(fd, &sb, sizeof(sb)); if (res!=sizeof(sb)) { ret=-1; goto xfs_read_sb_close; } // ---- check it's an XFS file system if (be32_to_cpu(sb.sb_magicnum) != XFS_SB_MAGIC) { ret=-1; msgprintf(3, "sb.sb_magicnum!=XFS_SB_MAGIC\n"); goto xfs_read_sb_close; } // ---- check XFS filesystem version xfsver=be16_to_cpu(sb.sb_versionnum) & XFS_SB_VERSION_NUMBITS; switch (xfsver) { case XFS_SB_VERSION_4: case XFS_SB_VERSION_5: msgprintf(MSG_DEBUG1, "Detected XFS filesystem version %d\n", (int)xfsver); dico_add_u64(d, 0, FSYSHEADKEY_FSXFSVERSION, xfsver); break; default: ret=-1; msgprintf(MSG_STACK, "Invalid XFS filesystem version: version=[%d]\n", (int)xfsver); goto xfs_read_sb_close; break; } // ---- label msgprintf(MSG_DEBUG1, "xfs_label=[%s]\n", sb.sb_fname); dico_add_string(d, 0, FSYSHEADKEY_FSLABEL, (char*)sb.sb_fname); // ---- uuid /*if ((str=e2p_uuid2str(&sb.sb_uuid))!=NULL) dico_add_string(d, 0, FSYSHEADKEY_FSUUID, str);*/ memset(uuid, 0, sizeof(uuid)); uuid_unparse_lower((u8*)&sb.sb_uuid, uuid); dico_add_string(d, 0, FSYSHEADKEY_FSUUID, uuid); msgprintf(MSG_DEBUG1, "xfs_uuid=[%s]\n", uuid); // ---- block size temp32=be32_to_cpu(sb.sb_blocksize); if ((temp32%512!=0) || (temp32<512) || (temp32>65536)) { ret=-1; msgprintf(3, "xfs_blksize=[%ld] is an invalid xfs block size\n", (long)temp32); goto xfs_read_sb_close; } dico_add_u64(d, 0, FSYSHEADKEY_FSXFSBLOCKSIZE, temp32); msgprintf(MSG_DEBUG1, "xfs_blksize=[%ld]\n", (long)temp32); // ---- get filesystem features (will all be set to 0 if this is an XFSv4) if (xfsver == XFS_SB_VERSION_5) { sb_features_compat=be32_to_cpu(sb.sb_features_compat); sb_features_ro_compat=be32_to_cpu(sb.sb_features_ro_compat); sb_features_incompat=be32_to_cpu(sb.sb_features_incompat); sb_features_log_incompat=be32_to_cpu(sb.sb_features_log_incompat); } // ---- check fsarchiver is aware of all the filesystem features used on that filesystem if (xfs_check_compatibility(sb_features_compat, sb_features_ro_compat, sb_features_incompat, sb_features_log_incompat)!=0) return -1; // ---- store features in the archive metadata dico_add_u64(d, 0, FSYSHEADKEY_FSXFSFEATURECOMPAT, (u64)sb_features_compat); dico_add_u64(d, 0, FSYSHEADKEY_FSXFSFEATUREROCOMPAT, (u64)sb_features_ro_compat); dico_add_u64(d, 0, FSYSHEADKEY_FSXFSFEATUREINCOMPAT, (u64)sb_features_incompat); dico_add_u64(d, 0, FSYSHEADKEY_FSXFSFEATURELOGINCOMPAT, (u64)sb_features_log_incompat); // ---- minimum fsarchiver version required to restore dico_add_u64(d, 0, FSYSHEADKEY_MINFSAVERSION, FSA_VERSION_BUILD(0, 6, 20, 0)); xfs_read_sb_close: close(fd); xfs_read_sb_return: return ret; } int xfs_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo) { return generic_mount(partition, mntbuf, fsbuf, "nouuid", flags); } int xfs_umount(char *partition, char *mntbuf) { return generic_umount(mntbuf); } int xfs_test(char *devname) { struct xfs_sb sb; int fd; if ((fd=open64(devname, O_RDONLY|O_LARGEFILE))<0) { msgprintf(MSG_DEBUG1, "open64(%s) failed\n", devname); return false; } memset(&sb, 0, sizeof(sb)); if (read(fd, &sb, sizeof(sb))!=sizeof(sb)) { close(fd); msgprintf(MSG_DEBUG1, "read failed\n"); return false; } // ---- check it's an XFS file system if (be32_to_cpu(sb.sb_magicnum) != XFS_SB_MAGIC) { close(fd); msgprintf(MSG_DEBUG1, "(be32_to_cpu(sb.sb_magicnum)=%.8x) != (XFS_SB_MAGIC=%.8x)\n", be32_to_cpu(sb.sb_magicnum), XFS_SB_MAGIC); return false; } close(fd); return true; } int xfs_get_reqmntopt(char *partition, cstrlist *reqopt, cstrlist *badopt) { if (!reqopt || !badopt) return -1; return 0; } fsarchiver-0.8.5/src/comp_lzo.c0000644000176100017610000000360113242523705013365 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "fsarchiver.h" #include "comp_lzo.h" #include "error.h" #ifdef OPTION_LZO_SUPPORT int compress_block_lzo(u64 origsize, u64 *compsize, u8 *origbuf, u8 *compbuf, u64 compbufsize, int level) { lzo_uint destsize=(lzo_uint)compbufsize; char workmem[LZO1X_1_MEM_COMPRESS]; switch (lzo1x_1_compress((lzo_bytep)origbuf, (lzo_uint)origsize, (lzo_bytep)compbuf, (lzo_uintp)&destsize, (lzo_voidp)workmem)) { case LZO_E_OK: *compsize=(u64)destsize; return FSAERR_SUCCESS; case LZO_E_OUT_OF_MEMORY: return FSAERR_ENOMEM; default: return FSAERR_UNKNOWN; } return FSAERR_UNKNOWN; } int uncompress_block_lzo(u64 compsize, u64 *origsize, u8 *origbuf, u64 origbufsize, u8 *compbuf) { lzo_uint new_len=origbufsize; int res; switch ((res=lzo1x_decompress_safe(compbuf, compsize, origbuf, &new_len, NULL))) { case LZO_E_OK: *origsize=(u64)new_len; return FSAERR_SUCCESS; case LZO_E_OUT_OF_MEMORY: return FSAERR_ENOMEM; default: errprintf("lzo1x_decompress_safe() failed, res=%d\n", res); return FSAERR_UNKNOWN; } return FSAERR_UNKNOWN; } #endif // OPTION_LZO_SUPPORT fsarchiver-0.8.5/src/thread_comp.c0000644000176100017610000003251613242523705014037 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include "fsarchiver.h" #include "common.h" #include "options.h" #include "comp_gzip.h" #include "comp_bzip2.h" #include "comp_lzma.h" #include "comp_lzo.h" #include "comp_lz4.h" #include "comp_zstd.h" #include "crypto.h" #include "syncthread.h" #include "thread_comp.h" #include "error.h" #include "queue.h" int compress_block_generic(struct s_blockinfo *blkinfo) { char *bufcomp=NULL; int attempt=0; int compalgo; int complevel; u64 compsize; u64 bufsize; int res; bufsize = (blkinfo->blkrealsize) + (blkinfo->blkrealsize / 16) + 64 + 3; // alloc bigger buffer else lzo will crash if ((bufcomp=malloc(bufsize))==NULL) { errprintf("malloc(%ld) failed: out of memory\n", (long)bufsize); return -1; } // compression level/algo to use for the first attempt compalgo=g_options.compressalgo; complevel=g_options.compresslevel; // compress the block do { switch (compalgo) { #ifdef OPTION_LZO_SUPPORT case COMPRESS_LZO: res=compress_block_lzo(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel); blkinfo->blkcompalgo=COMPRESS_LZO; break; #endif // OPTION_LZO_SUPPORT case COMPRESS_GZIP: res=compress_block_gzip(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel); blkinfo->blkcompalgo=COMPRESS_GZIP; break; case COMPRESS_BZIP2: res=compress_block_bzip2(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel); blkinfo->blkcompalgo=COMPRESS_BZIP2; break; #ifdef OPTION_LZMA_SUPPORT case COMPRESS_LZMA: res=compress_block_lzma(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel); blkinfo->blkcompalgo=COMPRESS_LZMA; break; #endif // OPTION_LZMA_SUPPORT #ifdef OPTION_LZ4_SUPPORT case COMPRESS_LZ4: res=compress_block_lz4(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel); blkinfo->blkcompalgo=COMPRESS_LZ4; break; #endif // OPTION_LZ4_SUPPORT #ifdef OPTION_ZSTD_SUPPORT case COMPRESS_ZSTD: res=compress_block_zstd(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel); blkinfo->blkcompalgo=COMPRESS_ZSTD; break; #endif // OPTION_ZSTD_SUPPORT default: free(bufcomp); msgprintf(2, "invalid compression level: %d\n", (int)compalgo); return -1; } // retry if high compression was used and compression failed because of FSAERR_ENOMEM if ((res == FSAERR_ENOMEM) && (compalgo > FSA_DEF_COMPRESS_ALGO)) { errprintf("attempt to compress the current block using an alternative algorithm (\"-z%d\")\n", FSA_DEF_COMPRESS_ALGO); compalgo = FSA_DEF_COMPRESS_ALGO; complevel = FSA_DEF_COMPRESS_LEVEL; } } while ((res == FSAERR_ENOMEM) && (attempt++ == 0)); // check compression status and efficiency if ((res==FSAERR_SUCCESS) && (compsize < blkinfo->blkrealsize)) // compression worked and saved space { free(blkinfo->blkdata); // free old buffer (with uncompressed data) blkinfo->blkdata=bufcomp; // new buffer (with compressed data) blkinfo->blkcompsize=compsize; // size after compression and before encryption blkinfo->blkarsize=compsize; // in case there is no encryption to set this //errprintf ("COMP_DBG: block successfully compressed using %s\n", compress_algo_int_to_string(compalgo)); } else // compressed version is bigger or compression failed: keep the original block { memcpy(bufcomp, blkinfo->blkdata, blkinfo->blkrealsize); free(blkinfo->blkdata); // free old buffer blkinfo->blkdata=bufcomp; // new buffer blkinfo->blkcompsize=blkinfo->blkrealsize; // size after compression and before encryption blkinfo->blkarsize=blkinfo->blkrealsize; // in case there is no encryption to set this blkinfo->blkcompalgo=COMPRESS_NONE; //errprintf ("COMP_DBG: block copied uncompressed, attempted using %s\n", compress_algo_int_to_string(compalgo)); } u64 cryptsize; char *bufcrypt=NULL; if (g_options.encryptalgo==ENCRYPT_BLOWFISH) { if ((bufcrypt=malloc(bufsize+8))==NULL) { errprintf("malloc(%ld) failed: out of memory\n", (long)bufsize+8); return -1; } if ((res=crypto_blowfish(blkinfo->blkcompsize, &cryptsize, (u8*)bufcomp, (u8*)bufcrypt, g_options.encryptpass, strlen((char*)g_options.encryptpass), 1))!=0) { errprintf("crypt_block_blowfish() failed with res=%d\n", res); return -1; } free(bufcomp); blkinfo->blkdata=bufcrypt; blkinfo->blkarsize=cryptsize; blkinfo->blkcryptalgo=ENCRYPT_BLOWFISH; } else { blkinfo->blkcryptalgo=ENCRYPT_NONE; } // calculates the final block checksum (block as it will be stored in the archive) blkinfo->blkarcsum=fletcher32((void*)blkinfo->blkdata, blkinfo->blkarsize); return 0; } int decompress_block_generic(struct s_blockinfo *blkinfo) { u64 checkorigsize; char *bufcomp=NULL; int res; // allocate memory for uncompressed data if ((bufcomp=malloc(blkinfo->blkrealsize))==NULL) { errprintf("malloc(%ld) failed: cannot allocate memory for compressed block\n", (long)blkinfo->blkrealsize); return -1; } // check the block checksum if (fletcher32((u8*)blkinfo->blkdata, blkinfo->blkarsize)!=(blkinfo->blkarcsum)) { errprintf("block is corrupt at blockoffset=%ld, blksize=%ld\n", (long)blkinfo->blkoffset, (long)blkinfo->blkrealsize); memset(bufcomp, 0, blkinfo->blkrealsize); } else // data not corrupted, decompresses the block { if ((blkinfo->blkcryptalgo!=ENCRYPT_NONE) && (g_options.encryptalgo!=ENCRYPT_BLOWFISH)) { msgprintf(MSG_DEBUG1, "this archive has been encrypted, you have to provide a password " "on the command line using option '-c'\n"); free (bufcomp); return -1; } char *bufcrypt=NULL; u64 clearsize; if (blkinfo->blkcryptalgo==ENCRYPT_BLOWFISH) { if ((bufcrypt=malloc(blkinfo->blkrealsize+8))==NULL) { errprintf("malloc(%ld) failed: out of memory\n", (long)blkinfo->blkrealsize+8); free(bufcomp); return -1; } if ((res=crypto_blowfish(blkinfo->blkarsize, &clearsize, (u8*)blkinfo->blkdata, (u8*)bufcrypt, g_options.encryptpass, strlen((char*)g_options.encryptpass), 0))!=0) { errprintf("crypt_block_blowfish() failed\n"); free(bufcomp); return -1; } if (clearsize!=blkinfo->blkcompsize) { errprintf("clearsize does not match blkcompsize: clearsize=%ld and blkcompsize=%ld\n", (long)clearsize, (long)blkinfo->blkcompsize); free(bufcomp); return -1; } free(blkinfo->blkdata); blkinfo->blkdata=bufcrypt; } switch (blkinfo->blkcompalgo) { case COMPRESS_NONE: memcpy(bufcomp, blkinfo->blkdata, blkinfo->blkarsize); res=0; break; #ifdef OPTION_LZO_SUPPORT case COMPRESS_LZO: if ((res=uncompress_block_lzo(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0) { errprintf("uncompress_block_lzo()=%d failed: finalsize=%ld and checkorigsize=%ld\n", res, (long)blkinfo->blkarsize, (long)checkorigsize); memset(bufcomp, 0, blkinfo->blkrealsize); // TODO: inc(error_counter); } break; #endif // OPTION_LZO_SUPPORT case COMPRESS_GZIP: if ((res=uncompress_block_gzip(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0) { errprintf("uncompress_block_gzip()=%d failed: finalsize=%ld and checkorigsize=%ld\n", res, (long)blkinfo->blkarsize, (long)checkorigsize); memset(bufcomp, 0, blkinfo->blkrealsize); // TODO: inc(error_counter); } break; case COMPRESS_BZIP2: if ((res=uncompress_block_bzip2(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0) { errprintf("uncompress_block_bzip2()=%d failed: finalsize=%ld and checkorigsize=%ld\n", res, (long)blkinfo->blkarsize, (long)checkorigsize); memset(bufcomp, 0, blkinfo->blkrealsize); // TODO: inc(error_counter); } break; #ifdef OPTION_LZMA_SUPPORT case COMPRESS_LZMA: if ((res=uncompress_block_lzma(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0) { errprintf("uncompress_block_lzma()=%d failed: finalsize=%ld and checkorigsize=%ld\n", res, (long)blkinfo->blkarsize, (long)checkorigsize); memset(bufcomp, 0, blkinfo->blkrealsize); // TODO: inc(error_counter); } break; #endif // OPTION_LZMA_SUPPORT #ifdef OPTION_LZ4_SUPPORT case COMPRESS_LZ4: if ((res=uncompress_block_lz4(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0) { errprintf("uncompress_block_lz4()=%d failed: finalsize=%ld and checkorigsize=%ld\n", res, (long)blkinfo->blkarsize, (long)checkorigsize); memset(bufcomp, 0, blkinfo->blkrealsize); // TODO: inc(error_counter); } break; #endif // OPTION_LZ4_SUPPORT #ifdef OPTION_ZSTD_SUPPORT case COMPRESS_ZSTD: if ((res=uncompress_block_zstd(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0) { errprintf("uncompress_block_zstd()=%d failed: finalsize=%ld and checkorigsize=%ld\n", res, (long)blkinfo->blkarsize, (long)checkorigsize); memset(bufcomp, 0, blkinfo->blkrealsize); // TODO: inc(error_counter); } break; #endif // OPTION_ZSTD_SUPPORT default: errprintf("unsupported compression algorithm: %ld\n", (long)blkinfo->blkcompalgo); return -1; } free(blkinfo->blkdata); // free old buffer (with compressed data) blkinfo->blkdata=bufcomp; // pointer to new buffer with uncompressed data } return 0; } int compression_function(int oper) { struct s_blockinfo blkinfo; s64 blknum; int res; while (queue_get_end_of_queue(&g_queue)==false) { if ((blknum=queue_get_first_block_todo(&g_queue, &blkinfo))>0) // block found { switch (oper) { case COMPTHR_COMPRESS: res=compress_block_generic(&blkinfo); break; case COMPTHR_DECOMPRESS: res=decompress_block_generic(&blkinfo); break; default: errprintf("oper is invalid: %d\n", oper); goto thread_comp_fct_error; } if (res!=0) { msgprintf(MSG_STACK, "compress_block()=%d failed\n", res); goto thread_comp_fct_error; } // don't check for errors: it's normal to fail when we terminate after a problem queue_replace_block(&g_queue, blknum, &blkinfo, QITEM_STATUS_DONE); } } msgprintf(MSG_DEBUG1, "THREAD-COMP: exit success\n"); return 0; thread_comp_fct_error: get_stopfillqueue(); msgprintf(MSG_DEBUG1, "THREAD-COMP: exit error\n"); return 0; } void *thread_comp_fct(void *args) { inc_secthreads(); compression_function(COMPTHR_COMPRESS); dec_secthreads(); return NULL; } void *thread_decomp_fct(void *args) { inc_secthreads(); compression_function(COMPTHR_DECOMPRESS); dec_secthreads(); return NULL; } fsarchiver-0.8.5/src/comp_lz4.h0000644000176100017610000000167113217127345013306 00000000000000 /* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2017 Cristian Vazquez. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __COMPRESS_LZ4_H__ #define __COMPRESS_LZ4_H__ #ifdef OPTION_LZ4_SUPPORT #include int compress_block_lz4(u64 origsize, u64 *compsize, u8 *origbuf, u8 *compbuf, u64 compbufsize, int level); int uncompress_block_lz4(u64 compsize, u64 *origsize, u8 *origbuf, u64 origbufsize, u8 *compbuf); #endif // OPTION_LZ4_SUPPORT #endif // __COMPRESS_LZ4_H__ fsarchiver-0.8.5/src/options.c0000644000176100017610000000655713242523705013253 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "fsarchiver.h" #include "options.h" #include "error.h" coptions g_options; int options_init() { memset(&g_options, 0, sizeof(coptions)); if (strlist_init(&g_options.exclude)!=0) return -1; return 0; } int options_destroy() { if (strlist_destroy(&g_options.exclude)!=0) return -1; memset(&g_options, 0, sizeof(coptions)); return 0; } int options_select_compress_level(int opt) { switch (opt) { #ifdef OPTION_LZ4_SUPPORT case 0: // lz4 g_options.compressalgo=COMPRESS_LZ4; break; #else case 0: // lz4 errprintf("compression level %d is not available: lz4 has been disabled at compilation time\n", opt); #endif // OPTION_LZ4_SUPPORT #ifdef OPTION_LZO_SUPPORT case 1: // lzo g_options.compressalgo=COMPRESS_LZO; g_options.compresslevel=3; break; #else case 1: // lzo errprintf("compression level %d is not available: lzo has been disabled at compilation time\n", opt); return -1; #endif // OPTION_LZO_SUPPORT case 2: // gzip fast g_options.compressalgo=COMPRESS_GZIP; g_options.compresslevel=3; break; case 3: // gzip standard g_options.compressalgo=COMPRESS_GZIP; g_options.compresslevel=6; break; case 4: // gzip best g_options.compressalgo=COMPRESS_GZIP; g_options.compresslevel=9; break; case 5: // bzip2 fast g_options.compressalgo=COMPRESS_BZIP2; g_options.datablocksize=262144; g_options.compresslevel=2; break; case 6: // bzip2 good g_options.compressalgo=COMPRESS_BZIP2; g_options.datablocksize=524288; g_options.compresslevel=5; break; #ifdef OPTION_LZMA_SUPPORT case 7: // lzma fast g_options.compressalgo=COMPRESS_LZMA; g_options.datablocksize=262144; g_options.compresslevel=1; break; case 8: // lzma medium g_options.compressalgo=COMPRESS_LZMA; g_options.datablocksize=524288; g_options.compresslevel=6; break; case 9: // lzma best g_options.compressalgo=COMPRESS_LZMA; g_options.datablocksize=FSA_MAX_BLKSIZE; g_options.compresslevel=9; break; #else case 7: // lzma case 8: // lzma case 9: // lzma errprintf("compression level %d is not available: lzma has been disabled at compilation time\n", opt); return -1; #endif default: errprintf("invalid compression level: %d\n", opt); return -1; } return 0; } fsarchiver-0.8.5/src/archinfo.h0000644000176100017610000000160413242523705013342 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __ARCHINFO_H__ #define __ARCHINFO_H__ struct s_dico; struct s_archreader; int archinfo_show_mainhead(struct s_archreader *ai, struct s_dico *dicomainhead); int archinfo_show_fshead(struct s_dico *dicofshead, int fsid); char *compalgostr(int algo); char *cryptalgostr(int algo); #endif // __ARCHINFO_H__ fsarchiver-0.8.5/src/thread_archio.c0000644000176100017610000002400013242523705014333 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "fsarchiver.h" #include "archreader.h" #include "archwriter.h" #include "dico.h" #include "common.h" #include "error.h" #include "syncthread.h" #include "queue.h" void *thread_writer_fct(void *args) { struct s_headinfo headinfo; struct s_blockinfo blkinfo; carchwriter *ai=NULL; s64 blknum; int type; // init inc_secthreads(); if ((ai=(carchwriter *)args)==NULL) { errprintf("ai is NULL\n"); goto thread_writer_fct_error; } if (archwriter_volpath(ai)!=0) { msgprintf(MSG_STACK, "archwriter_volpath() failed\n"); goto thread_writer_fct_error; } if (archwriter_create(ai)!=0) { msgprintf(MSG_STACK, "archwriter_create(%s) failed\n", ai->basepath); goto thread_writer_fct_error; } if (archwriter_write_volheader(ai)!=0) { msgprintf(MSG_STACK, "cannot write volume header: archwriter_write_volheader() failed\n"); goto thread_writer_fct_error; } while (queue_get_end_of_queue(&g_queue)==false) { if ((blknum=queue_dequeue_first(&g_queue, &type, &headinfo, &blkinfo))<0 && blknum!=FSAERR_ENDOFFILE) // error { msgprintf(MSG_STACK, "queue_dequeue_first()=%ld=%s failed\n", (long)blknum, error_int_to_string(blknum)); goto thread_writer_fct_error; } else if (blknum>0) // block or header found { switch (type) { case QITEM_TYPE_BLOCK: if (archwriter_dowrite_block(ai, &blkinfo)!=0) { msgprintf(MSG_STACK, "archive_dowrite_block() failed\n"); goto thread_writer_fct_error; } free(blkinfo.blkdata); break; case QITEM_TYPE_HEADER: if (archwriter_dowrite_header(ai, &headinfo)!=0) { msgprintf(MSG_STACK, "archive_write_header() failed\n"); goto thread_writer_fct_error; } dico_destroy(headinfo.dico); break; default: errprintf("unexpected item type from queue: type=%d\n", type); break; } } } // write last volume footer if (archwriter_write_volfooter(ai, true)!=0) { msgprintf(MSG_STACK, "cannot write volume footer: archio_write_volfooter() failed\n"); goto thread_writer_fct_error; } archwriter_close(ai); msgprintf(MSG_DEBUG1, "THREAD-WRITER: exit success\n"); dec_secthreads(); return NULL; thread_writer_fct_error: msgprintf(MSG_DEBUG1, "THREAD-WRITER: exit remove\n"); set_stopfillqueue(); // say to the create.c thread that it must stop while (queue_get_end_of_queue(&g_queue)==false) // wait until all the compression threads exit queue_destroy_first_item(&g_queue); // empty queue archwriter_close(ai); dec_secthreads(); return NULL; } void *thread_reader_fct(void *args) { char magic[FSA_SIZEOF_MAGIC]; struct s_blockinfo blkinfo; u32 endofarchive=false; carchreader *ai=NULL; cdico *dico=NULL; int skipblock; u16 fsid; int sumok; int status; u64 errors; s64 lres; int res; // init errors=0; inc_secthreads(); if ((ai=(carchreader *)args)==NULL) { errprintf("ai is NULL\n"); goto thread_reader_fct_error; } // open archive file if (archreader_volpath(ai)!=0) { errprintf("archreader_volpath() failed\n"); goto thread_reader_fct_error; } if (archreader_open(ai)!=0) { errprintf("archreader_open(%s) failed\n", ai->basepath); goto thread_reader_fct_error; } // read volume header if (archreader_read_volheader(ai)!=0) { errprintf("archio_read_volheader() failed\n"); goto thread_reader_fct_error; } // ---- read main archive header if ((res=archreader_read_header(ai, magic, &dico, false, &fsid))!=FSAERR_SUCCESS) { errprintf("archreader_read_header() failed to read the archive header\n"); goto thread_reader_fct_error; // this header is required to continue } if (dico_get_u32(dico, 0, MAINHEADKEY_ARCHIVEID, &ai->archid)!=0) { msgprintf(3, "cannot get archive-id from main header\n"); goto thread_reader_fct_error; } if ((lres=queue_add_header(&g_queue, dico, magic, fsid))!=FSAERR_SUCCESS) { errprintf("queue_add_header()=%ld=%s failed to add the archive header\n", (long)lres, error_int_to_string(lres)); goto thread_reader_fct_error; } // read all other data from file (filesys-header, normal objects headers, ...) while (endofarchive==false && get_stopfillqueue()==false) { if ((res=archreader_read_header(ai, magic, &dico, true, &fsid))!=FSAERR_SUCCESS) { dico_destroy(dico); msgprintf(MSG_STACK, "archreader_read_header() failed to read next header\n"); if (res==OLDERR_MINOR) // header is corrupt or not what we expected { errors++; msgprintf(MSG_DEBUG1, "OLDERR_MINOR\n"); continue; } else // fatal error (eg: cannot read archive from disk) { msgprintf(MSG_DEBUG1, "!OLDERR_MINOR\n"); goto thread_reader_fct_error; } } // read header and see if it's for archive management or higher level data if (strncmp(magic, FSA_MAGIC_VOLF, FSA_SIZEOF_MAGIC)==0) // header is "end of volume" { archreader_close(ai); // check the "end of archive" flag in header if (dico_get_u32(dico, 0, VOLUMEFOOTKEY_LASTVOL, &endofarchive)!=0) { errprintf("cannot get compr from block-header\n"); goto thread_reader_fct_error; } msgprintf(MSG_VERB2, "End of volume [%s]\n", ai->volpath); if (endofarchive!=true) { archreader_incvolume(ai, false); while (regfile_exists(ai->volpath)!=true) { // wait until the queue is empty so that the main thread does not pollute the screen while (queue_count(&g_queue)>0) usleep(5000); fflush(stdout); fflush(stderr); msgprintf(MSG_FORCE, "File [%s] is not found, please type the path to volume %ld:\n", ai->volpath, (long)ai->curvol); fprintf(stdout, "New path:> "); res=scanf("%256s", ai->volpath); } msgprintf(MSG_VERB2, "New volume is [%s]\n", ai->volpath); if (archreader_open(ai)!=0) { msgprintf(MSG_STACK, "archreader_open() failed\n"); goto thread_reader_fct_error; } if (archreader_read_volheader(ai)!=0) { msgprintf(MSG_STACK, "archio_read_volheader() failed\n"); goto thread_reader_fct_error; } } dico_destroy(dico); } else // high-level archive (not involved in volume management) { if (strncmp(magic, FSA_MAGIC_BLKH, FSA_SIZEOF_MAGIC)==0) // header starts a data block { skipblock=(g_fsbitmap[fsid]==0); //errprintf("DEBUG: skipblock=%d g_fsbitmap[fsid=%d]=%d\n", skipblock, (int)fsid, (int)g_fsbitmap[fsid]); if (archreader_read_block(ai, dico, skipblock, &sumok, &blkinfo)!=0) { msgprintf(MSG_STACK, "archreader_read_block() failed\n"); goto thread_reader_fct_error; } if (skipblock==false) { status=((sumok==true)?QITEM_STATUS_TODO:QITEM_STATUS_DONE); if ((lres=queue_add_block(&g_queue, &blkinfo, status))!=FSAERR_SUCCESS) { if (lres!=FSAERR_NOTOPEN) errprintf("queue_add_block()=%ld=%s failed\n", (long)lres, error_int_to_string(lres)); goto thread_reader_fct_error; } if (sumok==false) errors++; dico_destroy(dico); } } else // another higher level header { // if it's a global header or a if this local header belongs to a filesystem that the main thread needs if (fsid==FSA_FILESYSID_NULL || g_fsbitmap[fsid]==1) { if ((lres=queue_add_header(&g_queue, dico, magic, fsid))!=FSAERR_SUCCESS) { msgprintf(MSG_STACK, "queue_add_header()=%ld=%s failed\n", (long)lres, error_int_to_string(lres)); goto thread_reader_fct_error; } } else // header not used: remove data strucutre in dynamic memory { dico_destroy(dico); } } } } thread_reader_fct_error: msgprintf(MSG_DEBUG1, "THREAD-READER: queue_set_end_of_queue(&g_queue, true)\n"); queue_set_end_of_queue(&g_queue, true); // don't wait for more data from this thread dec_secthreads(); msgprintf(MSG_DEBUG1, "THREAD-READER: exit\n"); return NULL; } fsarchiver-0.8.5/src/fs_btrfs.h0000644000176100017610000001305013242523705013357 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __FS_BTRFS_H__ #define __FS_BTRFS_H__ struct s_dico; struct s_strlist; int btrfs_mkfs(struct s_dico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid); int btrfs_getinfo(struct s_dico *d, char *devname); int btrfs_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo); int btrfs_umount(char *partition, char *mntbuf); int btrfs_check_support_for_features(u64 compat, u64 incompat, u64 ro_compat); int btrfs_get_reqmntopt(char *partition, struct s_strlist *reqopt, struct s_strlist *badopt); int btrfs_test(char *devname); // compat flags: official definition from linux-3.14/fs/btrfs/ctree.h #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) #define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) #define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO (1ULL << 3) #define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZOv2 (1ULL << 4) #define BTRFS_FEATURE_INCOMPAT_BIG_METADATA (1ULL << 5) #define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF (1ULL << 6) #define BTRFS_FEATURE_INCOMPAT_RAID56 (1ULL << 7) #define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8) #define BTRFS_FEATURE_INCOMPAT_NO_HOLES (1ULL << 9) // compat flags: btrfs features that this fsarchiver version supports #define FSA_BTRFS_FEATURE_COMPAT_SUPP 0ULL #define FSA_BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL #define FSA_BTRFS_FEATURE_INCOMPAT_SUPP \ (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \ BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \ BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \ BTRFS_FEATURE_INCOMPAT_COMPRESS_LZOv2 | \ BTRFS_FEATURE_INCOMPAT_RAID56 | \ BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \ BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \ BTRFS_FEATURE_INCOMPAT_NO_HOLES) // disk layout definitions #define BTRFS_SUPER_MAGIC 0x9123683E #define BTRFS_MAGIC "_BHRfS_M" #define BTRFS_SUPER_INFO_OFFSET (64 * 1024) #define BTRFS_SUPER_INFO_SIZE 4096 #define BTRFS_SUPER_MIRROR_MAX 3 #define BTRFS_SUPER_MIRROR_SHIFT 12 #define BTRFS_NAME_LEN 255 #define BTRFS_CSUM_SIZE 32 #define BTRFS_CSUM_TYPE_CRC32 0 #define BTRFS_FSID_SIZE 16 #define BTRFS_HEADER_FLAG_WRITTEN (1 << 0) #define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048 #define BTRFS_LABEL_SIZE 256 #define BTRFS_UUID_SIZE 16 static inline u64 btrfs_sb_offset(int mirror) { u64 start = 16 * 1024; if (mirror) return start << (BTRFS_SUPER_MIRROR_SHIFT * mirror); return BTRFS_SUPER_INFO_OFFSET; } struct btrfs_dev_item { /* the internal btrfs device id */ __le64 devid; /* size of the device */ __le64 total_bytes; /* bytes used */ __le64 bytes_used; /* optimal io alignment for this device */ __le32 io_align; /* optimal io width for this device */ __le32 io_width; /* minimal io size for this device */ __le32 sector_size; /* type and info about this device */ __le64 type; /* expected generation for this device */ __le64 generation; /* * starting byte of this partition on the device, * to allowr for stripe alignment in the future */ __le64 start_offset; /* grouping information for allocation decisions */ __le32 dev_group; /* seek speed 0-100 where 100 is fastest */ u8 seek_speed; /* bandwidth 0-100 where 100 is fastest */ u8 bandwidth; /* btrfs generated uuid for this device */ u8 uuid[BTRFS_UUID_SIZE]; /* uuid of FS who owns this device */ u8 fsid[BTRFS_UUID_SIZE]; } __attribute__ ((__packed__)); /* * the super block basically lists the main trees of the FS * it currently lacks any block count etc etc */ struct btrfs_super_block { u8 csum[BTRFS_CSUM_SIZE]; /* the first 4 fields must match struct btrfs_header */ u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ __le64 bytenr; /* this block number */ __le64 flags; /* allowed to be different from the btrfs_header from here own down */ __le64 magic; __le64 generation; __le64 root; __le64 chunk_root; __le64 log_root; /* this will help find the new super based on the log root */ __le64 log_root_transid; __le64 total_bytes; __le64 bytes_used; __le64 root_dir_objectid; __le64 num_devices; __le32 sectorsize; __le32 nodesize; __le32 leafsize; __le32 stripesize; __le32 sys_chunk_array_size; __le64 chunk_root_generation; __le64 compat_flags; __le64 compat_ro_flags; __le64 incompat_flags; __le16 csum_type; u8 root_level; u8 chunk_root_level; u8 log_root_level; struct btrfs_dev_item dev_item; char label[BTRFS_LABEL_SIZE]; /* future expansion */ __le64 reserved[32]; u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; } __attribute__ ((__packed__)); #endif // __FS_BTRFS_H__ fsarchiver-0.8.5/src/fs_xfs.h0000644000176100017610000002332413242523705013044 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __FS_XFS_H__ #define __FS_XFS_H__ struct s_dico; struct s_strlist; /* * Super block * Fits into a sector-sized buffer at address 0 of each allocation group. * Only the first of these is ever updated except during growfs. */ #define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */ #define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */ #define XFS_SB_VERSION_2 2 /* 6.2 - attributes */ #define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */ #define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */ #define XFS_SB_VERSION_5 5 /* CRC enabled filesystem */ #define XFS_SB_VERSION_NUMBITS 0x000f #define XFS_SB_VERSION_ALLFBITS 0xfff0 #define XFS_SB_VERSION_ATTRBIT 0x0010 #define XFS_SB_VERSION_NLINKBIT 0x0020 #define XFS_SB_VERSION_QUOTABIT 0x0040 #define XFS_SB_VERSION_ALIGNBIT 0x0080 #define XFS_SB_VERSION_DALIGNBIT 0x0100 #define XFS_SB_VERSION_SHAREDBIT 0x0200 #define XFS_SB_VERSION_LOGV2BIT 0x0400 #define XFS_SB_VERSION_SECTORBIT 0x0800 #define XFS_SB_VERSION_EXTFLGBIT 0x1000 #define XFS_SB_VERSION_DIRV2BIT 0x2000 #define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */ #define XFS_SB_VERSION_MOREBITSBIT 0x8000 int xfs_mkfs(struct s_dico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid); int xfs_getinfo(struct s_dico *d, char *devname); int xfs_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo); int xfs_get_reqmntopt(char *partition, struct s_strlist *reqopt, struct s_strlist *badopt); int xfs_umount(char *partition, char *mntbuf); int xfs_test(char *devname); int xfs_check_compatibility(u64 compat, u64 ro_compat, u64 incompat, u64 log_incompat); typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */ typedef uint32_t xfs_extlen_t; /* extent length in blocks */ typedef uint32_t xfs_agnumber_t; /* allocation group number */ typedef int32_t xfs_extnum_t; /* # of extents in a file */ typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */ typedef int64_t xfs_fsize_t; /* bytes in a file */ typedef uint64_t xfs_ufsize_t; /* unsigned bytes in a file */ typedef int32_t xfs_suminfo_t; /* type of bitmap summary info */ typedef int32_t xfs_rtword_t; /* word type for bitmap manipulations */ typedef int64_t xfs_lsn_t; /* log sequence number */ typedef int32_t xfs_tid_t; /* transaction identifier */ typedef uint32_t xfs_dablk_t; /* dir/attr block number (in file) */ typedef uint32_t xfs_dahash_t; /* dir/attr hash value */ typedef uint16_t xfs_prid_t; /* prid_t truncated to 16bits in XFS */ /* * These types are 64 bits on disk but are either 32 or 64 bits in memory. * Disk based types: */ typedef uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ typedef uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ typedef uint64_t xfs_rtblock_t; /* extent (block) in realtime area */ typedef uint64_t xfs_dfiloff_t; /* block number in a file */ typedef uint64_t xfs_dfilblks_t; /* number of blocks in a file */ typedef __s64 xfs_off_t; /* type */ typedef __u64 xfs_ino_t; /* type */ typedef __s64 xfs_daddr_t; /* type */ typedef char * xfs_caddr_t; /* type */ typedef __u32 xfs_dev_t; typedef __u32 xfs_nlink_t; /* * Superblock - in core version. Must match the ondisk version below. * Must be padded to 64 bit alignment. */ struct xfs_sb { uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ uint32_t sb_blocksize; /* logical block size, bytes */ xfs_rfsblock_t sb_dblocks; /* number of data blocks */ xfs_rfsblock_t sb_rblocks; /* number of realtime blocks */ xfs_rtblock_t sb_rextents; /* number of realtime extents */ uuid_t sb_uuid; /* user-visible file system unique id */ xfs_fsblock_t sb_logstart; /* starting block of log if internal */ xfs_ino_t sb_rootino; /* root inode number */ xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */ xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */ xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */ xfs_agblock_t sb_agblocks; /* size of an allocation group */ xfs_agnumber_t sb_agcount; /* number of allocation groups */ xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */ xfs_extlen_t sb_logblocks; /* number of log blocks */ uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ uint16_t sb_sectsize; /* volume sector size, bytes */ uint16_t sb_inodesize; /* inode size, bytes */ uint16_t sb_inopblock; /* inodes per block */ char sb_fname[12]; /* file system name */ uint8_t sb_blocklog; /* log2 of sb_blocksize */ uint8_t sb_sectlog; /* log2 of sb_sectsize */ uint8_t sb_inodelog; /* log2 of sb_inodesize */ uint8_t sb_inopblog; /* log2 of sb_inopblock */ uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ uint8_t sb_rextslog; /* log2 of sb_rextents */ uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ uint8_t sb_imax_pct; /* max % of fs for inode space */ /* statistics */ /* * These fields must remain contiguous. If you really * want to change their layout, make sure you fix the * code in xfs_trans_apply_sb_deltas(). */ uint64_t sb_icount; /* allocated inodes */ uint64_t sb_ifree; /* free inodes */ uint64_t sb_fdblocks; /* free data blocks */ uint64_t sb_frextents; /* free realtime extents */ /* * End contiguous fields. */ xfs_ino_t sb_uquotino; /* user quota inode */ xfs_ino_t sb_gquotino; /* group quota inode */ uint16_t sb_qflags; /* quota flags */ uint8_t sb_flags; /* misc. flags */ uint8_t sb_shared_vn; /* shared version number */ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ uint32_t sb_unit; /* stripe or raid unit */ uint32_t sb_width; /* stripe or raid width */ uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */ uint8_t sb_logsectlog; /* log2 of the log sector size */ uint16_t sb_logsectsize; /* sector size for the log, bytes */ uint32_t sb_logsunit; /* stripe unit size for the log */ uint32_t sb_features2; /* additional feature bits */ /* * bad features2 field as a result of failing to pad the sb structure to * 64 bits. Some machines will be using this field for features2 bits. * Easiest just to mark it bad and not use it for anything else. * * This is not kept up to date in memory; it is always overwritten by * the value in sb_features2 when formatting the incore superblock to * the disk buffer. */ uint32_t sb_bad_features2; /* version 5 superblock fields start here */ /* feature masks */ uint32_t sb_features_compat; uint32_t sb_features_ro_compat; uint32_t sb_features_incompat; uint32_t sb_features_log_incompat; uint32_t sb_crc; /* superblock crc */ xfs_extlen_t sb_spino_align; /* sparse inode chunk alignment */ xfs_ino_t sb_pquotino; /* project quota inode */ xfs_lsn_t sb_lsn; /* last write sequence */ uuid_t sb_meta_uuid; /* metadata file system unique id */ /* must be padded to 64 bit alignment */ }; // XFS features used in XFS version 5 only #define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */ #define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1) /* reverse map btree */ #define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2) /* reflinked files */ #define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */ #define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */ #define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */ // features supported by the current fsarchiver version #define FSA_XFS_FEATURE_COMPAT_SUPP (u64)(0) #define FSA_XFS_FEATURE_RO_COMPAT_SUPP (u64)(XFS_SB_FEAT_RO_COMPAT_FINOBT|\ XFS_SB_FEAT_RO_COMPAT_RMAPBT|\ XFS_SB_FEAT_RO_COMPAT_REFLINK) #define FSA_XFS_FEATURE_INCOMPAT_SUPP (u64)(XFS_SB_FEAT_INCOMPAT_FTYPE|\ XFS_SB_FEAT_INCOMPAT_SPINODES|\ XFS_SB_FEAT_INCOMPAT_META_UUID) #define FSA_XFS_FEATURE_LOG_INCOMPAT_SUPP (u64)(0) #endif // __FS_XFS_H__ fsarchiver-0.8.5/src/common.c0000644000176100017610000004304113242523705013035 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_EXECINFO_H #include #endif #include "fsarchiver.h" #include "syncthread.h" #include "strlist.h" #include "common.h" #include "error.h" int stream_readline(FILE *f, char *buf, int buflen) { int i; char c; memset(buf, 0, buflen); for (i=0; (!feof(f)) && ((c=fgetc(f))!='\n') && (!feof(f)) && (i < buflen); i++) buf[i]=c; return i; } void concatenate_paths(char *buffer, int maxbufsize, char *p1, char *p2) { int i; memset(buffer, 0, maxbufsize); for (i=0; (p1[i]) && (p1[i]!='/' || p1[i+1]); i++) *(buffer++)=p1[i]; *(buffer++)='/'; while (*p2=='/') p2++; strlcatf(buffer, maxbufsize, "%s", p2); } char *format_size(u64 size, char *text, int max, char units) { double dSize; u64 llKiloB = 1024LL; u64 llMegaB = 1024LL * llKiloB; u64 llGigaB = 1024LL * llMegaB; u64 llTeraB = 1024LL * llGigaB; if ((units=='b') || ((units=='h') && size < llKiloB)) // In Bytes { snprintf(text, max, "%lld bytes", (long long)size); } else if ((units=='k') || ((units=='h') && size < llMegaB)) // In KiloBytes { dSize = ((double)size) / ((double)llKiloB); snprintf(text, max, "%.2f KB", (float) dSize); } else if ((units=='m') || ((units=='h') && size < llGigaB)) // In MegaBytes { dSize = ((double)size) / ((double)llMegaB); snprintf(text, max, "%.2f MB", (float) dSize); } else if ((units=='g') || ((units=='h') && size < llTeraB)) // In Gigabytes { dSize = ((double)size) / ((double)llGigaB); snprintf(text, max, "%.2f GB", (float) dSize); } else // bigger than 1TB { dSize = ((double)size) / ((double)llTeraB); snprintf(text, max, "%.2f TB", (float) dSize); } return text; } int mkdir_recursive(char *path) { char buffer[PATH_MAX]; struct stat64 statbuf; int len; int pos; len=strlen(path); for (pos=0; pos<=len; pos++) { if (path[pos]=='/' || path[pos]==0) { memset(buffer, 0, sizeof(buffer)); memcpy(buffer, path, pos); if (stat64(buffer, &statbuf)==-1 && errno==ENOENT) mkdir(buffer, 0755); } } return 0; } int extract_dirpath(char *filepath, char *dirbuf, int dirbufsize) { int i; snprintf(dirbuf, dirbufsize, "%s", filepath); for (i=0; (i=0) && (dirbuf[i]!='/')) dirbuf[i--]=0; if ((i>0) && (dirbuf[i]=='/')) dirbuf[i]=0; return 0; } int extract_basename(char *filepath, char *basenamebuf, int basenamebufsize) { int i; for (i=0; filepath[i]; i++); while ((i>0) && (filepath[i]!='/') && (filepath[i-1]!='/')) i--; snprintf(basenamebuf, basenamebufsize, "%s", &filepath[i]); return 0; } char *get_objtype_name(int objtype) { switch (objtype) { case OBJTYPE_DIR: return ("DIR "); case OBJTYPE_SYMLINK: return ("SYMLINK "); case OBJTYPE_REGFILEUNIQUE: return ("REGFILE "); case OBJTYPE_REGFILEMULTI: return ("REGFILEM"); case OBJTYPE_HARDLINK: return ("HARDLINK"); case OBJTYPE_CHARDEV: return ("CHARDEV "); case OBJTYPE_BLOCKDEV: return ("BLOCKDEV"); case OBJTYPE_FIFO: return ("FIFO "); case OBJTYPE_SOCKET: return ("SOCKET "); default: return ("UNKNOWN "); } } int is_dir_empty(char *path) { char fullpath[PATH_MAX]; struct stat64 statbuf; struct dirent *dir; DIR *dirdesc; dirdesc = opendir(path); if (!dirdesc) { sysprintf("cannot open directory %s\n", path); return -1; } while ((dir = readdir(dirdesc)) != NULL) { concatenate_paths(fullpath, sizeof(fullpath), path, dir->d_name); if (lstat64(fullpath, &statbuf)!=0) { sysprintf ("cannot stat %s\n", fullpath); closedir(dirdesc); return -1; } if (strcmp(dir->d_name,".")!=0 && strcmp(dir->d_name,"..")!=0) { closedir(dirdesc); return 1; // an item was found } } closedir(dirdesc); return 0; } // generate a non-null random u32 u32 generate_random_u32_id(void) { struct timeval now; u32 archid; memset(&now, 0, sizeof(struct timeval)); do { gettimeofday(&now, NULL); archid=((u32)now.tv_sec)^((u32)now.tv_usec); } while (archid==0); return archid; } u32 fletcher32(u8 *data, u32 len) { u32 sum1 = 0xffff, sum2 = 0xffff; while (len) { unsigned tlen = len > 360 ? 360 : len; len -= tlen; do { sum1 += *data++; sum2 += sum1; } while (--tlen); sum1 = (sum1 & 0xffff) + (sum1 >> 16); sum2 = (sum2 & 0xffff) + (sum2 >> 16); } // Second reduction step to reduce sums to 16 bits sum1 = (sum1 & 0xffff) + (sum1 >> 16); sum2 = (sum2 & 0xffff) + (sum2 >> 16); return sum2 << 16 | sum1; } int regfile_exists(char *filepath) { struct stat64 st; int res; res=stat64(filepath, &st); if ((res==0) && S_ISREG(st.st_mode)) return true; // file exists if (res==-1 && errno==ENOENT) return false; // does not exist return -1; // don't know } int getpathtoprog(char *buffer, int bufsize, char *prog) { char pathtest[PATH_MAX]; char delims[]=":\t\n"; struct stat bufstat; char pathenv[4096]; char *saveptr=0; char *result; char *vp; int i; memset(buffer, 0, bufsize); if ((vp=getenv("PATH")) == NULL) return -1; snprintf(pathenv, sizeof(pathenv), "%s", vp); result=strtok_r(pathenv, delims, &saveptr); for(i=0; result != NULL; i++) { snprintf(pathtest, sizeof(pathtest), "%s/%s", result, prog); if (stat(pathtest, &bufstat)==0 && access(pathtest, X_OK)==0) { snprintf(buffer, bufsize, "%s", pathtest); return 0; } result = strtok_r(NULL, delims, &saveptr); } return -1; } int exec_command(char *command, int cmdbufsize, int *exitst, char *stdoutbuf, int stdoutsize, char *stderrbuf, int stderrsize, char *format, ...) { char pathtoprog[PATH_MAX]; // full path to the program to run const int max_argv=128; // maximum arguments to a command char *argv[max_argv]; // pointer to arguments processed by wordexp() int outpos=0; // how many bytes have already been stored in the buffer for stdout int errpos=0; // how many bytes have already been stored in the buffer for stderr int pfildes1[2]; int pfildes2[2]; wordexp_t p; int status; int mystdout; int mystderr; va_list ap; int cmdpid; int flags; int pid; int res; char c; int i; // init memset(pathtoprog, 0, sizeof(pathtoprog)); for (i=0; i < max_argv; argv[i++]=NULL); if (exitst) *exitst=-1; // format the string if (stdoutbuf && stdoutsize) memset(stdoutbuf, 0, stdoutsize); if (stderrbuf && stderrsize) memset(stderrbuf, 0, stderrsize); memset(command, 0, cmdbufsize); va_start(ap, format); vsnprintf(command, cmdbufsize, format, ap); va_end(ap); // do shell expansion to parse the quotes for args with spaces wordexp(command, &p, 0); // will require wordfree to free the memory for(i=0; (i < p.we_wordc) && (i command to be executed { close(pfildes1[0]); // close read end of pipe close(pfildes2[0]); // close read end of pipe dup2(pfildes1[1],1); // make 1 same as write-to end of pipe close(pfildes1[1]); // close excess fildes dup2(pfildes2[1],2); // make 1 same as write-to end of pipe close(pfildes2[1]); // close excess fildes setenv("LC_ALL", "C", 1); // kill internationalization execvp(pathtoprog, argv); errprintf("execvp(%s) failed\n", pathtoprog); // still around? exec failed wordfree(&p); exit(EXIT_FAILURE); } else // parent --> fsarchiver { mystdout=pfildes1[0]; mystderr=pfildes2[0]; cmdpid=pid; close(pfildes1[1]); // close write end of pipe close(pfildes2[1]); // close write end of pipe // set non blocking reads to make sure we dont block on read(stderr) when buffer for stdout is full for instance flags = fcntl(mystdout, F_GETFL, 0); fcntl(mystdout, F_SETFL, flags | O_NONBLOCK); flags = fcntl(mystderr, F_GETFL, 0); fcntl(mystderr, F_SETFL, flags | O_NONBLOCK); do { // read data stored in the stdout pipe (read to prevents the sub-process command from blocking on write) do { res=read(mystdout, &c, 1); if ((stdoutbuf!=NULL) && (res>0) && (outpos+1 < stdoutsize)) stdoutbuf[outpos++]=c; } while (res>0); // read data stored in the stderr pipe (read to prevents the sub-process command from blocking on write) do { res=read(mystderr, &c, 1); if ((stderrbuf!=NULL) && (res>0) && (errpos+1 < stderrsize)) stderrbuf[errpos++]=c; } while (res>0); usleep(100000); // don't spin the cpu } while ( ((res=waitpid(cmdpid, &status, WNOHANG))!=cmdpid) && (res!=-1) ); // read the remaining data in the pipes if ((stdoutbuf!=NULL) && (outpos+1 < stdoutsize)) read(mystdout, stdoutbuf+outpos, stdoutsize-outpos-1); if ((stderrbuf!=NULL) && (errpos+1 < stderrsize)) read(mystderr, stderrbuf+errpos, stderrsize-errpos-1); msgprintf(MSG_VERB1, "command [%s] returned %d\n", command, WEXITSTATUS(status)); if (exitst) *exitst=WEXITSTATUS(status); if ((stdoutbuf!=NULL) && (outpos>0)) msgprintf(MSG_DEBUG1, "\n----stdout----\n%s\n----stdout----\n\n", stdoutbuf); if ((stderrbuf!=NULL) && (errpos>0)) msgprintf(MSG_DEBUG1, "\n----stderr----\n%s\n----stderr----\n\n", stderrbuf); wordfree(&p); return 0; } } int generate_random_tmpdir(char *buffer, int bufsize, int n) { struct tm tbreak; time_t abstime; struct timeval tv; gettimeofday(&tv, NULL); abstime=tv.tv_sec; localtime_r(&abstime, &tbreak); snprintf(buffer, bufsize, "/tmp/fsa/%.4d%.2d%.2d-%.2d%.2d%.2d-%.8x-%.2d", tbreak.tm_year+1900, tbreak.tm_mon+1, tbreak.tm_mday, tbreak.tm_hour, tbreak.tm_min, tbreak.tm_sec, (u32)tv.tv_usec, n); return 0; } // returns true if magic is a valid magic-string int is_magic_valid(char *magic) { int i; for (i=0; valid_magic[i]!=NULL; i++) if (memcmp(magic, valid_magic[i], FSA_SIZEOF_MAGIC)==0) return true; return false; } // just copies the path if it has the right extension or add the extension int path_force_extension(char *buf, int bufsize, char *origpath, char *ext) { int oldlen, extlen; if (!buf || !origpath || !ext) { errprintf("a parameter is null\n"); return -1; } oldlen=strlen(origpath); extlen=strlen(ext); if ((oldlen < extlen) || memcmp(origpath+oldlen-extlen, ext, extlen)!=0) snprintf(buf, bufsize, "%s%s", origpath, ext); else // the extension has been found at the end of origpath snprintf(buf, bufsize, "%s", origpath); return 0; } // convert a binary md5 to an hexadecimal format char *format_md5(char *buf, int maxbuf, u8 *md5bin) { int i; memset(buf, 0, maxbuf); for (i=0; i<16; i++) strlcatf(buf, maxbuf, "%.2x", md5bin[i]); return buf; } char *format_time(char *buffer, int bufsize, u64 t) { struct tm timeres; time_t t2; if (!buffer) return NULL; t2=t; localtime_r(&t2, &timeres); snprintf(buffer, bufsize, "%.4d-%.2d-%.2d_%.2d-%.2d-%.2d", timeres.tm_year+1900, timeres.tm_mon+1, timeres.tm_mday, timeres.tm_hour, timeres.tm_min, timeres.tm_sec); return buffer; } // add a formatted string at the end of a buffer that already contains a string char *strlcatf(char *dest, int destbufsize, char *format, ...) { va_list ap; int len1; // if buffer already full, don't cat the second string if ((len1=strnlen(dest, destbufsize))==destbufsize) return dest; // at the new formatted string at the end of the first one va_start(ap, format); vsnprintf(dest+len1, destbufsize-len1, format, ap); va_end(ap); return dest; } int get_parent_dir_time_attrib(char *filepath, char *parentdirbuf, int bufsize, struct timeval *tv) { struct stat64 statbuf; extract_dirpath(filepath, parentdirbuf, bufsize); if (lstat64(parentdirbuf, &statbuf)!=0) { sysprintf("cannot lstat64(%s)\n", parentdirbuf); return -1; } if (!S_ISDIR(statbuf.st_mode)) { sysprintf("error: [%s] is not a directory\n", parentdirbuf); return -1; } // prepare structure to be passed to utimes tv[0].tv_usec=0; tv[0].tv_sec=statbuf.st_atime; tv[1].tv_usec=0; tv[1].tv_sec=statbuf.st_mtime; return 0; } int stats_show(cstats stats, int fsid) { msgprintf(MSG_FORCE, "Statistics for filesystem %d\n", fsid); msgprintf(MSG_FORCE, "* files successfully processed:....regfiles=%lld, directories=%lld, " "symlinks=%lld, hardlinks=%lld, specials=%lld\n", (long long)stats.cnt_regfile, (long long)stats.cnt_dir, (long long)stats.cnt_symlink, (long long)stats.cnt_hardlink, (long long)stats.cnt_special); msgprintf(MSG_FORCE, "* files with errors:...............regfiles=%lld, directories=%lld, " "symlinks=%lld, hardlinks=%lld, specials=%lld\n", (long long)stats.err_regfile, (long long)stats.err_dir, (long long)stats.err_symlink, (long long)stats.err_hardlink, (long long)stats.err_special); return 0; } u64 stats_errcount(cstats stats) { return stats.err_regfile+stats.err_dir+stats.err_symlink+stats.err_hardlink+stats.err_special; } int format_stacktrace(char *buffer, int bufsize) { #ifdef HAVE_EXECINFO_H const int stack_depth=20; void *temp[stack_depth]; char **strings; int nptrs; int i; // format the backtrace (advanced error info) memset(buffer, 0, bufsize); nptrs=backtrace(temp, stack_depth); strings=backtrace_symbols(temp, nptrs); if (strings!=NULL) { for (i = 0; i < nptrs; i++) strlcatf(buffer, bufsize, "%s\n", strings[i]); free(strings); } #endif return 0; } int exclude_check(cstrlist *patlist, char *string) { char pattern[1024]; int count; int i; count=strlist_count(patlist); for (i=0; i < count; i++) { strlist_getitem(patlist, i, pattern, sizeof(pattern)); if (fnmatch(pattern, string, 0)==0) return true; } return false; } int get_path_to_volume(char *newvolbuf, int bufsize, char *basepath, long curvol) { char prefix[PATH_MAX]; int pathlen; if ((pathlen=strlen(basepath))<4) // all archives terminates with ".fsa" { errprintf("archive has an invalid basepath: [%s]\n", basepath); return -1; } if (curvol==0) // first volume { if (realpath(basepath, newvolbuf)!=newvolbuf) snprintf(newvolbuf, bufsize, "%s", basepath); } else // not the first volume { memset(prefix, 0, sizeof(prefix)); memcpy(prefix, basepath, pathlen-2); snprintf(newvolbuf, bufsize, "%s%.2ld", prefix, (long)curvol); } return 0; } s64 get_device_size(char *partition) { s64 devsize; int fd; if ((fd=open64(partition, O_RDONLY|O_LARGEFILE))<0) return -1; if ((devsize=lseek64(fd, 0, SEEK_END))<0) return -1; close(fd); return devsize; } fsarchiver-0.8.5/src/fs_ntfs.c0000644000176100017610000002317213242523705013212 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include "fsarchiver.h" #include "devinfo.h" #include "dico.h" #include "common.h" #include "fs_ntfs.h" #include "filesys.h" #include "strlist.h" #include "error.h" int ntfs_mkfs(cdico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid) { char command[2048]; char buffer[2048]; char options[2048]; int exitst; u64 temp64; u32 temp32; u16 temp16; // there is no option that just displays the version and return 0 in mkfs.ntfs if (exec_command(command, sizeof(command), NULL, NULL, 0, NULL, 0, "mkfs.ntfs")!=0) { errprintf("mkfs.ntfs not found. please install ntfsprogs-2.0.0 on your system or check the PATH.\n"); return -1; } // ---- set the advanced filesystem settings from the dico memset(options, 0, sizeof(options)); strlcatf(options, sizeof(options), " %s ", fsoptions); if (strlen(mkfslabel) > 0) strlcatf(options, sizeof(options), " --label '%s' ", mkfslabel); else if (dico_get_string(d, 0, FSYSHEADKEY_FSLABEL, buffer, sizeof(buffer))==0 && strlen(buffer)>0) strlcatf(options, sizeof(options), " --label '%s' ", buffer); if (dico_get_u16(d, 0, FSYSHEADKEY_NTFSSECTORSIZE, &temp16)==0) strlcatf(options, sizeof(options), " -s %ld ", (long)temp16); if (dico_get_u32(d, 0, FSYSHEADKEY_NTFSCLUSTERSIZE, &temp32)==0) strlcatf(options, sizeof(options), " -c %ld ", (long)temp32); if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "mkfs.ntfs -f %s %s", partition, options)!=0 || exitst!=0) { errprintf("command [%s] failed\n", command); return -1; } // ---- preserve ntfs uuid (attribute saved only with fsarchiver>=0.5.8) if (dico_get_u64(d, 0, FSYSHEADKEY_NTFSUUID, &temp64)==0) ntfs_replace_uuid(partition, cpu_to_le64(temp64)); return 0; } int ntfs_getinfo(cdico *d, char *devname) { struct s_devinfo devinfo; struct s_ntfsinfo info; char bootsect[512]; int fd=-1; if (((fd=open64(devname, O_RDONLY|O_LARGEFILE))<0) || (read(fd, bootsect, sizeof(bootsect))!=sizeof(bootsect)) || (close(fd)<0)) { sysprintf("cannot open device or read bootsector on %s\n", devname); return -1; } // check signature in the boot sector if (memcmp(bootsect+3, "NTFS", 4) != 0) { errprintf("cannot find the ntfs signature on %s\n", devname); return -1; } // get device label from common code in libbklid if (get_devinfo(&devinfo, devname, -1, -1)!=0) { errprintf("get_devinfo(%s) failed\n", devname); return -1; } info.bytes_per_sector = le16_to_cpu(*((u16*)(bootsect+0xB))); info.sectors_per_clusters = le8_to_cpu(*((u8*)(bootsect+0xD))); info.bytes_per_cluster = info.bytes_per_sector * info.sectors_per_clusters; info.uuid = le64_to_cpu(*((u64*)(bootsect+0x48))); msgprintf(MSG_VERB2, "bytes_per_sector=[%lld]\n", (long long)info.bytes_per_sector); msgprintf(MSG_VERB2, "sectors_per_clusters=[%lld]\n", (long long)info.sectors_per_clusters); msgprintf(MSG_VERB2, "bytes_per_cluster=[%lld]\n", (long long)info.bytes_per_cluster); msgprintf(MSG_VERB2, "uuid=[%016llX]\n", (long long unsigned int)info.uuid); dico_add_u16(d, 0, FSYSHEADKEY_NTFSSECTORSIZE, info.bytes_per_sector); dico_add_u32(d, 0, FSYSHEADKEY_NTFSCLUSTERSIZE, info.bytes_per_cluster); dico_add_u64(d, 0, FSYSHEADKEY_NTFSUUID, info.uuid); // get label from library dico_add_string(d, 0, FSYSHEADKEY_FSLABEL, devinfo.label); msgprintf(MSG_VERB2, "ntfs_label=[%s]\n", devinfo.label); // minimum fsarchiver version required to restore dico_add_u64(d, 0, FSYSHEADKEY_MINFSAVERSION, FSA_VERSION_BUILD(0, 6, 4, 0)); // save mount options used at savefs so that restfs can use consistent mount options dico_add_string(d, 0, FSYSHEADKEY_MOUNTINFO, "streams_interface=xattr"); // may change in the future return 0; } int ntfs_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo) { char minversion[1024]; char streamif[1024]; int year=0, month=0, day=0; char stderrbuf[2048]; char command[2048]; char options[1024]; char delims[]="\n\r"; char *saveptr; char *result; u64 instver=0; int exitst; // init memset(options, 0, sizeof(options)); memset(stderrbuf, 0, sizeof(stderrbuf)); snprintf(minversion, sizeof(minversion), "ntfs-3g %.4d.%.2d.%.2d (standard release)", NTFS3G_MINVER_Y, NTFS3G_MINVER_M, NTFS3G_MINVER_D); // check that mount.ntfs-3g is available (don't check the exit status, it's not supposed to be 0) if (exec_command(command, sizeof(command), NULL, NULL, 0, stderrbuf, sizeof(stderrbuf), "ntfs-3g -h")!=0) { errprintf("ntfs-3g not found. please install %s\n" "or a newer version on your system or check the PATH.\n", minversion); return -1; } // check if there is a recent ntfs-3g version installed result=strtok_r(stderrbuf, delims, &saveptr); while (result != NULL && instver==0) { if (sscanf(result, "ntfs-3g %4d.%2d.%2d ", &year, &month, &day)==3) { instver=NTFS3G_VERSION(year, month, day); msgprintf(MSG_VERB2, "ntfs-3g detected version: year=[%.4d], month=[%.2d], day=[%.2d]\n", year, month, day); } result = strtok_r(NULL, delims, &saveptr); } if (instver < NTFS3G_VERSION(NTFS3G_MINVER_Y, NTFS3G_MINVER_M, NTFS3G_MINVER_D)) { errprintf("fsarchiver requires %s to operate. The detected version is too old\n", minversion); return -1; } else { msgprintf(MSG_VERB2, "ntfs-3g has been found: version is %d.%d.%d\n", year, month, day); } // if mntinfo is specified, check which mount option was used at savefs and use the same for consistency snprintf(streamif, sizeof(streamif), "xattr"); // set the default "streams_interface" (may change in the future) if ((mntinfo!=NULL) && (strlen(mntinfo)>0)) // if a mntinfo has been specified, respect its options { if (strstr(mntinfo, "streams_interface=xattr")!=NULL) // if "xattr" was used during savefs then use it for restfs snprintf(streamif, sizeof(streamif), "xattr"); else if (strstr(mntinfo, "streams_interface=windows")!=NULL) // if "windows" was used during savefs then use it for restfs snprintf(streamif, sizeof(streamif), "windows"); } // set mount options strlcatf(options, sizeof(options), " -o streams_interface=%s -o efs_raw ", streamif); if (flags & MS_RDONLY) strlcatf(options, sizeof(options), " -o ro "); // ---- set the advanced filesystem settings from the dico if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "ntfs-3g %s %s %s", options, partition, mntbuf)!=0 || exitst!=0) { errprintf("command [%s] failed, make sure a recent version of ntfs-3g is installed\n", command); return -1; } return 0; } int ntfs_umount(char *partition, char *mntbuf) { char command[2048]; int existst; if (exec_command(command, sizeof(command), NULL, NULL, 0, NULL, 0, "fusermount")!=0) { errprintf("fusermount not found. please install fuse on your system or check the PATH.\n"); return -1; } if (exec_command(command, sizeof(command), &existst, NULL, 0, NULL, 0, "fusermount -u %s", mntbuf)!=0 || existst!=0) { errprintf("cannot unmount [%s]\n", mntbuf); return -1; } return 0; } int ntfs_test(char *devname) { char bootsect[16384]; int fd=-1; if ((fd=open64(devname, O_RDONLY|O_LARGEFILE))<0) return false; if (read(fd, bootsect, sizeof(bootsect))!=sizeof(bootsect)) { close(fd); return false; } if (memcmp(bootsect+3, "NTFS", 4) != 0) { close(fd); return false; } close(fd); return true; } int ntfs_get_reqmntopt(char *partition, cstrlist *reqopt, cstrlist *badopt) { if (!reqopt || !badopt) return -1; strlist_add(reqopt, "streams_interface=xattr"); // may change in the future return 0; } int ntfs_replace_uuid(char *devname, u64 uuid) { u8 bootsect[512]; int fd=-1; if ((fd=open64(devname, O_RDWR|O_LARGEFILE))<0) { errprintf("cannot open(%s, O_RDWR)\n", devname); return -1; } if (read(fd, bootsect, sizeof(bootsect))!=sizeof(bootsect)) { errprintf("cannot read the boot sector on %s\n", devname); close(fd); return -1; } memcpy(bootsect+0x48, &uuid, sizeof(uuid)); if (lseek(fd, 0, SEEK_SET)!=0) { errprintf("lseek(fd, 0, SEEK_SET) failed\n"); close(fd); return -1; } if (write(fd, bootsect, sizeof(bootsect))!=sizeof(bootsect)) { errprintf("cannot modify the boot sector on %s\n", devname); close(fd); return -1; } close(fd); return 0; } fsarchiver-0.8.5/src/dico.h0000644000176100017610000000434213242523705012471 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __DICO_H__ #define __DICO_H__ #include "types.h" enum {DICO_ESUCCESS=0, DICO_ENOENT, DICO_EINVAL, DICO_EBADSIZE, DICO_EFULL, DICO_EMEM, DICO_EDUPLICATE, DICO_EINVALCHAR}; enum {DICTYPE_NULL=0, DICTYPE_U8, DICTYPE_U16, DICTYPE_U32, DICTYPE_U64, DICTYPE_DATA, DICTYPE_STRING}; struct s_dico; struct s_dicoitem; typedef struct s_dico cdico; typedef struct s_dicoitem cdicoitem; struct s_dico { struct s_dicoitem *head; }; struct s_dicoitem { u8 type; u8 section; u16 key; u16 size; char *data; cdicoitem *next; }; cdico *dico_alloc(); int dico_destroy(cdico *d); int dico_show(cdico *d, u8 section, char *debugtxt); int dico_count_all_sections(cdico *d); int dico_count_one_section(cdico *d, u8 section); int dico_add_data(cdico *d, u8 section, u16 key, const void *data, u16 size); int dico_add_generic(cdico *d, u8 section, u16 key, const void *data, u16 size, u8 type); int dico_get_generic(cdico *d, u8 section, u16 key, void *data, u16 maxsize, u16 *size); int dico_get_data(cdico *d, u8 section, u16 key, void *data, u16 maxsize, u16 *size); int dico_add_u16(cdico *d, u8 section, u16 key, u16 data); int dico_add_u32(cdico *d, u8 section, u16 key, u32 data); int dico_add_u64(cdico *d, u8 section, u16 key, u64 data); int dico_get_u16(cdico *d, u8 section, u16 key, u16 *data); int dico_get_u32(cdico *d, u8 section, u16 key, u32 *data); int dico_get_u64(cdico *d, u8 section, u16 key, u64 *data); int dico_add_string(cdico *d, u8 section, u16 key, const char *szstring); int dico_get_string(cdico *d, u8 section, u16 key, char *buffer, u16 bufsize); #endif // __DICO_H__ fsarchiver-0.8.5/src/syncthread.c0000644000176100017610000000473013242523705013713 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "fsarchiver.h" #include "fsarchiver.h" #include "syncthread.h" #include "queue.h" // queue use to share data between the three sort of threads cqueue g_queue; // filesystem bitmap used by do_extract() to say to threadio_readimg which filesystems to skip // eg: "g_fsbitmap[0]=1,g_fsbitmap[1]=0" means that we want to read filesystem 0 and skip fs 1 u8 g_fsbitmap[FSA_MAX_FSPERARCH]; // g_stopfillqueue is set to true when the threads that reads the queue wants to stop // either because there is an error or because it does not need the next data atomic_t g_stopfillqueue={ (false) }; atomic_t g_aborted={ (false) }; void set_stopfillqueue() { atomic_set(&g_stopfillqueue, true); } bool get_stopfillqueue() { return atomic_read(&g_stopfillqueue); } // how many secondary threads are running (compression/decompression and archio threads) atomic_t g_secthreads={ (0) }; void inc_secthreads() { (void)__sync_add_and_fetch(&g_secthreads.counter, 1); } void dec_secthreads() { (void)__sync_sub_and_fetch(&g_secthreads.counter, 1); } int get_secthreads() { return atomic_read(&g_secthreads); } bool get_interrupted() { return (get_abort()==true || get_stopfillqueue()==true); } // get_abort() returns true if a SIGINT/SIGTERM has been received (interrupted by the user) int get_abort() { int mysigs[]={SIGINT, SIGTERM, -1}; sigset_t mask_set; sigpending(&mask_set); int i; if (atomic_read(&g_aborted)==true) return true; if (sigpending(&mask_set)==0) { for (i=0; mysigs[i]!=-1; i++) { if (sigismember(&mask_set, mysigs[i])) { //msgprintf(MSG_FORCE, "get_terminate(): received signal %d\n", mysigs[i]); atomic_set(&g_aborted, true); return true; } } } return false; } fsarchiver-0.8.5/src/error.h0000644000176100017610000000456213242523705012710 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __ERROR_H__ #define __ERROR_H__ struct s_stats; typedef struct s_stats cstats; struct s_stats { u64 cnt_regfile; u64 cnt_dir; u64 cnt_symlink; u64 cnt_hardlink; u64 cnt_special; u64 err_regfile; u64 err_dir; u64 err_symlink; u64 err_hardlink; u64 err_special; }; int fsaprintf(int level, bool showerrno, bool showloc, const char *file, const char *fct, int line, char *format, ...) __attribute__ ((format (printf, 7, 8))); // ---- message levels enum {MSG_FORCE=0, // always show this messages whatever the level is MSG_VERB1=1, // normal messages that have to be shown when verbose>=1 (fsarchive -v) MSG_VERB2=2, // detailed messages that have to be shown when verbose>=2 (fsarchive -vv) MSG_STACK=3, // messages shown when a function exists (propagate error at upper level) MSG_DEBUG1=4, // debugging messages level 1 (very basic info) MSG_DEBUG2=5, // debugging messages level 2 MSG_DEBUG3=6, // debugging messages level 3 MSG_DEBUG4=7, // debugging messages level 4 MSG_DEBUG5=8 // debugging messages level 5 (very detailed debug) }; char *error_int_to_string(s64 err); // use sysprintf to print an error that follows a libc function and to show errno #define sysprintf(fmt, args...) fsaprintf(0, true, true, __FILE__, __FUNCTION__, __LINE__, fmt, ## args) // use errprintf to print an error that does not come from a libc function #define errprintf(fmt, args...) fsaprintf(0, false, true, __FILE__, __FUNCTION__, __LINE__, fmt, ## args) // use msgprintf with a level to show normal messages or debug messages #define msgprintf(level, fmt, args...) fsaprintf(level, false, level>=3, __FILE__, __FUNCTION__, __LINE__, fmt, ## args) #endif // __ERROR_H__ fsarchiver-0.8.5/src/oper_probe.h0000644000176100017610000000126713242523705013712 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __OPER_PROBE_H__ #define __OPER_PROBE_H__ int oper_probe(bool details); #endif // __OPER_PROBE_H__ fsarchiver-0.8.5/src/oper_save.h0000644000176100017610000000133113242523705013531 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __OPER_SAVE_H__ #define __OPER_SAVE_H__ int oper_save(char *archive, int argc, char **argv, int archtype); #endif // __OPER_SAVE_H__ fsarchiver-0.8.5/src/regmulti.h0000644000176100017610000000370013242523705013400 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __REGMULTI_H__ #define __REGMULTI_H__ struct s_dico; struct s_queue; struct s_regmulti; typedef struct s_regmulti cregmulti; struct s_regmulti { // common u32 count; // how many small files are in this struct u32 maxitems; // how many small files that struct can contains u32 maxblksize; // maximum size of a data block // linked list of headers struct s_dico *objhead[FSA_MAX_SMALLFILECOUNT]; // worst case: each file is just one byte: this is how many files we can store in the block // common block to be compressed char data[FSA_MAX_BLKSIZE]; u32 usedsize; // how many bytes are used in data }; int regmulti_empty(cregmulti *m); int regmulti_init(cregmulti *m, u32 maxblksize); int regmulti_count(cregmulti *m, struct s_dico *header, char *data, u32 datsize); bool regmulti_save_enough_space_for_new_file(cregmulti *m, u32 filesize); int regmulti_save_addfile(cregmulti *m, struct s_dico *header, char *data, u32 datsize); int regmulti_save_enqueue(cregmulti *m, struct s_queue *q, int fsid); int regmulti_rest_addheader(cregmulti *m, struct s_dico *header); int regmulti_rest_setdatablock(cregmulti *m, char *data, u32 datsize); int regmulti_rest_getfile(cregmulti *m, int index, struct s_dico **filehead, char *data, u64 *datsize, u32 bufsize); #endif // __REGMULTI_H__ fsarchiver-0.8.5/src/filesys.h0000644000176100017610000000407313242523705013232 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __FILESYS_H__ #define __FILESYS_H__ #define PROGVER(x, y, z) (((u64)x)<<16)+(((u64)y)<<8)+(((u64)z)<<0) struct s_strlist; struct s_dico; struct s_filesys; typedef struct s_filesys cfilesys; struct s_filesys { char *name; int (*mount)(char *partition, char *mntbuf, char *fsname, int flags, char *mntinfo); int (*umount)(char *partition, char *mntbuf); int (*getinfo)(struct s_dico *d, char *devname); int (*mkfs)(struct s_dico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid); int (*test)(char *partition); int (*reqmntopt)(char *partition, struct s_strlist *reqopt, struct s_strlist *badopt); bool support_for_xattr; bool support_for_acls; bool winattr; bool savesymtargettype; // we have to know the type of the target to recreate a symlink on ntfs bool stable; // say if the fsarchiver support for this filesystem is considered stable or not }; extern cfilesys filesys[]; int devcmp(char *dev1, char *dev2); int generic_get_spacestats(char *dev, char *mnt, char *text, int textlen); int generic_get_fsrwstatus(char *options); int generic_get_fstype(char *fsname, int *fstype); int generic_get_mntinfo(char *devname, int *readwrite, char *mntbuf, int maxmntbuf, char *optbuf, int maxoptbuf, char *fsbuf, int maxfsbuf); int generic_mount(char *partition, char *mntbuf, char *fsbuf, char *mntopt, int flags); char *format_prog_version(u64 version, char *bufdat, int buflen); int generic_umount(char *mntbuf); #endif // __FILESYS_H__ fsarchiver-0.8.5/src/logfile.c0000644000176100017610000000356413242523705013174 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include "fsarchiver.h" #include "logfile.h" #include "common.h" #include "error.h" int g_logfile=-1; int logfile_open() { char logpath[PATH_MAX]; char timestamp[1024]; char *logdir="/var/log"; format_time(timestamp, sizeof(timestamp), time(NULL)); snprintf(logpath, sizeof(logpath), "%s/fsarchiver_%s_%ld.log", logdir, timestamp, (long)getpid()); mkdir_recursive(logdir); g_logfile=open64(logpath, O_RDWR|O_CREAT|O_TRUNC|O_LARGEFILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (g_logfile>=0) { msgprintf(MSG_VERB1, "Creating logfile in %s\n", logpath); msgprintf(MSG_VERB1, "Running fsarchiver version=[%s], fileformat=[%s]\n", FSA_VERSION, FSA_FILEFORMAT); return FSAERR_SUCCESS; } else { sysprintf("Cannot create logfile in %s\n", logpath); return FSAERR_UNKNOWN; } } int logfile_close() { close(g_logfile); return FSAERR_SUCCESS; } int logfile_write(char *str, int len) { if (g_logfile>=0) return write(g_logfile, str, len); else return FSAERR_UNKNOWN; } fsarchiver-0.8.5/src/syncthread.h0000644000176100017610000000263513242523705013722 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __SYNCTHREAD_H__ #define __SYNCTHREAD_H__ // global threads sync data extern struct s_queue g_queue; // queue use to share data between the three sort of threads // global threads sync functions int get_abort(); // returns true if threads must exit because an error or signal received bool get_interrupted(); // returns true if either abort is true of stopfillqueue is true // say to the thread that is filling the queue to stop void set_stopfillqueue(); bool get_stopfillqueue(); // secondary threads counter void inc_secthreads(); void dec_secthreads(); int get_secthreads(); // filesystem bitmap used by do_extract() to say to threadio_readimg which filesystems to skip // eg: "g_fsbitmap[0]=1,g_fsbitmap[1]=0" means that we want to read filesystem 0 and skip fs 1 extern u8 g_fsbitmap[FSA_MAX_FSPERARCH]; #endif // __SYNCTHREAD_H__ fsarchiver-0.8.5/src/datafile.h0000644000176100017610000000177513242523705013333 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __DATAFILE_H__ #define __DATAFILE_H__ #include "types.h" struct s_datafile; typedef struct s_datafile cdatafile; cdatafile *datafile_alloc(); int datafile_destroy(cdatafile *f); int datafile_open_write(cdatafile *f, char *path, bool simul, bool sparse); int datafile_write(cdatafile *f, char *data, u64 len); int datafile_close(cdatafile *f, u8 *md5bufdat, int md5bufsize); #endif // __DATAFILE_H__ fsarchiver-0.8.5/src/comp_lz4.c0000644000176100017610000000362313217127345013300 00000000000000 /* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2017 Cristian Vazquez. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "fsarchiver.h" #include "common.h" #include "comp_lz4.h" #include "error.h" #ifdef OPTION_LZ4_SUPPORT int compress_block_lz4(u64 origsize, u64 *compsize, u8 *origbuf, u8 *compbuf, u64 compbufsize, int level) { int destsize=compbufsize; int res; #define LZ4_VERSION (LZ4_VERSION_MAJOR*10 + LZ4_VERSION_MINOR) #if LZ4_VERSION >= 17 res=LZ4_compress_default((const char*)origbuf, (char*)compbuf, (int)origsize, destsize); if (res==0){ errprintf("LZ4_compress_default(): failed.\n"); return FSAERR_UNKNOWN; } #else res=LZ4_compress((const char*)origbuf, (char*)compbuf, (int)origsize); if (res==0){ errprintf("LZ4_compress(): failed.\n"); return FSAERR_UNKNOWN; } #endif // LZ4_VERSION if (res > 0){ *compsize=(u64)res; return FSAERR_SUCCESS; } return FSAERR_UNKNOWN; } int uncompress_block_lz4(u64 compsize, u64 *origsize, u8 *origbuf, u64 origbufsize, u8 *compbuf) { int destsize=origbufsize; int res; if((res=LZ4_decompress_safe((char*)compbuf, (char*)origbuf, compsize, destsize)) > 0){ *origsize=(u64)res; return FSAERR_SUCCESS; } errprintf("LZ4_decompress_safe() failed, res=%d\n", res); return FSAERR_UNKNOWN; } #endif //OPTION_LZ4_SUPPORT fsarchiver-0.8.5/src/comp_bzip2.h0000644000176100017610000000156613242523705013624 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __COMPRESS_BZIP2_H__ #define __COMPRESS_BZIP2_H__ int compress_block_bzip2(u64 origsize, u64 *compsize, u8 *origbuf, u8 *compbuf, u64 compbufsize, int level); int uncompress_block_bzip2(u64 compsize, u64 *origsize, u8 *origbuf, u64 origbufsize, u8 *compbuf); #endif // __COMPRESS_BZIP2_H__ fsarchiver-0.8.5/src/dichl.c0000644000176100017610000000575513242523705012642 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include "fsarchiver.h" #include "dichl.h" #include "common.h" #include "error.h" cdichl *dichl_alloc() { cdichl *d; if ((d=malloc(sizeof(cdichl)))==NULL) return NULL; d->head=NULL; return d; } int dichl_destroy(cdichl *d) { cdichlitem *item, *next; if (d==NULL) return -1; item=d->head; while (item!=NULL) { next=item->next; free(item->str); free(item); item=next; } free(d); return 0; } int dichl_add(cdichl *d, u64 key1, u64 key2, char *str) { cdichlitem *item, *lnew, *last; int len; if (d==NULL || !str) { errprintf("invalid parameters\n"); return -1; } len=strlen(str); // allocate object lnew=malloc(sizeof(cdichlitem)); if (!lnew) { errprintf("malloc(%ld) failed: out of memory\n", (long)sizeof(cdichlitem)); return -1; } memset(lnew, 0, sizeof(cdichlitem)); lnew->str=malloc(len+1); if (!lnew->str) { free(lnew); errprintf("malloc(%ld) failed: out of memory\n", (long)len+1); return -1; } memcpy(lnew->str, str, len+1); lnew->key1=key1; lnew->key2=key2; lnew->next=NULL; // go to the end of the item and check for duplicates if (d->head==NULL) // item is empty { d->head=lnew; } else // item is not empty { for (item=d->head; item!=NULL; item=item->next) { last=item; if (item->key1==key1 && item->key2==key2) { errprintf("dichl_add_internal(): item with key1=%ld and key2=%ld is already in dico\n", (long)item->key1, (long)item->key2); return -1; } } last->next=lnew; } return 0; } int dichl_get(cdichl *d, u64 key1, u64 key2, char *buf, int bufsize) { cdichlitem *item; int len; if (d==NULL || !buf) { errprintf("invalid dichl\n"); return -1; } for (item=d->head; item!=NULL; item=item->next) { if ((item!=NULL) && (item->key1==key1) && (item->key2==key2)) { len=strlen(item->str); if (bufsizestr); return 0; } } return -3; // not found } fsarchiver-0.8.5/src/filesys.c0000644000176100017610000003033613242523705013226 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "fsarchiver.h" #include "common.h" #include "filesys.h" #include "fs_ext2.h" #include "fs_reiserfs.h" #include "fs_reiser4.h" #include "fs_btrfs.h" #include "fs_xfs.h" #include "fs_jfs.h" #include "fs_ntfs.h" #include "fs_vfat.h" #include "error.h" cfilesys filesys[]= { {"ext2", extfs_mount, extfs_umount, extfs_getinfo, ext2_mkfs, ext2_test, extfs_get_reqmntopt, true, true, false, false, true}, {"ext3", extfs_mount, extfs_umount, extfs_getinfo, ext3_mkfs, ext3_test, extfs_get_reqmntopt, true, true, false, false, true}, {"ext4", extfs_mount, extfs_umount, extfs_getinfo, ext4_mkfs, ext4_test, extfs_get_reqmntopt, true, true, false, false, true}, {"reiserfs", reiserfs_mount, reiserfs_umount, reiserfs_getinfo, reiserfs_mkfs, reiserfs_test, reiserfs_get_reqmntopt, true, true, false, false, true}, {"reiser4", reiser4_mount, reiser4_umount, reiser4_getinfo, reiser4_mkfs, reiser4_test, reiser4_get_reqmntopt, true, true, false, false, true}, {"btrfs", btrfs_mount, btrfs_umount, btrfs_getinfo, btrfs_mkfs, btrfs_test, btrfs_get_reqmntopt, true, true, false, false, true}, {"xfs", xfs_mount, xfs_umount, xfs_getinfo, xfs_mkfs, xfs_test, xfs_get_reqmntopt, true, true, false, false, true}, {"jfs", jfs_mount, jfs_umount, jfs_getinfo, jfs_mkfs, jfs_test, jfs_get_reqmntopt, true, true, false, false, true}, {"ntfs", ntfs_mount, ntfs_umount, ntfs_getinfo, ntfs_mkfs, ntfs_test, ntfs_get_reqmntopt, false, false, true, true, false}, {"vfat", vfat_mount, vfat_umount, vfat_getinfo, vfat_mkfs, vfat_test, vfat_get_reqmntopt, false, false, false, false, true}, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, false, false, false, false} }; // return the index of a filesystem in the filesystem table int generic_get_fstype(char *fsname, int *fstype) { int i; for (i=0; filesys[i].name; i++) { if (strcmp(filesys[i].name, fsname)==0) { *fstype=i; return 0; } } *fstype=-1; return -1; } int generic_get_spacestats(char *dev, char *mnt, char *text, int textlen) { struct statfs stf; struct stat64 st; // init memset(text, 0, textlen); if (stat64(dev, &st)!=0) return -1; if (statfs(dev, &stf)!=0) return -1; if (!S_ISBLK(st.st_mode)) return -1; else return 0; } int generic_get_fsrwstatus(char *options) { char temp[FSA_MAX_FSNAMELEN]; char delims[]=","; char *saveptr; char *result; snprintf(temp, sizeof(temp), "%s", options); result=strtok_r(temp, delims, &saveptr); while(result != NULL) { if (strcmp(result, "rw")==0) return 1; // true result = strtok_r(NULL, delims, &saveptr); } return 0; // false } int devcmp(char *dev1, char *dev2) { struct stat64 devstat[2]; char *devname[]={dev1, dev2}; int i; for (i=0; i<2; i++) { if (strncmp(devname[i], "/dev/", 5)!=0) return -1; errno=0; if (stat64(devname[i], &devstat[i]) != 0) { if (errno == ENOENT) errprintf("Warning: node for device [%s] does not exist in /dev/\n", devname[i]); else errprintf("Warning: cannot get details for device [%s]\n", devname[i]); return -1; } if (!S_ISBLK(devstat[0].st_mode)) { errprintf("Warning: [%s] is not a block device\n", devname[i]); return -1; } } return (devstat[0].st_rdev==devstat[1].st_rdev) ? 0 : 1; } int generic_get_mntinfo(char *devname, int *readwrite, char *mntbuf, int maxmntbuf, char *optbuf, int maxoptbuf, char *fsbuf, int maxfsbuf) { char col_fs[FSA_MAX_FSNAMELEN]; int devisroot=false; struct stat64 devstat; struct stat64 rootstat; long major, minor; char delims[]=" \t\n:"; struct utsname suname; char col_dev[128]; char col_mnt[128]; char col_opt[128]; char line[1024]; char temp[2048]; char *saveptr; char *result; FILE *f; int sep; int i; // init uname(&suname); *readwrite=-1; // unknown memset(mntbuf, 0, maxmntbuf); memset(optbuf, 0, maxoptbuf); // ---- 1. attempt to find device in "/proc/self/mountinfo" if ((stat64(devname, &devstat)==0) && ((f=fopen("/proc/self/mountinfo","rb"))!=NULL)) { msgprintf(MSG_DEBUG1, "device=[%s] has major=[%ld] and minor=[%ld]\n", devname, (long)major(devstat.st_rdev), (long)minor(devstat.st_rdev)); while(!feof(f)) { if (stream_readline(f, line, 1024)>1) { result=strtok_r(line, delims, &saveptr); major = -1; minor = -1; sep = -1; col_dev[0]=col_mnt[0]=col_fs[0]=col_opt[0]=0; for(i=0; result != NULL; i++) { if (strcmp(result, "-") == 0) // found separator sep = i; switch (i) { case 2: major = atol(result); break; case 3: minor = atol(result); break; case 5: snprintf(col_mnt, sizeof(col_mnt), "%s", result); break; } if ((sep != -1) && (i == sep + 1)) snprintf(col_fs, sizeof(col_fs), "%s", result); if ((sep != -1) && (i == sep + 3)) snprintf(col_opt, sizeof(col_opt), "%s", result); result = strtok_r(NULL, delims, &saveptr); } msgprintf(MSG_DEBUG1, "mountinfo entry: major=[%ld] minor=[%ld] filesys=[%s] col_opt=[%s] col_mnt=[%s]\n", major, minor, col_fs, col_opt, col_mnt); if ((major==major(devstat.st_rdev)) && (minor==minor(devstat.st_rdev))) { if (generic_get_spacestats(devname, col_mnt, temp, sizeof(temp))==0) { msgprintf(MSG_DEBUG1, "found mountinfo entry for device=[%s]: mnt=[%s] fs=[%s] opt=[%s]\n", devname, col_mnt, col_fs, col_opt); *readwrite=generic_get_fsrwstatus(col_opt); snprintf(mntbuf, maxmntbuf, "%s", col_mnt); snprintf(optbuf, maxoptbuf, "%s", col_opt); snprintf(fsbuf, maxfsbuf, "%s", col_fs); fclose(f); return 0; } } } } fclose(f); } // ---- 2. if there is no /proc/self/mountinfo then use "/proc/mounts" instead // workaround for systems not having the "/dev/root" node entry. // There are systems showing "/dev/root" in "/proc/mounts" instead // of the actual root partition such as "/dev/sda1". // The consequence is that fsarchiver won't be able to realize // that the device it is archiving (such as "/dev/sda1") is the // same as "/dev/root" and that it is actually mounted. This // function would then say that the "/dev/sda1" device is not mounted // and fsarchiver would try to mount it and mount() fails with EBUSY if (stat64(devname, &devstat)==0 && stat64("/", &rootstat)==0 && (devstat.st_rdev==rootstat.st_dev)) { devisroot=true; msgprintf(MSG_VERB1, "device [%s] is the root device\n", devname); } // 2. check device in "/proc/mounts" (typical case) if ((f=fopen("/proc/mounts","rb"))==NULL) { sysprintf("Cannot open /proc/mounts\n"); return 1; } while(!feof(f)) { if (stream_readline(f, line, 1024)>1) { result=strtok_r(line, delims, &saveptr); col_dev[0]=col_mnt[0]=col_fs[0]=col_opt[0]=0; for(i=0; result != NULL && i<=3; i++) { switch (i) // only the second word is a mount-point { case 0: snprintf(col_dev, sizeof(col_dev), "%s", result); break; case 1: snprintf(col_mnt, sizeof(col_mnt), "%s", result); break; case 2: snprintf(col_fs, sizeof(col_fs), "%s", result); break; case 3: snprintf(col_opt, sizeof(col_opt), "%s", result); break; } result = strtok_r(NULL, delims, &saveptr); } if ((devisroot==true) && (strcmp(col_mnt, "/")==0) && (strcmp(col_fs, "rootfs")!=0)) snprintf(col_dev, sizeof(col_dev), "%s", devname); msgprintf(MSG_DEBUG1, "mount entry: col_dev=[%s] col_mnt=[%s] col_fs=[%s] col_opt=[%s]\n", col_dev, col_mnt, col_fs, col_opt); if (devcmp(col_dev, devname)==0) { if (generic_get_spacestats(col_dev, col_mnt, temp, sizeof(temp))==0) { msgprintf(MSG_DEBUG1, "found mount entry for device=[%s]: mnt=[%s] fs=[%s] opt=[%s]\n", devname, col_mnt, col_fs, col_opt); *readwrite=generic_get_fsrwstatus(col_opt); snprintf(mntbuf, maxmntbuf, "%s", col_mnt); snprintf(optbuf, maxoptbuf, "%s", col_opt); snprintf(fsbuf, maxfsbuf, "%s", col_fs); fclose(f); return 0; } } } } fclose(f); return -1; } int generic_mount(char *partition, char *mntbuf, char *fsbuf, char *mntopt, int flags) { if (!partition || !mntbuf || !fsbuf || !fsbuf[0]) { errprintf("invalid parameters\n"); return -1; } // optimization: don't change access times on the original partition flags|=MS_NOATIME|MS_NODIRATIME; // if fsbuf is not empty, use the filesystem which is specified msgprintf(MSG_DEBUG1, "trying to mount [%s] on [%s] as [%s] with options [%s]\n", partition, mntbuf, fsbuf, mntopt); if (mount(partition, mntbuf, fsbuf, flags, mntopt)!=0) { errprintf("partition [%s] cannot be mounted on [%s] as [%s] with options [%s]\n", partition, mntbuf, fsbuf, mntopt); return -1; } msgprintf(MSG_VERB2, "partition [%s] was successfully mounted on [%s] as [%s] with options [%s]\n", partition, mntbuf, fsbuf, mntopt); return 0; } int generic_umount(char *mntbuf) { int res=0; int i; if (!mntbuf) { errprintf("invalid param: mntbuf is null\n"); return -1; } msgprintf(MSG_DEBUG1, "generic_umount(%s)\n", mntbuf); for (i=0, errno=0 ; (i < 4) && (res=umount2(mntbuf, 0)!=0) && (errno==EBUSY) ; i++) { sync(); sleep(i+1); } if (res!=0) errprintf("Failed to umount device %s after %d attempts\n", mntbuf, (int)i); return res; } char *format_prog_version(u64 version, char *bufdat, int buflen) { snprintf(bufdat, buflen, "%ld.%ld.%ld", (long)(version>>16&0xFF), (long)(version>>8&0xFF), (long)(version>>0&0xFF)); return bufdat; } fsarchiver-0.8.5/src/fs_reiser4.h0000644000176100017610000000361413242523705013621 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __FS_REISER4_H__ #define __FS_REISER4_H__ struct s_dico; struct s_strlist; int reiser4_mkfs(struct s_dico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid); int reiser4_getinfo(struct s_dico *d, char *devname); int reiser4_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo); int reiser4_get_reqmntopt(char *partition, struct s_strlist *reqopt, struct s_strlist *badopt); int reiser4_umount(char *partition, char *mntbuf); int reiser4_test(char *devname); #define REISERFS4_SUPER_MAGIC "ReIsEr4" #define MAGIC_SIZE 16 #define REISER4_DISK_OFFSET_IN_BYTES (64 * 1024) typedef struct reiser4_master_sb reiser4_master_sb; struct reiser4_master_sb { char magic[16]; // "ReIsEr4" u16 disk_plugin_id; // id of disk layout plugin u16 blocksize; char uuid[16]; // unique id char label[16]; // filesystem label u64 diskmap; // location of the diskmap. 0 if not present } __attribute__ ((__packed__)); /*struct format40_super { u64 sb_block_count; u64 sb_free_blocks; u64 sb_root_block; u64 sb_oid[2]; u64 sb_flushes; u32 sb_mkfs_id; char sb_magic[MAGIC_SIZE]; u16 sb_tree_height; u16 sb_policy; u64 sb_flags; char sb_unused[432]; } __attribute__((packed));*/ #endif // __FS_REISER4_H__ fsarchiver-0.8.5/src/thread_comp.h0000644000176100017610000000142613242523705014040 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __THREAD_COMP_H__ #define __THREAD_COMP_H__ enum {COMPTHR_COMPRESS=1, COMPTHR_DECOMPRESS=2}; void *thread_comp_fct(void *args); void *thread_decomp_fct(void *args); #endif // __THREAD_COMP_H__ fsarchiver-0.8.5/src/fs_btrfs.c0000644000176100017610000001617713242523705013367 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include "fsarchiver.h" #include "dico.h" #include "common.h" #include "fs_btrfs.h" #include "filesys.h" #include "strlist.h" #include "error.h" int btrfs_check_compatibility(u64 compat, u64 incompat, u64 ro_compat) { // to preserve the filesystem attributes, fsa must know all the features including the COMPAT ones if (compat & ~FSA_BTRFS_FEATURE_COMPAT_SUPP) return -1; if (incompat & ~FSA_BTRFS_FEATURE_INCOMPAT_SUPP) return -1; if (ro_compat & ~FSA_BTRFS_FEATURE_COMPAT_RO_SUPP) return -1; return 0; } int btrfs_mkfs(cdico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid) { char command[2048]; char buffer[2048]; char options[2048]; u64 compat_flags; u64 incompat_flags; u64 compat_ro_flags; int exitst; u64 temp64; // ---- get original filesystem features (if the original filesystem was a btrfs) if (dico_get_u64(d, 0, FSYSHEADKEY_BTRFSFEATURECOMPAT, &compat_flags)!=0 || dico_get_u64(d, 0, FSYSHEADKEY_BTRFSFEATUREINCOMPAT, &incompat_flags)!=0 || dico_get_u64(d, 0, FSYSHEADKEY_BTRFSFEATUREROCOMPAT, &compat_ro_flags)!=0) { // dont fail the original filesystem may not be a btrfs. in that case set defaults features compat_flags=0; incompat_flags=0; compat_ro_flags=0; } // ---- check there is no unsuported feature in that filesystem if (btrfs_check_compatibility(compat_flags, incompat_flags, compat_ro_flags)!=0) { errprintf("this filesystem has features which are not supported by this fsarchiver version.\n"); return -1; } // ---- there is no option that just displays the version and return 0 in mkfs.btrfs-0.16 if (exec_command(command, sizeof(command), NULL, NULL, 0, NULL, 0, "mkfs.btrfs")!=0) { errprintf("mkfs.btrfs not found. please install btrfs-progs on your system or check the PATH.\n"); return -1; } // ---- set the advanced filesystem settings from the dico memset(options, 0, sizeof(options)); strlcatf(options, sizeof(options), " %s ", fsoptions); if (strlen(mkfslabel) > 0) strlcatf(options, sizeof(options), " -L '%s' ", mkfslabel); else if (dico_get_string(d, 0, FSYSHEADKEY_FSLABEL, buffer, sizeof(buffer))==0 && strlen(buffer)>0) strlcatf(options, sizeof(options), " -L '%s' ", buffer); if (strlen(mkfsuuid) > 0) strlcatf(options, sizeof(options), " -U '%s' ", mkfsuuid); else if (dico_get_string(d, 0, FSYSHEADKEY_FSUUID, buffer, sizeof(buffer))==0) strlcatf(options, sizeof(options), " -U '%s' ", buffer); if (dico_get_u64(d, 0, FSYSHEADKEY_FSBTRFSSECTORSIZE, &temp64)==0) strlcatf(options, sizeof(options), " -s %ld ", (long)temp64); if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "mkfs.btrfs -f %s %s", partition, options)!=0 || exitst!=0) { errprintf("command [%s] failed\n", command); return -1; } return 0; } int btrfs_getinfo(cdico *d, char *devname) { struct btrfs_super_block sb; char uuid[512]; u16 temp32; int ret=0; int fd; if ((fd=open64(devname, O_RDONLY|O_LARGEFILE))<0) { ret=-1; errprintf("cannot open(%s, O_RDONLY)\n", devname); goto btrfs_read_sb_return; } if (lseek(fd, BTRFS_SUPER_INFO_OFFSET, SEEK_SET)!=BTRFS_SUPER_INFO_OFFSET) { ret=-2; errprintf("cannot lseek(fd, BTRFS_SUPER_INFO_OFFSET, SEEK_SET) on %s\n", devname); goto btrfs_read_sb_close; } if (read(fd, &sb, sizeof(sb))!=sizeof(sb)) { ret=-3; errprintf("cannot read the btrfs superblock on device [%s]\n", devname); goto btrfs_read_sb_close; } if (strncmp((char*)&sb.magic, BTRFS_MAGIC, sizeof(sb.magic))!=0) { ret=-4; errprintf("magic different from expectations superblock on [%s]: magic=[%.8s], expected=[%.8s]\n", devname, (char*)&sb.magic, BTRFS_MAGIC); goto btrfs_read_sb_close; } // ---- label msgprintf(MSG_DEBUG1, "btrfs_label=[%s]\n", sb.label); dico_add_string(d, 0, FSYSHEADKEY_FSLABEL, (char*)sb.label); // ---- uuid /*if ((str=e2p_uuid2str(sb.dev_item.fsid))!=NULL) dico_add_string(d, 0, FSYSHEADKEY_FSUUID, str);*/ memset(uuid, 0, sizeof(uuid)); uuid_unparse_lower((u8*)sb.dev_item.fsid, uuid); dico_add_string(d, 0, FSYSHEADKEY_FSUUID, uuid); msgprintf(MSG_DEBUG1, "btrfs_uuid=[%s]\n", uuid); // ---- sector size temp32=le32_to_cpu(sb.sectorsize); dico_add_u64(d, 0, FSYSHEADKEY_FSBTRFSSECTORSIZE, temp32); msgprintf(MSG_DEBUG1, "btrfs_sectorsize=[%ld]\n", (long)temp32); // ---- filesystem features dico_add_u64(d, 0, FSYSHEADKEY_BTRFSFEATURECOMPAT, le64_to_cpu(sb.compat_flags)); dico_add_u64(d, 0, FSYSHEADKEY_BTRFSFEATUREINCOMPAT, le64_to_cpu(sb.incompat_flags)); dico_add_u64(d, 0, FSYSHEADKEY_BTRFSFEATUREROCOMPAT, le64_to_cpu(sb.compat_ro_flags)); if (btrfs_check_compatibility(le64_to_cpu(sb.compat_flags), le64_to_cpu(sb.incompat_flags), le64_to_cpu(sb.compat_ro_flags))!=0) { errprintf("this filesystem has features which are not supported by this fsarchiver version.\n"); return -1; } // ---- minimum fsarchiver version required to restore dico_add_u64(d, 0, FSYSHEADKEY_MINFSAVERSION, FSA_VERSION_BUILD(0, 6, 4, 0)); btrfs_read_sb_close: close(fd); btrfs_read_sb_return: return ret; } int btrfs_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo) { return generic_mount(partition, mntbuf, fsbuf, NULL, flags); } int btrfs_umount(char *partition, char *mntbuf) { return generic_umount(mntbuf); } int btrfs_test(char *devname) { struct btrfs_super_block sb; int fd; if ((fd=open64(devname, O_RDONLY|O_LARGEFILE))<0) return false; if (lseek(fd, BTRFS_SUPER_INFO_OFFSET, SEEK_SET)!=BTRFS_SUPER_INFO_OFFSET) { close(fd); return false; } if (read(fd, &sb, sizeof(sb))!=sizeof(sb)) { close(fd); return false; } if (strncmp((char*)&sb.magic, BTRFS_MAGIC, sizeof(sb.magic))!=0) { close(fd); return false; } close(fd); return true; } int btrfs_get_reqmntopt(char *partition, cstrlist *reqopt, cstrlist *badopt) { if (!reqopt || !badopt) return -1; strlist_add(badopt, "noacl"); return 0; } fsarchiver-0.8.5/src/archinfo.c0000644000176100017610000001254013242523705013336 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "fsarchiver.h" #include "dico.h" #include "common.h" #include "archinfo.h" #include "archreader.h" #include "error.h" char *compalgostr(int algo) { switch (algo) { case COMPRESS_NONE: return "none"; case COMPRESS_LZO: return "lzo"; case COMPRESS_GZIP: return "gzip"; case COMPRESS_BZIP2: return "bzip2"; case COMPRESS_LZMA: return "lzma"; case COMPRESS_LZ4: return "lz4"; case COMPRESS_ZSTD: return "zstd"; default: return "unknown"; } } char *cryptalgostr(int algo) { switch (algo) { case ENCRYPT_NONE: return "none"; case ENCRYPT_BLOWFISH: return "blowfish"; default: return "unknown"; } } int archinfo_show_mainhead(carchreader *ai, cdico *dicomainhead) { char buffer[256]; if (!ai || !dicomainhead) { errprintf("a parameter is null\n"); return -1; } msgprintf(MSG_FORCE, "====================== archive information ======================\n"); msgprintf(MSG_FORCE, "Archive type: \t\t\t%s\n", (ai->archtype==ARCHTYPE_FILESYSTEMS)?"filesystems":"flat files"); if ((ai->archtype==ARCHTYPE_FILESYSTEMS)) msgprintf(0, "Filesystems count: \t\t%ld\n", (long)ai->fscount); msgprintf(MSG_FORCE, "Archive id: \t\t\t%.8x\n", (unsigned int)ai->archid); msgprintf(MSG_FORCE, "Archive file format: \t\t%s\n", ai->filefmt); msgprintf(MSG_FORCE, "Archive created with: \t\t%s\n", ai->creatver); msgprintf(MSG_FORCE, "Archive creation date: \t\t%s\n", format_time(buffer, sizeof(buffer), ai->creattime)); msgprintf(MSG_FORCE, "Archive label: \t\t\t%s\n", ai->label); if (ai->minfsaver > 0) // fsarchiver < 0.6.7 had no per-archive minfsaver version requirement msgprintf(MSG_FORCE, "Minimum fsarchiver version:\t%d.%d.%d.%d\n", (int)FSA_VERSION_GET_A(ai->minfsaver), (int)FSA_VERSION_GET_B(ai->minfsaver), (int)FSA_VERSION_GET_C(ai->minfsaver), (int)FSA_VERSION_GET_D(ai->minfsaver)); msgprintf(MSG_FORCE, "Compression level: \t\t%d (%s level %d)\n", ai->fsacomp, compalgostr(ai->compalgo), ai->complevel); msgprintf(MSG_FORCE, "Encryption algorithm: \t\t%s\n", cryptalgostr(ai->cryptalgo)); msgprintf(MSG_FORCE, "\n"); return 0; } int archinfo_show_fshead(cdico *dicofshead, int fsid) { char magic[FSA_SIZEOF_MAGIC+1]; char fsbuf[FSA_MAX_FSNAMELEN]; u64 temp64; u64 fsbytestotal; u64 fsbytesused; char buffer[256]; char fslabel[256]; char fsuuid[256]; char fsorigdev[256]; // init memset(magic, 0, sizeof(magic)); if (!dicofshead) { errprintf("dicofshead is null\n"); return -1; } if (dico_get_data(dicofshead, 0, FSYSHEADKEY_FILESYSTEM, fsbuf, sizeof(fsbuf), NULL)!=0) { errprintf("cannot find FSYSHEADKEY_FILESYSTEM in filesystem-header\n"); return -1; } if (dico_get_u64(dicofshead, 0, FSYSHEADKEY_BYTESTOTAL, &fsbytestotal)!=0) { errprintf("cannot find FSYSHEADKEY_BYTESTOTAL in filesystem-header\n"); return -1; } if (dico_get_u64(dicofshead, 0, FSYSHEADKEY_BYTESUSED, &fsbytesused)!=0) { errprintf("cannot find FSYSHEADKEY_BYTESUSED in filesystem-header\n"); return -1; } if (dico_get_string(dicofshead, 0, FSYSHEADKEY_FSLABEL, fslabel, sizeof(fslabel))<0) snprintf(fslabel, sizeof(fslabel), ""); if (dico_get_string(dicofshead, 0, FSYSHEADKEY_ORIGDEV, fsorigdev, sizeof(fsorigdev))<0) snprintf(fsorigdev, sizeof(fsorigdev), ""); // filesystem uuid: maybe an ntfs uuid or an unix uuid snprintf(fsuuid, sizeof(fsuuid), ""); if (dico_get_u64(dicofshead, 0, FSYSHEADKEY_NTFSUUID, &temp64)==0) snprintf(fsuuid, sizeof(fsuuid), "%016llX", (long long unsigned int)temp64); else if (dico_get_string(dicofshead, 0, FSYSHEADKEY_FSUUID, buffer, sizeof(buffer))==0 && strlen(buffer)==36) snprintf(fsuuid, sizeof(fsuuid), "%s", buffer); msgprintf(MSG_FORCE, "===================== filesystem information ====================\n"); msgprintf(MSG_FORCE, "Filesystem id in archive: \t%ld\n", (long)fsid); msgprintf(MSG_FORCE, "Filesystem format: \t\t%s\n", fsbuf); msgprintf(MSG_FORCE, "Filesystem label: \t\t%s\n", fslabel); msgprintf(MSG_FORCE, "Filesystem uuid: \t\t%s\n", fsuuid); msgprintf(MSG_FORCE, "Original device: \t\t%s\n", fsorigdev); msgprintf(MSG_FORCE, "Original filesystem size: \t%s (%lld bytes)\n", format_size(fsbytestotal, buffer, sizeof(buffer), 'h'), (long long)fsbytestotal); msgprintf(MSG_FORCE, "Space used in filesystem: \t%s (%lld bytes)\n", format_size(fsbytesused, buffer, sizeof(buffer), 'h'), (long long)fsbytesused); msgprintf(MSG_FORCE, "\n"); return 0; } fsarchiver-0.8.5/src/logfile.h0000644000176100017610000000136713242523705013200 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __LOGFILE_H__ #define __LOGFILE_H__ extern int g_logfile; int logfile_open(); int logfile_close(); int logfile_write(char *str, int len); #endif // __LOGFILE_H__ fsarchiver-0.8.5/src/devinfo.c0000644000176100017610000001256013242523705013201 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "fsarchiver.h" #include "devinfo.h" #include "common.h" #include "fs_ext2.h" #include "error.h" int get_devinfo(struct s_devinfo *outdev, char *indevname, int min, int maj) { char sysblkdevname[512]; blkid_tag_iterate iter; char sysblkinfo[PATH_MAX]; const char *type, *value; struct stat64 statbuf; struct dirent *dir; char temp[PATH_MAX]; blkid_dev dev; DIR *dirdesc; FILE *finfo; int found; int fd; int i; // init memset(outdev, 0, sizeof(struct s_devinfo)); // defaults values outdev->devtype=BLKDEV_INVALID; snprintf(outdev->label, sizeof(outdev->label), ""); snprintf(outdev->uuid, sizeof(outdev->uuid), ""); snprintf(outdev->fsname, sizeof(outdev->fsname), ""); // check the name starts with "/dev/" if ((strlen(indevname) < 5) || (memcmp(indevname, "/dev/", 5)!=0)) return -1; // get short name ("/dev/sda1" -> "sda1") snprintf(outdev->devname, sizeof(outdev->devname), "%s", indevname+5); // skip "/dev/" // get long name if there is one (eg: LVM / devmapper) snprintf(outdev->longname, sizeof(outdev->longname), "%s", indevname); if ((dirdesc=opendir("/dev/mapper"))!=NULL) { found=false; while (((dir=readdir(dirdesc)) != NULL) && found==false) { snprintf(temp, sizeof(temp), "/dev/mapper/%s", dir->d_name); if ((stat64(temp, &statbuf)==0) && S_ISBLK(statbuf.st_mode) && (major(statbuf.st_rdev)==maj) && (minor(statbuf.st_rdev)==min)) { snprintf(outdev->longname, sizeof(outdev->longname), "%s", temp); found=true; } } closedir(dirdesc); } // get device basic info (size, major, minor) if (((fd=open64(outdev->longname, O_RDONLY|O_LARGEFILE))<0) || ((outdev->devsize=lseek64(fd, 0, SEEK_END))<0) || (fstat64(fd, &statbuf)!=0) || (!S_ISBLK(statbuf.st_mode)) || (close(fd)<0)) return -1; outdev->rdev=statbuf.st_rdev; outdev->major=major(statbuf.st_rdev); outdev->minor=minor(statbuf.st_rdev); format_size(outdev->devsize, outdev->txtsize, sizeof(outdev->txtsize), 'h'); if (outdev->devsize==1024) // ignore extended partitions return -1; // devname shown in /sys/block (eg for HP-cciss: "cciss/c0d0" -> "cciss!c0d0") snprintf(sysblkdevname, sizeof(sysblkdevname), "%s", outdev->devname); for (i=0; (sysblkdevname[i]!=0) && (idevtype=BLKDEV_PHYSDISK; snprintf(sysblkinfo, sizeof(sysblkinfo), "/sys/block/%s/device/model", sysblkdevname); if ( ((finfo=fopen(sysblkinfo, "rb")) != NULL) && (fread(temp, 1, sizeof(temp), finfo)>0) && fclose(finfo)==0 ) for (i=0; (temp[i]!=0) && (temp[i]!='\r') && (temp[i]!='\n'); i++) outdev->name[i]=temp[i]; } else { outdev->devtype=BLKDEV_FILESYSDEV; } // get blkid infos about the device (label, uuid) blkid_cache cache = NULL; if (blkid_get_cache(&cache, NULL) < 0) return -1; if ((dev=blkid_get_dev(cache, outdev->longname, BLKID_DEV_NORMAL))!=NULL) { iter = blkid_tag_iterate_begin(dev); while (blkid_tag_next(iter, &type, &value)==0) { if (strcmp(type, "LABEL")==0) snprintf(outdev->label, sizeof(outdev->label), "%s", value); else if (strcmp(type, "UUID")==0) snprintf(outdev->uuid, sizeof(outdev->uuid), "%s", value); else if (strcmp(type, "TYPE")==0) snprintf(outdev->fsname, sizeof(outdev->fsname), "%s", value); } blkid_tag_iterate_end(iter); // workaround: blkid < 1.41 don't know ext4 and say it is ext3 instead if (strcmp(outdev->fsname, "ext3")==0) { if (ext3_test(outdev->longname)==true) snprintf(outdev->fsname, sizeof(outdev->fsname), "ext3"); else // cannot run ext4_test(): it would fail on an ext4 when e2fsprogs < 1.41 snprintf(outdev->fsname, sizeof(outdev->fsname), "ext4"); } } blkid_put_cache(cache); // free memory allocated by blkid_get_cache return 0; } fsarchiver-0.8.5/src/oper_save.c0000644000176100017610000015430613242767463013552 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fsarchiver.h" #include "dico.h" #include "dichl.h" #include "archwriter.h" #include "options.h" #include "common.h" #include "oper_save.h" #include "strlist.h" #include "filesys.h" #include "fs_ext2.h" #include "fs_xfs.h" #include "fs_reiserfs.h" #include "fs_reiser4.h" #include "fs_jfs.h" #include "fs_btrfs.h" #include "fs_ntfs.h" #include "thread_comp.h" #include "thread_archio.h" #include "syncthread.h" #include "regmulti.h" #include "crypto.h" #include "error.h" #include "queue.h" #ifndef ENOATTR #define ENOATTR ENODATA #endif typedef struct s_savear { carchwriter ai; cregmulti regmulti; cdichl *dichardlinks; cstats stats; int fstype; int fsid; u64 objectid; u64 cost_global; u64 cost_current; } csavear; typedef struct s_devinfo { char devpath[PATH_MAX]; char partmount[PATH_MAX]; bool mountedbyfsa; int fstype; } cdevinfo; int createar_obj_regfile_multi(csavear *save, cdico *header, char *relpath, char *fullpath, u64 filesize) { char databuf[FSA_MAX_SMALLFILESIZE]; u8 md5sum[16]; int ret=0; int res; int fd; // The checksum will be in the obj-header not in a file footer if ((fd=open64(fullpath, O_RDONLY|O_LARGEFILE))<0) { sysprintf("Cannot open small file %s for reading\n", relpath); return -1; } msgprintf(MSG_DEBUG1, "backup_obj_regfile_multi(file=%s, size=%lld)\n", relpath, (long long)filesize); res=read(fd, databuf, (long)filesize); close(fd); if (res!=filesize) { if (res>=0 && resregmulti, filesize)==false) { if (regmulti_save_enqueue(&save->regmulti, &g_queue, save->fsid)!=0) { errprintf("Cannot queue last block of small-files\n"); return -1; } regmulti_empty(&save->regmulti); } // copy current small file to the shared-block if (regmulti_save_addfile(&save->regmulti, header, databuf, filesize)!=0) { errprintf("Cannot add small-file %s to regmulti structure\n", relpath); return -1; } return ret; } int createar_obj_regfile_unique(csavear *save, cdico *header, char *relpath, char *fullpath, u64 filesize) // large or empty files { cdico *footerdico=NULL; struct s_blockinfo blkinfo; gcry_md_hd_t md5ctx; u32 curblocksize; bool eof=false; u64 remaining; char text[256]; u8 *origblock; u8 *md5tmp; u8 md5sum[16]; u64 filepos; int ret=0; int res; int fd; if (gcry_md_open(&md5ctx, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR) { errprintf("gcry_md_open() failed\n"); return -1; } if ((fd=open64(fullpath, O_RDONLY|O_LARGEFILE))<0) { sysprintf("Cannot open %s for reading\n", relpath); return -1; } // write header with file attributes (only if open64() works) queue_add_header(&g_queue, header, FSA_MAGIC_OBJT, save->fsid); msgprintf(MSG_DEBUG1, "backup_obj_regfile_unique(file=%s, size=%lld)\n", relpath, (long long)filesize); for (filepos=0; (filesize>0) && (filepos < filesize) && (get_interrupted()==false); filepos+=curblocksize) { remaining=filesize-filepos; curblocksize=min(remaining, g_options.datablocksize); msgprintf(MSG_DEBUG2, "----> filepos=%lld, remaining=%lld, curblocksize=%lld\n", (long long)filepos, (long long)remaining, (long long)curblocksize); origblock=malloc(curblocksize); if (!origblock) { errprintf("malloc(%ld) failed: cannot allocate data block\n", (long)origblock); ret=-1; goto backup_obj_regfile_unique_error; } if (eof==false) // file has not been truncated: read the next block { if ((res=read(fd, origblock, (long)curblocksize))!=curblocksize) { ret=-1; if (res>=0 && resfsid; if (queue_add_block(&g_queue, &blkinfo, QITEM_STATUS_TODO)!=0) { sysprintf("queue_add_block(%s) failed\n", relpath); ret=-1; goto backup_obj_regfile_unique_error; } } if (get_interrupted()==true) { errprintf("operation has been interrupted\n"); ret=-1; goto backup_obj_regfile_unique_error; } // write the footer with the global md5sum if ((md5tmp=gcry_md_read(md5ctx, GCRY_MD_MD5))==NULL) { errprintf("gcry_md_read() failed\n"); ret=-1; goto backup_obj_regfile_unique_error; } memcpy(md5sum, md5tmp, 16); gcry_md_close(md5ctx); msgprintf(MSG_DEBUG1, "--> finished loop for file=%s, size=%lld, md5=[%s]\n", relpath, (long long)filesize, format_md5(text, sizeof(text), md5sum)); // don't write the footer for empty files (checksum does not make sense --> don't waste space in the archive) if (filesize>0) { if ((footerdico=dico_alloc())==NULL) { errprintf("dico_alloc() failed\n"); ret=-1; goto backup_obj_regfile_unique_error; } dico_add_data(footerdico, 0, BLOCKFOOTITEMKEY_MD5SUM, md5sum, 16); if (queue_add_header(&g_queue, footerdico, FSA_MAGIC_FILF, save->fsid)!=0) { msgprintf(MSG_VERB2, "Cannot write footer for file %s\n", relpath); ret=-1; goto backup_obj_regfile_unique_error; } } backup_obj_regfile_unique_error: close(fd); return ret; } int createar_item_xattr(csavear *save, char *root, char *relpath, struct stat64 *statbuf, cdico *d) { char fullpath[PATH_MAX]; char *valbuf=NULL; char buffer[4096]; s64 attrsize; int valsize=0; int listlen; u64 attrcnt; int ret=0; int pos; int len; // init concatenate_paths(fullpath, sizeof(fullpath), root, relpath); attrcnt=0; memset(buffer, 0, sizeof(buffer)); listlen=llistxattr(fullpath, buffer, sizeof(buffer)-1); msgprintf(MSG_DEBUG2, "xattr:llistxattr(%s)=%d\n", relpath, listlen); for (pos=0; (pos65535LL) { errprintf("file [%s] has an xattr [%s] with data too big (size=%ld, maxsize=64k)\n", relpath, buffer+pos, (long)attrsize); ret=-1; continue; // copy the next xattr } errno=0; if ((valbuf=malloc(attrsize+1))==NULL) { sysprintf("malloc(%ld) failed\n", (long)(attrsize+1)); ret=-1; continue; // ignore the current xattr } errno=0; valsize=lgetxattr(fullpath, buffer+pos, valbuf, attrsize); msgprintf(MSG_VERB2, " xattr:lgetxattr(%s,%s)=%d\n", relpath, buffer+pos, valsize); if (valsize>=0) { msgprintf(MSG_VERB2, " xattr:lgetxattr(%s,%s)=%d: [%s]\n", relpath, buffer+pos, valsize, buffer+pos); msgprintf(MSG_DEBUG2, " xattr:lgetxattr(%s)=%d: [%s]=[%s]\n", relpath, valsize, buffer+pos, valbuf); msgprintf(MSG_DEBUG2, " xattr:dico_add_string(%s, xattr): key=%d, name=[%s]\n", relpath, (int)(2*attrcnt)+0, buffer+pos); dico_add_string(d, DICO_OBJ_SECTION_XATTR, (2*attrcnt)+0, buffer+pos); msgprintf(MSG_DEBUG2, " xattr:dico_add_data(%s, xattr): key=%d, data (size=[%d])\n", relpath, (int)(2*attrcnt)+1, valsize); dico_add_data(d, DICO_OBJ_SECTION_XATTR, (2*attrcnt)+1, valbuf, valsize); attrcnt++; free(valbuf); } else if (errno!=ENOATTR) // if the attribute exists and we cannot read it { sysprintf(" xattr:lgetxattr(%s,%s)=%d\n", relpath, buffer+pos, valsize); ret=-1; free(valbuf); continue; // copy the next xattr } else // errno==ENOATTR hence the attribute does not exist { msgprintf(MSG_VERB2, " xattr:lgetxattr-win(%s,%s)=-1: errno==ENOATTR\n", relpath, buffer+pos); free(valbuf); } } return ret; } int createar_item_winattr(csavear *save, char *root, char *relpath, struct stat64 *statbuf, cdico *d) { char fullpath[PATH_MAX]; char *valbuf=NULL; int valsize=0; s64 attrsize; u64 attrcnt; int ret=0; int i; char *winattr[]= {"system.ntfs_acl", "system.ntfs_attrib", "system.ntfs_reparse_data", "system.ntfs_times", "system.ntfs_dos_name", NULL}; // init concatenate_paths(fullpath, sizeof(fullpath), root, relpath); attrcnt=0; for (i=0; winattr[i]; i++) { if ((strcmp(relpath, "/")==0) && (strcmp(winattr[i], "system.ntfs_dos_name")==0)) // the root inode does not require a short name continue; errno=0; if ((attrsize=lgetxattr(fullpath, winattr[i], NULL, 0)) < 0) // get the size of the attribute { if (errno!=ENOATTR) { sysprintf(" winattr:lgetxattr(%s,%s): returned negative attribute size\n", relpath, winattr[i]); // output if there are any other error ret=-1; } continue; // ignore the current xattr } msgprintf(MSG_VERB2, " winattr:file=[%s], attrcnt=%d, name=[%s], size=%ld\n", relpath, (int)attrcnt, winattr[i], (long)attrsize); if (attrsize>65535LL) { errprintf("file [%s] has an xattr [%s] with data size=%ld too big (max xattr size is 65535)\n", relpath, winattr[i], (long)attrsize); ret=-1; continue; // ignore the current xattr } errno=0; if ((valbuf=malloc(attrsize+1))==NULL) { sysprintf("malloc(%d) failed\n", (int)(attrsize+1)); ret=-1; continue; // ignore the current xattr } valsize=lgetxattr(fullpath, winattr[i], valbuf, attrsize); msgprintf(MSG_VERB2, " winattr:lgetxattr-win(%s,%s)=%d\n", relpath, winattr[i], valsize); if (valsize>=0) { msgprintf(MSG_VERB2, " winattr:dico_add_string(%s, winattr): key=%d, name=[%s]\n", relpath, (int)(2*attrcnt)+0, winattr[i]); dico_add_string(d, DICO_OBJ_SECTION_WINATTR, (2*attrcnt)+0, winattr[i]); msgprintf(MSG_VERB2, " winattr:dico_add_data(%s, winattr): key=%d, data (size=[%d])\n", relpath, (int)(2*attrcnt)+1, valsize); dico_add_data(d, DICO_OBJ_SECTION_WINATTR, (2*attrcnt)+1, valbuf, valsize); free(valbuf); attrcnt++; } else if (errno!=ENOATTR) // if the attribute exists and we cannot read it { sysprintf(" winattr:lgetxattr(%s,%s)=%d\n", relpath, winattr[i], valsize); ret=-1; free(valbuf); continue; // ignore the current xattr } else // errno==ENOATTR hence the attribute does not exist { msgprintf(MSG_VERB2, " winattr:lgetxattr-win(%s,%s)=-1: errno==ENOATTR\n", relpath, winattr[i]); free(valbuf); } } return ret; } int createar_item_stdattr(csavear *save, char *root, char *relpath, struct stat64 *statbuf, cdico *d, int *objtype, u64 *filecost) { struct stat64 stattarget; char fullpath[PATH_MAX]; char buffer[PATH_MAX]; char buffer2[PATH_MAX]; char directory[PATH_MAX]; char *linktarget=NULL; u64 flags; int res; int i; // init flags=0; *objtype=OBJTYPE_NULL; *filecost=FSA_COST_PER_FILE; // fixed cost per file concatenate_paths(fullpath, sizeof(fullpath), root, relpath); msgprintf(MSG_DEBUG2, "Adding [%.5lld]=[%s]\n", (long long)save->objectid, relpath); if (dico_add_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_OBJECTID, (u64)(save->objectid)++)!=0) { errprintf("dico_add_u64(DICO_OBJ_SECTION_STDATTR) failed\n"); return -1; } if (dico_add_string(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_PATH, relpath)!=0) { errprintf("dico_add_string(DICO_OBJ_SECTION_STDATTR) failed\n"); return -1; } if (dico_add_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_SIZE, (u64)statbuf->st_size)!=0) { errprintf("dico_add_u64(DICO_OBJ_SECTION_STDATTR) failed\n"); return -1; } if (dico_add_u32(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_MODE, (u32)statbuf->st_mode)!=0) { errprintf("dico_add_u32(DICO_OBJ_SECTION_STDATTR) failed\n"); return -1; } if (dico_add_u32(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_UID, (u32)statbuf->st_uid)!=0) { errprintf("dico_add_u32(DICO_OBJ_SECTION_STDATTR) failed\n"); return -1; } if (dico_add_u32(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_GID, (u32)statbuf->st_gid)!=0) { errprintf("dico_add_u32(gid) failed\n"); return -1; } if (dico_add_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_ATIME, (u32)statbuf->st_atime)!=0) { errprintf("dico_add_u32(DICO_OBJ_SECTION_STDATTR) failed\n"); return -1; } if (dico_add_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_MTIME, (u32)statbuf->st_mtime)!=0) { errprintf("dico_add_u32(DICO_OBJ_SECTION_STDATTR) failed\n"); return -1; } // 2. copy specific properties to the dico switch (statbuf->st_mode & S_IFMT) { case S_IFDIR: *objtype=OBJTYPE_DIR; break; case S_IFLNK: // save path of the target of the symlink *objtype=OBJTYPE_SYMLINK; memset(buffer, 0, sizeof(buffer)); memset(buffer2, 0, sizeof(buffer2)); if ((readlink(fullpath, buffer, sizeof(buffer)))<0) { sysprintf("readlink(%s) failed\n", fullpath); return -1; } // fix path as ntfs-3g>=2010.3.6 may return an absolute path that includes the mount directory linktarget=buffer; if (memcmp(linktarget, "/tmp/fsa/", 9)==0) { for (i=0; i<3; i++) { if (linktarget[0]=='/') linktarget++; while (linktarget[0]!=0 && linktarget[0]!='/') linktarget++; } } msgprintf(MSG_DEBUG1, "fixed-readlink([%s])=[%s]\n", fullpath, linktarget); dico_add_string(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_SYMLINK, linktarget); // save type of the target of the symlink (required to recreate ntfs symlinks) if (filesys[save->fstype].savesymtargettype==true) { if (linktarget[0]=='/') // absolute symbolic link { snprintf(buffer2, sizeof(buffer2), "%s", buffer); msgprintf(MSG_DEBUG1, "absolute-symlink: fullpath=[%s] --> lstat64=[%s]\n", fullpath, buffer2); } else // relative symbolic link { extract_dirpath(fullpath, directory, sizeof(directory)); concatenate_paths(buffer2, sizeof(buffer2), directory, linktarget); msgprintf(MSG_DEBUG1, "relative-symlink: fullpath=[%s] --> lstat64=[%s]\n", fullpath, buffer2); } if (lstat64(buffer2, &stattarget)==0) { switch (stattarget.st_mode & S_IFMT) { case S_IFDIR: dico_add_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_LINKTARGETTYPE, OBJTYPE_DIR); msgprintf(MSG_DEBUG1, "LINK: link=[%s], target=[%s]=DIR\n", relpath, buffer2); break; case S_IFREG: dico_add_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_LINKTARGETTYPE, OBJTYPE_REGFILEUNIQUE); msgprintf(MSG_DEBUG1, "LINK: link=[%s], target=[%s]=REGFILE\n", relpath, buffer2); break; default: msgprintf(MSG_DEBUG1, "LINK: link=[%s], target=[%s]=UNKNOWN\n", relpath, buffer2); break; } } } break; case S_IFREG: if (statbuf->st_nlink>1) // there are several links to that inode: there are hard links { res=dichl_get(save->dichardlinks, (u64)statbuf->st_rdev, (u64)statbuf->st_ino, buffer, sizeof(buffer)); if (res==0) // inode already seen --> hard link { dico_add_string(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_HARDLINK, buffer); *objtype=OBJTYPE_HARDLINK; } else // next link to thar inode will be an hard link { dichl_add(save->dichardlinks, (u64)statbuf->st_rdev, (u64)statbuf->st_ino, relpath); } } if (*objtype==OBJTYPE_NULL) // not an hard-link: it's a regular file or the first link when multiple links found { // don't allow reg-files with hardlinks to be copied as a small-file with other small-files // the file would be copied later in the archive (when the block for small files is ready) // and then the hardlink may come before the regfile (first link to that object) // case 1: file smaller than threshold: pack its data with other small files in a single compressed block *filecost+=statbuf->st_size; if ((statbuf->st_size > 0) && (statbuf->st_size < g_options.smallfilethresh) && (statbuf->st_nlink==1)) *objtype=OBJTYPE_REGFILEMULTI; else // case 2: file having hardlinks or larger than the threshold *objtype=OBJTYPE_REGFILEUNIQUE; // empty files are considered as OBJTYPE_REGFILEUNIQUE (statbuf->st_size==0) } if (*objtype==OBJTYPE_REGFILEUNIQUE || *objtype==OBJTYPE_REGFILEMULTI) { if (((u64)statbuf->st_blocks) * ((u64)DEV_BSIZE) < ((u64)statbuf->st_size)) flags|=FSA_FILEFLAGS_SPARSE; } break; case S_IFCHR: dico_add_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_RDEV, statbuf->st_rdev); *objtype=OBJTYPE_CHARDEV; break; case S_IFBLK: dico_add_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_RDEV, statbuf->st_rdev); *objtype=OBJTYPE_BLOCKDEV; break; case S_IFIFO: dico_add_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_RDEV, statbuf->st_rdev); *objtype=OBJTYPE_FIFO; break; case S_IFSOCK: dico_add_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_RDEV, statbuf->st_rdev); *objtype=OBJTYPE_SOCKET; break; default: errprintf("unknown item %s\n", fullpath); return -1; break; } dico_add_u32(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_OBJTYPE, *objtype); if (flags!=0) dico_add_u64(d, DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_FLAGS, flags); return 0; } int createar_save_file(csavear *save, char *root, char *relpath, struct stat64 *statbuf, u64 *costeval) { char fullpath[PATH_MAX]; char strprogress[256]; cdico *dicoattr; int attrerrors=0; u64 filecost; s64 progress; int objtype; int res; // init concatenate_paths(fullpath, sizeof(fullpath), root, relpath); // don't backup the archive file itself if (archwriter_is_path_to_curvol(&save->ai, fullpath)==true) { errprintf("file [%s] ignored: it's the current archive file\n", fullpath); save->stats.err_regfile++; return 0; // not a fatal error, oper must continue } // ---- backup standard file attributes if ((dicoattr=dico_alloc())==NULL) { errprintf("dico_alloc() failed\n"); return -1; // fatal error } if (createar_item_stdattr(save, root, relpath, statbuf, dicoattr, &objtype, &filecost)!=0) { msgprintf(MSG_STACK, "backup_item_stdattr() failed: cannot read standard attributes on [%s]\n", relpath); attrerrors++; } // --- cost required for the progression info if (costeval!=NULL) { *costeval+=filecost; dico_destroy(dicoattr); return 0; } // ---- backup other file attributes (xattr + winattr) if (createar_item_xattr(save, root, relpath, statbuf, dicoattr)!=0) { msgprintf(MSG_STACK, "backup_item_xattr() failed: cannot prepare xattr-dico for item %s\n", relpath); attrerrors++; } if (filesys[save->fstype].winattr==true) { if (createar_item_winattr(save, root, relpath, statbuf, dicoattr)!=0) { msgprintf(MSG_STACK, "backup_item_winattr() failed: cannot prepare winattr-dico for item %s\n", relpath); attrerrors++; } } // ---- file details and progress bar if (get_interrupted()==false) { memset(strprogress, 0, sizeof(strprogress)); if (save->cost_global>0) { save->cost_current+=filecost; progress=((save->cost_current)*100)/(save->cost_global); if (progress>=0 && progress<=100) snprintf(strprogress, sizeof(strprogress), "[%3d%%]", (int)progress); } msgprintf(MSG_VERB1, "-[%.2d]%s[%s] %s\n", save->fsid, strprogress, get_objtype_name(objtype), relpath); } // ---- backup file contents for regfiles switch (objtype) { case OBJTYPE_DIR: if (attrerrors>0) { save->stats.err_dir++; dico_destroy(dicoattr); return 0; // error is not fatal, operation must continue } if (queue_add_header(&g_queue, dicoattr, FSA_MAGIC_OBJT, save->fsid)!=0) { errprintf("queue_add_header(%s) failed\n", relpath); return -1; // fatal error } save->stats.cnt_dir++; break; case OBJTYPE_SYMLINK: if (attrerrors>0) { save->stats.err_symlink++; dico_destroy(dicoattr); return 0; // error is not fatal, operation must continue } if (queue_add_header(&g_queue, dicoattr, FSA_MAGIC_OBJT, save->fsid)!=0) { errprintf("queue_add_header(%s) failed\n", relpath); return -1; // fatal error } save->stats.cnt_symlink++; break; case OBJTYPE_HARDLINK: if (attrerrors>0) { save->stats.err_hardlink++; dico_destroy(dicoattr); return 0; // error is not fatal, operation must continue } if (queue_add_header(&g_queue, dicoattr, FSA_MAGIC_OBJT, save->fsid)!=0) { errprintf("queue_add_header(%s) failed\n", relpath); return -1; // fatal error } save->stats.cnt_hardlink++; break; case OBJTYPE_CHARDEV: case OBJTYPE_BLOCKDEV: case OBJTYPE_FIFO: case OBJTYPE_SOCKET: if (attrerrors>0) { save->stats.err_special++; dico_destroy(dicoattr); return 0; // error is not fatal, operation must continue } if (queue_add_header(&g_queue, dicoattr, FSA_MAGIC_OBJT, save->fsid)!=0) { errprintf("queue_add_header(%s) failed\n", relpath); return -1; // fatal error } save->stats.cnt_special++; break; case OBJTYPE_REGFILEUNIQUE: if (attrerrors>0) { save->stats.err_regfile++; dico_destroy(dicoattr); return 0; // error is not fatal, operation must continue } if ((res=createar_obj_regfile_unique(save, dicoattr, relpath, fullpath, statbuf->st_size))!=0) { msgprintf(MSG_STACK, "backup_obj_regfile_unique(%s)=%d failed\n", relpath, res); save->stats.err_regfile++; return 0; // not a fatal error, oper must continue } else { save->stats.cnt_regfile++; } break; case OBJTYPE_REGFILEMULTI: if (attrerrors>0) { save->stats.err_regfile++; dico_destroy(dicoattr); return 0; // error is not fatal, operation must continue } if ((res=createar_obj_regfile_multi(save, dicoattr, relpath, fullpath, statbuf->st_size))!=0) { msgprintf(MSG_STACK, "backup_obj_regfile_multi(%s)=%d failed\n", relpath, res); save->stats.err_regfile++; return 0; // not a fatal error, oper must continue } else { save->stats.cnt_regfile++; } break; default: // unknown type errprintf("invalid object type: %ld for file %s\n", (long)objtype, relpath); return -1; // fatal error break; } return 0; } int createar_save_directory(csavear *save, char *root, char *path, u64 *costeval) { char fulldirpath[PATH_MAX]; char fullpath[PATH_MAX]; char relpath[PATH_MAX]; struct stat64 statbuf; struct dirent *dir; DIR *dirdesc; int ret=0; // init concatenate_paths(fulldirpath, sizeof(fulldirpath), root, path); if (!(dirdesc=opendir(fulldirpath))) { sysprintf("cannot open directory %s\n", fulldirpath); return 0; // not a fatal error, oper must continue } // backup the directory itself (important for the root of the filesystem) if (lstat64(fulldirpath, &statbuf)!=0) { sysprintf("cannot lstat64(%s)\n", fulldirpath); ret=-1; goto backup_dir_err; } // save info about the directory itself if (createar_save_file(save, root, path, &statbuf, costeval)!=0) { errprintf("createar_save_file(%s,%s) failed\n", root, path); ret=-1; goto backup_dir_err; } while (((dir = readdir(dirdesc)) != NULL) && (get_interrupted()==false)) { // ---- ignore "." and ".." and ignore mount-points if (strcmp(dir->d_name,".")==0 || strcmp(dir->d_name,"..")==0) continue; // ignore "." and ".." // ---- calculate paths concatenate_paths(relpath, sizeof(relpath), path, dir->d_name); concatenate_paths(fullpath, sizeof(fullpath), fulldirpath, dir->d_name); // ---- get details about current file if (lstat64(fullpath, &statbuf)!=0) { sysprintf("cannot lstat64(%s)\n", fullpath); ret=-1; goto backup_dir_err; } // check the list of excluded files/dirs if ((exclude_check(&g_options.exclude, dir->d_name)==true) // is filename excluded ? || (exclude_check(&g_options.exclude, relpath)==true)) // is filepath excluded ? { if (costeval==NULL) // dont log twice (eval + real) msgprintf(MSG_VERB2, "file/dir=[%s] excluded\n", relpath); continue; } // backup contents before the directory itself so that the dir-attributes are written after the dir contents if (S_ISDIR(statbuf.st_mode)) { if (createar_save_directory(save, root, relpath, costeval)!=0) { msgprintf(MSG_STACK, "createar_save_directory(%s) failed\n", relpath); ret=-1; goto backup_dir_err; } } else // not a directory { if (createar_save_file(save, root, relpath, &statbuf, costeval)!=0) { msgprintf(MSG_STACK, "createar_save_directory(%s) failed\n", relpath); ret=-1; goto backup_dir_err; } } } backup_dir_err: closedir(dirdesc); return ret; } int createar_save_directory_wrapper(csavear *save, char *root, char *path, u64 *costeval) { int ret; if ((save->dichardlinks=dichl_alloc())==NULL) { errprintf("dichardlinks=dichl_alloc() failed\n"); return -1; } if (regmulti_init(&save->regmulti, g_options.datablocksize)!=0) { errprintf("regmulti_init failed\n"); return -1; } ret=createar_save_directory(save, root, path, costeval); // put all small files that are in the last block to the queue if (regmulti_save_enqueue(&save->regmulti, &g_queue, save->fsid)!=0) { errprintf("Cannot queue last block of small-files\n"); return -1; } // dico for hard links not required anymore dichl_destroy(save->dichardlinks); return ret; } int createar_write_mainhead(csavear *save, int archtype, int fscount) { u8 bufcheckclear[FSA_CHECKPASSBUF_SIZE+8]; u8 bufcheckcrypt[FSA_CHECKPASSBUF_SIZE+8]; u64 cryptsize; u8 md5sum[16]; struct timeval now; cdico *d; if (!save) { errprintf("ai is NULL\n"); return -1; } // init gettimeofday(&now, NULL); if ((d=dico_alloc())==NULL) { errprintf("dico_alloc() failed\n"); return -1; } dico_add_string(d, 0, MAINHEADKEY_FILEFORMATVER, FSA_FILEFORMAT); dico_add_string(d, 0, MAINHEADKEY_PROGVERCREAT, FSA_VERSION); dico_add_string(d, 0, MAINHEADKEY_ARCHLABEL, g_options.archlabel); dico_add_u64(d, 0, MAINHEADKEY_CREATTIME, now.tv_sec); dico_add_u32(d, 0, MAINHEADKEY_ARCHIVEID, save->ai.archid); dico_add_u32(d, 0, MAINHEADKEY_ARCHTYPE, archtype); dico_add_u32(d, 0, MAINHEADKEY_COMPRESSALGO, g_options.compressalgo); dico_add_u32(d, 0, MAINHEADKEY_COMPRESSLEVEL, g_options.compresslevel); dico_add_u32(d, 0, MAINHEADKEY_ENCRYPTALGO, g_options.encryptalgo); dico_add_u32(d, 0, MAINHEADKEY_FSACOMPLEVEL, g_options.fsacomplevel); dico_add_u32(d, 0, MAINHEADKEY_HASDIRSINFOHEAD, true); // minimum fsarchiver version required to restore that archive dico_add_u64(d, 0, MAINHEADKEY_MINFSAVERSION, FSA_VERSION_BUILD(0, 6, 4, 0)); if (archtype==ARCHTYPE_FILESYSTEMS) { dico_add_u64(d, 0, MAINHEADKEY_FSCOUNT, fscount); } // if encryption is enabled, save the md5sum of a random buffer to check the password if (g_options.encryptalgo!=ENCRYPT_NONE) { memset(md5sum, 0, sizeof(md5sum)); crypto_random(bufcheckclear, FSA_CHECKPASSBUF_SIZE); crypto_blowfish(FSA_CHECKPASSBUF_SIZE, &cryptsize, bufcheckclear, bufcheckcrypt, g_options.encryptpass, strlen((char*)g_options.encryptpass), true); gcry_md_hash_buffer(GCRY_MD_MD5, md5sum, bufcheckclear, FSA_CHECKPASSBUF_SIZE); assert(dico_add_data(d, 0, MAINHEADKEY_BUFCHECKPASSCLEARMD5, md5sum, 16)==0); assert(dico_add_data(d, 0, MAINHEADKEY_BUFCHECKPASSCRYPTBUF, bufcheckcrypt, FSA_CHECKPASSBUF_SIZE)==0); } if (queue_add_header(&g_queue, d, FSA_MAGIC_MAIN, FSA_FILESYSID_NULL)!=0) { errprintf("cannot write dico for main header\n"); dico_destroy(d); return -1; } return 0; } int filesystem_mount_partition(cdevinfo *devinfo, cdico *dicofsinfo, u16 fsid) { char fsbuf[FSA_MAX_FSNAMELEN]; struct statvfs64 statfsbuf; cstrlist reqmntopt; cstrlist badmntopt; cstrlist curmntopt; int showwarningcount1=0; int showwarningcount2=0; int errorattr=false; char temp[PATH_MAX]; char curmntdir[PATH_MAX]; char optbuf[128]; u64 fsbytestotal; u64 fsbytesused; int readwrite; int tmptype; int count; int res; int i; res=generic_get_mntinfo(devinfo->devpath, &readwrite, curmntdir, sizeof(curmntdir), optbuf, sizeof(optbuf), fsbuf, sizeof(fsbuf)); if (res==0) // partition is already mounted { devinfo->mountedbyfsa=false; //snprintf(partmnt, PATH_MAX, "%s", curmntdir); // return the mount point to main savefs function msgprintf(MSG_DEBUG1, "generic_get_mntinfo(%s): mnt=[%s], opt=[%s], fs=[%s], rw=[%d]\n", devinfo->devpath, curmntdir, optbuf, fsbuf, readwrite); if (readwrite==1 && g_options.allowsaverw==0) { errprintf("partition [%s] is mounted read/write. please mount it read-only \n" "and then try again. you can do \"mount -o remount,ro %s\". you can \n" "also run fsarchiver with option '-A' if you know what you are doing.\n", devinfo->devpath, devinfo->devpath); return -1; } if (generic_get_fstype(fsbuf, &devinfo->fstype)!=0) { if (strcmp(fsbuf, "fuseblk")==0) errprintf("partition [%s] is using a fuse based filesystem (probably ntfs-3g). Unmount it and try again\n", devinfo->devpath); else errprintf("filesystem of partition [%s] is not supported by fsarchiver: filesystem=[%s]\n", devinfo->devpath, fsbuf); return -1; } // check the filesystem is mounted with the right mount-options (to preserve acl and xattr) strlist_init(&reqmntopt); strlist_init(&badmntopt); strlist_init(&curmntopt); if (filesys[devinfo->fstype].reqmntopt(devinfo->devpath, &reqmntopt, &badmntopt)!=0) { errprintf("cannot get the required mount options for partition=[%s]\n", devinfo->devpath); strlist_empty(&reqmntopt); strlist_empty(&badmntopt); return -1; } strlist_split(&curmntopt, optbuf, ','); msgprintf(MSG_DEBUG2, "mount options found for partition=[%s]: [%s]\n", devinfo->devpath, strlist_merge(&curmntopt, temp, sizeof(temp), ',')); msgprintf(MSG_DEBUG2, "mount options required for partition=[%s]: [%s]\n", devinfo->devpath, strlist_merge(&reqmntopt, temp, sizeof(temp), ',')); msgprintf(MSG_DEBUG2, "mount options to avoid for partition=[%s]: [%s]\n", devinfo->devpath, strlist_merge(&badmntopt, temp, sizeof(temp), ',')); count=strlist_count(&reqmntopt); for (i=0; i < count; i++) { strlist_getitem(&reqmntopt, i, optbuf, sizeof(optbuf)); msgprintf(MSG_DEBUG2, "checking there is reqmntopt[%d]=[%s]\n", i, optbuf); if (strlist_exists(&curmntopt, optbuf)!=true) { if (showwarningcount1==0) errprintf("partition [%s] has to be mounted with options [%s] in order to preserve " "all its attributes. you can use mount with option remount to do that.\n", devinfo->devpath, strlist_merge(&reqmntopt, temp, sizeof(temp), ',')); if (g_options.dontcheckmountopts==true) { if (showwarningcount1++ == 0) // show this warning only once errprintf("fsarchiver will continue anyway since the option '-a' was used\n"); } else // don't ignore the mount options { errprintf("fsarchiver cannot continue, you can use option '-a' to ignore " "the mount options (xattr or acl may not be preserved)\n"); return -1; } } } count=strlist_count(&badmntopt); for (i=0; i < count; i++) { strlist_getitem(&badmntopt, i, optbuf, sizeof(optbuf)); msgprintf(MSG_DEBUG2, "checking there is not badmntopt[%d]=[%s]\n", i, optbuf); if (strlist_exists(&curmntopt, optbuf)==true) { if (showwarningcount2==0) errprintf("partition [%s] has to be mounted without options [%s] in order to preserve all its attributes\n", devinfo->devpath, strlist_merge(&badmntopt, temp, sizeof(temp), ',')); if (g_options.dontcheckmountopts==true) { if (showwarningcount2++ == 0) // show this warning only once errprintf("fsarchiver will continue anyway since the option '-a' was used\n"); } else // don't ignore the mount options { errprintf("fsarchiver cannot continue, you can use option '-a' to ignore " "the mount options (xattr or acl may not be preserverd)\n"); return -1; } } } strlist_empty(&reqmntopt); strlist_empty(&badmntopt); strlist_empty(&curmntopt); // create a "mount --bind" for that mounted partition (to see behind its mount points) mkdir_recursive(devinfo->partmount); if (mount(curmntdir, devinfo->partmount, NULL, MS_BIND|MS_RDONLY, NULL)!=0) { errprintf("mount(src=[%s], target=[%s], NULL, MS_BIND|MS_RDONLY, NULL) failed\n", curmntdir, devinfo->partmount); return -1; } devinfo->mountedbyfsa=true; } else // partition not yet mounted { mkdir_recursive(devinfo->partmount); msgprintf(MSG_DEBUG1, "partition %s is not mounted\n", devinfo->devpath); for (tmptype=-1, i=0; (filesys[i].name) && (tmptype==-1); i++) { if ((filesys[i].test(devinfo->devpath)==true) && (filesys[i].mount(devinfo->devpath, devinfo->partmount, filesys[i].name, MS_RDONLY, NULL)==0)) { tmptype=i; msgprintf(MSG_DEBUG1, "partition %s successfully mounted on [%s] as [%s]\n", devinfo->devpath, devinfo->partmount, filesys[i].name); } } if (tmptype==-1) { errprintf("cannot mount partition [%s]: filesystem may not be supported by either fsarchiver or the kernel.\n", devinfo->devpath); return -1; } devinfo->fstype=tmptype; devinfo->mountedbyfsa=true; } // Make sure users are aware if they save filesystems with experimental support in fsarchiver if ((g_options.experimental==false) && (filesys[devinfo->fstype].stable==false)) { errprintf("You must enable support for experimental features in order to save %s filesystems with fsarchiver.\n", filesys[devinfo->fstype].name); return -1; } // Make sure support for extended attributes is enabled if this filesystem supports it if (g_options.dontcheckmountopts==false) { errorattr=false; if (filesys[devinfo->fstype].support_for_xattr==true) { errno=0; res=lgetxattr(devinfo->partmount, "user.fsa_test_xattr", temp, sizeof(temp)); msgprintf(MSG_DEBUG1, "lgetxattr(\"%s\", \"user.fsa_test_attr\", buf, bufsize)=[%d] and errno=[%d]\n", devinfo->partmount, (int)res, (int)errno); // errno should be set to ENOATTR if we are able to read extended attributes if ((res!=0) && (errno==ENOTSUP)) { errprintf("fsarchiver is unable to access extended attributes on device [%s].\n", devinfo->devpath); errorattr=true; } } if (filesys[devinfo->fstype].support_for_acls==true) { errno=0; res=lgetxattr(devinfo->partmount, "system.posix_acl_access", temp, sizeof(temp)); msgprintf(MSG_DEBUG1, "lgetxattr(\"%s\", \"system.posix_acl_access\", buf, bufsize)=[%d] and errno=[%d]\n", devinfo->partmount, (int)res, (int)errno); // errno should be set to ENOATTR if we are able to read ACLs if ((res!=0) && (errno==ENOTSUP)) { errprintf("fsarchiver is unable to access ACLs on device [%s].\n", devinfo->devpath); errorattr=true; } } if (errorattr==true) { errprintf("Cannot continue, you can use option '-a' to ignore " "support for xattr and acl (they will not be preserved)\n"); return -1; } } // get space statistics if (statvfs64(devinfo->partmount, &statfsbuf)!=0) { errprintf("statvfs64(%s) failed\n", devinfo->partmount); return -1; } fsbytestotal=(u64)statfsbuf.f_frsize*(u64)statfsbuf.f_blocks; fsbytesused=fsbytestotal-((u64)statfsbuf.f_frsize*(u64)statfsbuf.f_bfree); dico_add_string(dicofsinfo, 0, FSYSHEADKEY_FILESYSTEM, filesys[devinfo->fstype].name); dico_add_string(dicofsinfo, 0, FSYSHEADKEY_MNTPATH, devinfo->partmount); dico_add_string(dicofsinfo, 0, FSYSHEADKEY_ORIGDEV, devinfo->devpath); dico_add_u64(dicofsinfo, 0, FSYSHEADKEY_BYTESTOTAL, fsbytestotal); dico_add_u64(dicofsinfo, 0, FSYSHEADKEY_BYTESUSED, fsbytesused); if (filesys[devinfo->fstype].getinfo(dicofsinfo, devinfo->devpath)!=0) { errprintf("cannot save filesystem attributes for partition %s\n", devinfo->devpath); return -1; } return 0; } int createar_oper_savefs(csavear *save, cdevinfo *devinfo) { cdico *dicobegin=NULL; cdico *dicoend=NULL; int ret=0; // write "begin of filesystem" header if ((dicobegin=dico_alloc())==NULL) { errprintf("dicostart=dico_alloc() failed\n"); return -1; } queue_add_header(&g_queue, dicobegin, FSA_MAGIC_FSYB, save->fsid); // init filesystem data struct save->fstype=devinfo->fstype; // main task ret=createar_save_directory_wrapper(save, devinfo->partmount, "/", NULL); // write "end of filesystem" header if ((dicoend=dico_alloc())==NULL) { errprintf("dicoend=dico_alloc() failed\n"); return -1; } // TODO: add stats about files count in that dico queue_add_header(&g_queue, dicoend, FSA_MAGIC_DATF, save->fsid); return ret; } int createar_oper_savedir(csavear *save, char *rootdir) { char fullpath[PATH_MAX]; char currentdir[PATH_MAX]; if (rootdir[0]=='/') // absolute path { snprintf(fullpath, sizeof(fullpath), "%s", rootdir); createar_save_directory_wrapper(save, "/", fullpath, NULL); } else // relative path { concatenate_paths(fullpath, sizeof(fullpath), getcwd(currentdir, sizeof(currentdir)), rootdir); createar_save_directory_wrapper(save, ".", rootdir, NULL); } return 0; } int oper_save(char *archive, int argc, char **argv, int archtype) { pthread_t thread_comp[FSA_MAX_COMPJOBS]; cdico *dicofsinfo[FSA_MAX_FSPERARCH]; cdevinfo devinfo[FSA_MAX_FSPERARCH]; pthread_t thread_writer; u64 cost_evalfs=0; u64 totalerr=0; cdico *dicoend=NULL; cdico *dirsinfo=NULL; struct stat64 st; csavear save; int ret=0; int i; // init memset(&save, 0, sizeof(save)); save.cost_global=0; // init archive archwriter_init(&save.ai); archwriter_generate_id(&save.ai); // pass options to archive path_force_extension(save.ai.basepath, PATH_MAX, archive, ".fsa"); // init misc data struct to zero thread_writer=0; for (i=0; i0) ret=-1; archwriter_destroy(&save.ai); return ret; } fsarchiver-0.8.5/src/writebuf.h0000644000176100017610000000223713242523705013403 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __WRITEBUF_H__ #define __WRITEBUF_H__ struct s_dico; struct s_blockinfo; struct s_writebuf; typedef struct s_writebuf cwritebuf; struct s_writebuf { char *data; u64 size; }; cwritebuf *writebuf_alloc(); int writebuf_destroy(cwritebuf *wb); int writebuf_add_data(cwritebuf *wb, void *data, u64 size); int writebuf_add_dico(cwritebuf *wb, struct s_dico *d, char *magic); int writebuf_add_header(cwritebuf *wb, struct s_dico *d, char *magic, u32 archid, u16 fsid); int writebuf_add_block(cwritebuf *wb, struct s_blockinfo *blkinfo, u32 archid, u16 fsid); #endif // __WRITEBUF_H__ fsarchiver-0.8.5/src/queue.c0000644000176100017610000005004313242523705012671 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include "fsarchiver.h" #include "queue.h" #include "dico.h" #include "common.h" #include "syncthread.h" #include "error.h" struct timespec get_timeout() { struct timespec t; clock_gettime(CLOCK_REALTIME, &t); t.tv_sec++; return t; } s64 queue_init(cqueue *q, s64 blkmax) { pthread_mutexattr_t attr; if (!q) { errprintf("q is NULL\n"); return FSAERR_EINVAL; } // ---- init default attributes q->head=NULL; q->curitemnum=1; q->itemcount=0; q->blkcount=0; q->blkmax=blkmax; q->endofqueue=false; // ---- init pthread structures assert(pthread_mutexattr_init(&attr)==0); assert(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)==0); if (pthread_mutex_init(&q->mutex, &attr)!=0) { msgprintf(3, "pthread_mutex_init failed\n"); return FSAERR_UNKNOWN; } if (pthread_cond_init(&q->cond,NULL)!=0) { msgprintf(3, "pthread_cond_init failed\n"); return FSAERR_UNKNOWN; } return FSAERR_SUCCESS; } s64 queue_destroy(cqueue *q) { cqueueitem *cur; cqueueitem *next; if (!q) { errprintf("q is NULL\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); for (cur=q->head; cur!=NULL; cur=next) { next=cur->next; free(cur); } q->head=NULL; q->itemcount=0; assert(pthread_mutex_unlock(&q->mutex)==0); assert(pthread_mutex_destroy(&q->mutex)==0); assert(pthread_cond_destroy(&q->cond)==0); return FSAERR_SUCCESS; } s64 queue_set_end_of_queue(cqueue *q, bool state) { if (!q) { errprintf("q is NULL\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); q->endofqueue=state; assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return FSAERR_SUCCESS; } bool queue_get_end_of_queue(cqueue *q) { bool res; if (!q) { errprintf("q is NULL\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); res=((q->itemcount<1) && (q->endofqueue==true)); assert(pthread_mutex_unlock(&q->mutex)==0); return res; } bool queuelocked_get_end_of_queue(cqueue *q) { bool res; if (!q) { errprintf("q is NULL\n"); return FSAERR_EINVAL; } res=((q->itemcount<1) && (q->endofqueue==true)); return res; } // runs with the mutex unlocked (external users) s64 queue_count(cqueue *q) { s64 itemcount; if (!q) { errprintf("q is NULL\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); itemcount = q->itemcount; assert(pthread_mutex_unlock(&q->mutex)==0); return itemcount; } // how many items in the queue have a particular status s64 queue_count_status(cqueue *q, int status) { cqueueitem *cur; int count=0; if (!q) { errprintf("q is NULL\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); for (cur=q->head; cur!=NULL; cur=cur->next) { if (status==QITEM_STATUS_NULL || cur->status==status) count++; } assert(pthread_mutex_unlock(&q->mutex)==0); return count; } // add a block at the end of the queue s64 queue_add_block(cqueue *q, cblockinfo *blkinfo, int status) { cqueueitem *item; cqueueitem *cur; if (!q || !blkinfo) { errprintf("a parameter is NULL\n"); return FSAERR_EINVAL; } // create the new item in memory item=malloc(sizeof(cqueueitem)); if (!item) { errprintf("malloc(%ld) failed: out of memory\n", (long)sizeof(cqueueitem)); return FSAERR_ENOMEM; } item->type=QITEM_TYPE_BLOCK; item->status=status; item->blkinfo=*blkinfo; item->next=NULL; assert(pthread_mutex_lock(&q->mutex)==0); // does not make sense to add item on a queue where endofqueue is true if (q->endofqueue==true) { free (item); assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_ENDOFFILE; } // wait while (queue-is-full) to let the other threads remove items first while (q->blkcount > q->blkmax) { struct timespec t=get_timeout(); pthread_cond_timedwait(&q->cond, &q->mutex, &t); } if (q->head==NULL) // if list empty: item is head { q->head=item; } else // list not empty: add items at the end { for (cur=q->head; (cur!=NULL) && (cur->next!=NULL); cur=cur->next); cur->next=item; } q->blkcount++; q->itemcount++; item->itemnum=q->curitemnum++; assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return FSAERR_SUCCESS; } s64 queue_add_header(cqueue *q, cdico *d, char *magic, u16 fsid) { cheadinfo headinfo; if (!q || !d || !magic) { errprintf("parameter is null\n"); return FSAERR_EINVAL; } memset(&headinfo, 0, sizeof(headinfo)); memcpy(headinfo.magic, magic, FSA_SIZEOF_MAGIC); headinfo.fsid=fsid; headinfo.dico=d; return queue_add_header_internal(q, &headinfo); } s64 queue_add_header_internal(cqueue *q, cheadinfo *headinfo) { cqueueitem *item; cqueueitem *cur; if (!q || !headinfo) { errprintf("parameter is null\n"); return FSAERR_EINVAL; } // create the new item in memory item=malloc(sizeof(cqueueitem)); if (!item) { errprintf("malloc(%ld) failed: out of memory 1\n", (long)sizeof(cqueueitem)); return FSAERR_ENOMEM; } item->headinfo=*headinfo; item->type=QITEM_TYPE_HEADER; item->status=QITEM_STATUS_DONE; item->next=NULL; assert(pthread_mutex_lock(&q->mutex)==0); // does not make sense to add item on a queue where endofqueue is true if (q->endofqueue==true) { free(item); assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_ENDOFFILE; } // wait while (queue-is-full) to let the other threads remove items first while (q->blkcount > q->blkmax) { struct timespec t=get_timeout(); pthread_cond_timedwait(&q->cond, &q->mutex, &t); } item->itemnum=q->curitemnum++; if (q->head==NULL) // if list empty { q->head=item; } else // list not empty { for (cur=q->head; (cur!=NULL) && (cur->next!=NULL); cur=cur->next); cur->next=item; } q->itemcount++; assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return FSAERR_SUCCESS; } // function called by the compression thread when a block has been compressed s64 queue_replace_block(cqueue *q, s64 itemnum, cblockinfo *blkinfo, int newstatus) { cqueueitem *cur; if (!q || !blkinfo) { errprintf("a parameter is null\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); if (q->head==NULL) { assert(pthread_mutex_unlock(&q->mutex)==0); msgprintf(MSG_DEBUG1, "q->head is NULL: list is empty\n"); return FSAERR_ENOENT; // item not found } for (cur=q->head; cur!=NULL; cur=cur->next) { if (cur->itemnum==itemnum) // block found { cur->status=newstatus; cur->blkinfo=*blkinfo; assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return FSAERR_SUCCESS; } } assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_ENOENT; // not found } // get number of items to be processed s64 queue_count_items_todo(cqueue *q) { cqueueitem *cur; s64 count=0; if (!q) { errprintf("a parameter is null\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); for (cur=q->head; cur!=NULL; cur=cur->next) { if ((cur->type==QITEM_TYPE_BLOCK) && (cur->status!=QITEM_STATUS_DONE)) count++; } assert(pthread_mutex_unlock(&q->mutex)==0); return count; } // the compression thread requires the first block which has not yet been compressed s64 queue_get_first_block_todo(cqueue *q, cblockinfo *blkinfo) { cqueueitem *cur; s64 itemfound=-1; int res; if (!q || !blkinfo) { errprintf("a parameter is null\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); while (queuelocked_get_end_of_queue(q)==false) { for (cur=q->head; cur!=NULL; cur=cur->next) { if ((cur->type==QITEM_TYPE_BLOCK) && (cur->status==QITEM_STATUS_TODO)) { *blkinfo=cur->blkinfo; cur->status=QITEM_STATUS_PROGRESS; itemfound=cur->itemnum; assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return itemfound; // ">0" means item found } } struct timespec t=get_timeout(); if ((res=pthread_cond_timedwait(&q->cond, &q->mutex, &t))!=0 && res!=ETIMEDOUT) { assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_UNKNOWN; } } // if it failed at the other end of the queue assert(pthread_mutex_unlock(&q->mutex)==0); if (queuelocked_get_end_of_queue(q)) return FSAERR_ENDOFFILE; else return FSAERR_UNKNOWN; } // the writer thread requires the first block of the queue if it ready to go //s64 queue_dequeue_first(cqueue *q, int *type, char *magic, cdico **dico, cblockinfo *blkinfo) s64 queue_dequeue_first(cqueue *q, int *type, cheadinfo *headinfo, cblockinfo *blkinfo) { cqueueitem *cur=NULL; s64 itemfound=-1; int ret; if (!q || !headinfo || !blkinfo) { errprintf("a parameter is null\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); while (queuelocked_get_end_of_queue(q)==false) { if (((cur=q->head)!=NULL) && (cur->status==QITEM_STATUS_DONE)) { if (cur->type==QITEM_TYPE_BLOCK) // item to dequeue is a block { q->blkcount--; *type=cur->type; itemfound=cur->itemnum; *blkinfo=cur->blkinfo; q->head=cur->next; free(cur); q->itemcount--; assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return itemfound; // ">0" means item found } else if (cur->type==QITEM_TYPE_HEADER) // item to dequeue is a dico { *headinfo=cur->headinfo; *type=cur->type; itemfound=cur->itemnum; q->head=cur->next; free(cur); q->itemcount--; assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return itemfound; // ">0" means item found } else { errprintf("invalid item type in queue\n"); assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_EINVAL; } } struct timespec t=get_timeout(); pthread_cond_timedwait(&q->cond, &q->mutex, &t); } // if it failed at the other end of the queue ret=(queuelocked_get_end_of_queue(q)==true)?FSAERR_ENDOFFILE:FSAERR_UNKNOWN; assert(pthread_mutex_unlock(&q->mutex)==0); return ret; } // the extract function wants to read headers from the queue s64 queue_dequeue_block(cqueue *q, cblockinfo *blkinfo) { cqueueitem *cur; s64 itemnum; if (!q || !blkinfo) { errprintf("a parameter is null\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); // while ((first-item-of-the-queue-is-not-ready) && (not-at-the-end-of-the-queue)) while ( (((cur=q->head)==NULL) || (cur->status!=QITEM_STATUS_DONE)) && (queuelocked_get_end_of_queue(q)==false) ) { struct timespec t=get_timeout(); pthread_cond_timedwait(&q->cond, &q->mutex, &t); } // if it failed at the other end of the queue if (queuelocked_get_end_of_queue(q)) { assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_ENDOFFILE; } cur=q->head; assert(cur!=NULL); // queuelocked_is_first_block_ready means there is at least one block in the queue // test the first item if ((cur->type==QITEM_TYPE_BLOCK) && (cur->status==QITEM_STATUS_DONE)) { *blkinfo=cur->blkinfo; q->head=cur->next; itemnum=cur->itemnum; free(cur); q->blkcount--; q->itemcount--; assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return itemnum; } else { errprintf("dequeue - wrong type of data in the queue: wanted a block, found an header\n"); assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return FSAERR_WRONGTYPE; // ok but not found } } s64 queue_dequeue_header(cqueue *q, cdico **d, char *magicbuf, u16 *fsid) { cheadinfo headinfo; s64 lres; if (!q || !d || !magicbuf) { errprintf("a parameter is null\n"); return FSAERR_EINVAL; } if ((lres=queue_dequeue_header_internal(q, &headinfo))<=0) { msgprintf(MSG_STACK, "queue_dequeue_header_internal() failed\n"); return lres; } memcpy(magicbuf, headinfo.magic, FSA_SIZEOF_MAGIC); *d=headinfo.dico; if (fsid!=NULL) *fsid=headinfo.fsid; return lres; } s64 queue_dequeue_header_internal(cqueue *q, cheadinfo *headinfo) { cqueueitem *cur; s64 itemnum; if (!q || !headinfo) { errprintf("a parameter is null\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); // while ((first-item-of-the-queue-is-not-ready) && (not-at-the-end-of-the-queue)) while ( (((cur=q->head)==NULL) || (cur->status!=QITEM_STATUS_DONE)) && (queuelocked_get_end_of_queue(q)==false) ) { struct timespec t=get_timeout(); pthread_cond_timedwait(&q->cond, &q->mutex, &t); } // if it failed at the other end of the queue if (queuelocked_get_end_of_queue(q)) { assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_ENDOFFILE; } cur=q->head; assert (cur!=NULL); // queuelocked_is_first_block_ready means there is at least one block in the queue // test the first item switch (cur->type) { case QITEM_TYPE_HEADER: q->head=cur->next; *headinfo=cur->headinfo; itemnum=cur->itemnum; free(cur); q->itemcount--; assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return itemnum; case QITEM_TYPE_BLOCK: errprintf("dequeue - wrong type of data in the queue: expected a dico and found a block\n"); assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return FSAERR_WRONGTYPE; // ok but not found default: // should never happen errprintf("dequeue - wrong type of data in the queue: expected a dico and found an unknown item\n"); assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return FSAERR_WRONGTYPE; // ok but not found } } // returns true if the first item in queue is a dico or a block which is ready bool queuelocked_is_first_item_ready(cqueue *q) { cqueueitem *cur; if (!q) { errprintf("a parameter is null\n"); return false; // not found } if ((cur=q->head)==NULL) return false; // list empty else if (cur->type==QITEM_TYPE_HEADER) return true; // a dico is always ready else if ((cur->type==QITEM_TYPE_BLOCK) && (cur->status==QITEM_STATUS_DONE)) return true; // a block which has been prepared is ready else // other cases: block not yet prepared return false; } // say what the next item which is ready in the queue is but do not remove it s64 queue_check_next_item(cqueue *q, int *type, char *magic) { cqueueitem *cur; if (!q || !type || !magic) { errprintf("a parameter is null\n"); return FSAERR_EINVAL; } memset(magic, 0, FSA_SIZEOF_MAGIC); *type=0; assert(pthread_mutex_lock(&q->mutex)==0); // while ((first-item-of-the-queue-is-not-ready) && (not-at-the-end-of-the-queue)) while ( (((cur=q->head)==NULL) || (cur->status!=QITEM_STATUS_DONE)) && (queuelocked_get_end_of_queue(q)==false) ) { struct timespec t=get_timeout(); pthread_cond_timedwait(&q->cond, &q->mutex, &t); } // if it failed at the other end of the queue if (queuelocked_get_end_of_queue(q)) { assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_ENDOFFILE; } // test the first item if (((cur=q->head)!=NULL) && (cur->status==QITEM_STATUS_DONE)) { if (cur->type==QITEM_TYPE_BLOCK) // item to dequeue is a block { *type=cur->type; memset(magic, 0, FSA_SIZEOF_MAGIC); assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_SUCCESS; } else if (cur->type==QITEM_TYPE_HEADER) // item to dequeue is a dico { memcpy(magic, cur->headinfo.magic, FSA_SIZEOF_MAGIC); // header contents *type=cur->type; assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_SUCCESS; } else { errprintf("invalid item type in queue: type=%d\n", cur->type); assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_EINVAL; } } assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return FSAERR_ENOENT; // not found } // destroy the first item in the queue (similar to dequeue but do not read it) s64 queue_destroy_first_item(cqueue *q) { cqueueitem *cur; if (!q) { errprintf("a parameter is null\n"); return FSAERR_EINVAL; } assert(pthread_mutex_lock(&q->mutex)==0); // while ((first-item-of-the-queue-is-not-ready or first-item-is-being-processed-by-comp-thread) && (not-at-the-end-of-the-queue)) while ( (((cur=q->head)==NULL) || (cur->status==QITEM_STATUS_PROGRESS)) && (queuelocked_get_end_of_queue(q)==false) ) { struct timespec t=get_timeout(); pthread_cond_timedwait(&q->cond, &q->mutex, &t); } // if it failed at the other end of the queue if (queuelocked_get_end_of_queue(q)) { assert(pthread_mutex_unlock(&q->mutex)==0); return FSAERR_ENDOFFILE; } cur=q->head; assert(cur!=NULL); // queuelocked_is_first_block_ready means there is at least one block in the queue switch (cur->type) { case QITEM_TYPE_BLOCK: q->blkcount--; free(cur->blkinfo.blkdata); break; case QITEM_TYPE_HEADER: dico_destroy(cur->headinfo.dico); break; } q->head=cur->next; free(cur); q->itemcount--; assert(pthread_mutex_unlock(&q->mutex)==0); pthread_cond_broadcast(&q->cond); return FSAERR_SUCCESS; } fsarchiver-0.8.5/src/strlist.h0000644000176100017610000000255413242523705013262 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __STRLIST_H__ #define __STRLIST_H__ struct s_strlist; typedef struct s_strlist cstrlist; struct s_strlistitem; typedef struct s_strlistitem cstrlistitem; struct s_strlistitem { char *str; cstrlistitem *next; }; struct s_strlist { cstrlistitem *head; }; int strlist_destroy(cstrlist *l); int strlist_init(cstrlist *l); int strlist_empty(cstrlist *l); int strlist_add(cstrlist *l, char *str); int strlist_remove(cstrlist *l, char *str); int strlist_exists(cstrlist *l, char *str); int strlist_getitem(cstrlist *l, int index, char *buf, int bufsize); char *strlist_merge(cstrlist *l, char *bufdat, int bufsize, char sep); int strlist_split(cstrlist *l, char *text, char sep); int strlist_count(cstrlist *l); int strlist_show(cstrlist *l); #endif // __STRLIST_H__ fsarchiver-0.8.5/src/fs_reiserfs.h0000644000176100017610000000646413242523705014074 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __FS_REISERFS_H__ #define __FS_REISERFS_H__ struct s_dico; struct s_strlist; int reiserfs_mkfs(struct s_dico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid); int reiserfs_getinfo(struct s_dico *d, char *devname); int reiserfs_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo); int reiserfs_get_reqmntopt(char *partition, struct s_strlist *reqopt, struct s_strlist *badopt); int reiserfs_umount(char *partition, char *mntbuf); int reiserfs_test(char *devname); #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" #define REISER4FS_SUPER_MAGIC_STRING "ReIsEr4" #define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) struct reiserfs_super_block_v1 { u32 s_block_count; /* blocks count */ u32 s_free_blocks; /* free blocks count */ u32 s_root_block; /* root block number */ u32 s_journal_block; /* journal block number */ u32 s_journal_dev; /* journal device number */ u32 s_orig_journal_size; /* size of the journal on FS creation. used to make sure they don't overflow it */ u32 s_journal_trans_max ; /* max number of blocks in a transaction. */ u32 s_journal_block_count ; /* total size of the journal. can change over time */ u32 s_journal_max_batch ; /* max number of blocks to batch into a trans */ u32 s_journal_max_commit_age ; /* in seconds, how old can an async commit be */ u32 s_journal_max_trans_age ; /* in seconds, how old can a transaction be */ u16 s_blocksize; /* block size */ u16 s_oid_maxsize; /* max size of object id array, see get_objectid() commentary */ u16 s_oid_cursize; /* current size of object id array */ u16 s_state; /* valid or error */ char s_magic[12]; /* reiserfs magic string indicates that file system is reiserfs */ u32 s_hash_function_code; /* indicate, what hash fuction is being use to sort names in a directory*/ u16 s_tree_height; /* height of disk tree */ u16 s_bmap_nr; /* amount of bitmap blocks needed to address each block of file system */ u16 s_reserved; } __attribute__ ((__packed__)); struct reiserfs_super_block { struct reiserfs_super_block_v1 s_v1; u32 s_inode_generation; u32 s_flags; /* Right now used only by inode-attributes, if enabled */ unsigned char s_uuid[16]; /* filesystem unique identifier */ unsigned char s_label[16]; /* filesystem volume label */ char s_unused[88]; /* padding and reserved */ }; #endif // __FS_REISERFS_H__ fsarchiver-0.8.5/src/fsarchiver.h0000644000176100017610000002176713242523705013721 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __FSARCHIVER_H__ #define __FSARCHIVER_H__ #include "types.h" // ----------------------------- min and max ----------------------------- #if !defined(min) # define min(a, b) ((a) < (b) ? (a) : (b)) #endif #if !defined(max) # define max(a, b) ((a) > (b) ? (a) : (b)) #endif // -------------------------------- fsarchiver commands --------------------------------------------- enum {OPER_NULL=0, OPER_SAVEFS, OPER_RESTFS, OPER_SAVEDIR, OPER_RESTDIR, OPER_ARCHINFO, OPER_PROBE}; // ----------------------------------- dico sections ------------------------------------------------ enum {DICO_OBJ_SECTION_STDATTR=0, DICO_OBJ_SECTION_XATTR=1, DICO_OBJ_SECTION_WINATTR=2}; // ----------------------------------- archive types ------------------------------------------------ enum {ARCHTYPE_NULL=0, ARCHTYPE_FILESYSTEMS, ARCHTYPE_DIRECTORIES}; // ----------------------------------- volume header and footer ------------------------------------- enum {VOLUMEHEADKEY_VOLNUM, VOLUMEHEADKEY_ARCHID, VOLUMEHEADKEY_FILEFORMATVER, VOLUMEHEADKEY_PROGVERCREAT}; enum {VOLUMEFOOTKEY_VOLNUM, VOLUMEFOOTKEY_ARCHID, VOLUMEFOOTKEY_LASTVOL}; // ----------------------------------- algorithms used to process data------------------------------- enum {COMPRESS_NULL=0, COMPRESS_NONE, COMPRESS_LZO, COMPRESS_GZIP, COMPRESS_BZIP2, COMPRESS_LZMA, COMPRESS_LZ4, COMPRESS_ZSTD}; enum {ENCRYPT_NULL=0, ENCRYPT_NONE, ENCRYPT_BLOWFISH}; // ----------------------------------- dico keys ---------------------------------------------------- enum {OBJTYPE_NULL=0, OBJTYPE_DIR, OBJTYPE_SYMLINK, OBJTYPE_HARDLINK, OBJTYPE_CHARDEV, OBJTYPE_BLOCKDEV, OBJTYPE_FIFO, OBJTYPE_SOCKET, OBJTYPE_REGFILEUNIQUE, OBJTYPE_REGFILEMULTI}; enum {DISKITEMKEY_NULL=0, DISKITEMKEY_OBJECTID, DISKITEMKEY_PATH, DISKITEMKEY_OBJTYPE, DISKITEMKEY_SYMLINK, DISKITEMKEY_HARDLINK, DISKITEMKEY_RDEV, DISKITEMKEY_MODE, DISKITEMKEY_SIZE, DISKITEMKEY_UID, DISKITEMKEY_GID, DISKITEMKEY_ATIME, DISKITEMKEY_MTIME, DISKITEMKEY_MD5SUM, DISKITEMKEY_MULTIFILESCOUNT, DISKITEMKEY_MULTIFILESOFFSET, DISKITEMKEY_LINKTARGETTYPE, DISKITEMKEY_FLAGS}; enum {BLOCKHEADITEMKEY_NULL=0, BLOCKHEADITEMKEY_REALSIZE, BLOCKHEADITEMKEY_BLOCKOFFSET, BLOCKHEADITEMKEY_COMPRESSALGO, BLOCKHEADITEMKEY_ENCRYPTALGO, BLOCKHEADITEMKEY_ARSIZE, BLOCKHEADITEMKEY_COMPSIZE, BLOCKHEADITEMKEY_ARCSUM}; enum {BLOCKFOOTITEMKEY_NULL=0, BLOCKFOOTITEMKEY_MD5SUM}; enum {MAINHEADKEY_NULL=0, MAINHEADKEY_FILEFORMATVER, MAINHEADKEY_PROGVERCREAT, MAINHEADKEY_ARCHIVEID, MAINHEADKEY_CREATTIME, MAINHEADKEY_ARCHLABEL, MAINHEADKEY_ARCHTYPE, MAINHEADKEY_FSCOUNT, MAINHEADKEY_COMPRESSALGO, MAINHEADKEY_COMPRESSLEVEL, MAINHEADKEY_ENCRYPTALGO, MAINHEADKEY_BUFCHECKPASSCLEARMD5, MAINHEADKEY_BUFCHECKPASSCRYPTBUF, MAINHEADKEY_FSACOMPLEVEL, MAINHEADKEY_MINFSAVERSION, MAINHEADKEY_HASDIRSINFOHEAD}; enum {FSYSHEADKEY_NULL=0, FSYSHEADKEY_FILESYSTEM, FSYSHEADKEY_MNTPATH, FSYSHEADKEY_BYTESTOTAL, FSYSHEADKEY_BYTESUSED, FSYSHEADKEY_FSLABEL, FSYSHEADKEY_FSUUID, FSYSHEADKEY_FSINODESIZE, FSYSHEADKEY_FSVERSION, FSYSHEADKEY_FSEXTDEFMNTOPT, FSYSHEADKEY_FSEXTREVISION, FSYSHEADKEY_FSEXTBLOCKSIZE, FSYSHEADKEY_FSEXTFEATURECOMPAT, FSYSHEADKEY_FSEXTFEATUREINCOMPAT, FSYSHEADKEY_FSEXTFEATUREROCOMPAT, FSYSHEADKEY_FSREISERBLOCKSIZE, FSYSHEADKEY_FSREISER4BLOCKSIZE, FSYSHEADKEY_FSXFSBLOCKSIZE, FSYSHEADKEY_FSBTRFSSECTORSIZE, FSYSHEADKEY_NTFSSECTORSIZE, FSYSHEADKEY_NTFSCLUSTERSIZE, FSYSHEADKEY_BTRFSFEATURECOMPAT, FSYSHEADKEY_BTRFSFEATUREINCOMPAT, FSYSHEADKEY_BTRFSFEATUREROCOMPAT, FSYSHEADKEY_NTFSUUID, FSYSHEADKEY_MINFSAVERSION, FSYSHEADKEY_MOUNTINFO, FSYSHEADKEY_ORIGDEV, FSYSHEADKEY_TOTALCOST, FSYSHEADKEY_FSEXTFSCKMAXMNTCOUNT, FSYSHEADKEY_FSEXTFSCKCHECKINTERVAL, FSYSHEADKEY_FSEXTEOPTRAIDSTRIPEWIDTH, FSYSHEADKEY_FSEXTEOPTRAIDSTRIDE, FSYSHEADKEY_FSINODEBLOCKSPERGROUP, FSYSHEADKEY_FSXFSVERSION, FSYSHEADKEY_FSXFSFEATURECOMPAT, FSYSHEADKEY_FSXFSFEATUREROCOMPAT, FSYSHEADKEY_FSXFSFEATUREINCOMPAT, FSYSHEADKEY_FSXFSFEATURELOGINCOMPAT, FSYSHEADKEY_FSVFATTYPE, FSYSHEADKEY_FSVFATSERIAL}; enum {DIRSINFOKEY_NULL=0, DIRSINFOKEY_TOTALCOST}; // -------------------------------- fsarchiver errors --------------------------------------------- enum {FSAERR_SUCCESS=0, // success FSAERR_UNKNOWN=-1, // uknown error (default code that means error) FSAERR_ENOMEM=-2, // out of memory error FSAERR_EINVAL=-3, // invalid parameter FSAERR_ENOENT=-4, // entry not found FSAERR_ENDOFFILE=-5, // end of file/queue FSAERR_WRONGTYPE=-6, // wrong type of data FSAERR_NOTOPEN=-7, // resource has been closed FSAERR_ENOSPC=-8, // no space left on device FSAERR_SEEK=-9, // lseek64 error FSAERR_READ=-10, // read error FSAERR_WRITE=-11 // write error }; // -------------------------------- old errors codes --------------------------------------------- enum {OLDERR_FATAL=1, OLDERR_MINOR=2}; // ----------------------------- fsarchiver const ------------------------ #define FSA_VERSION PACKAGE_VERSION #define FSA_RELDATE PACKAGE_RELDATE #define FSA_FILEFORMAT PACKAGE_FILEFMT #define FSA_GCRYPT_VERSION "1.2.3" #define FSA_MAX_FILEFMTLEN 32 #define FSA_MAX_PROGVERLEN 32 #define FSA_MAX_FSNAMELEN 128 #define FSA_MAX_DEVLEN 256 #define FSA_MAX_UUIDLEN 128 #define FSA_MAX_BLKDEVICES 256 #define FSA_MAX_FSPERARCH 128 #define FSA_MAX_COMPJOBS 32 #define FSA_MAX_QUEUESIZE 32 #define FSA_MAX_BLKSIZE 921600 #define FSA_DEF_BLKSIZE 524288 #define FSA_DEF_COMPRESS_ALGO COMPRESS_GZIP // legacy compression is using gzip by default #define FSA_DEF_COMPRESS_LEVEL 6 // legacy compression is with "gzip -6" by default #define FSA_DEF_ZSTD_LEVEL 8 // default compression level when zstd is used #define FSA_MAX_SMALLFILECOUNT 512 // there can be up to FSA_MAX_SMALLFILECOUNT files copied in a single data block #define FSA_MAX_SMALLFILESIZE 131072 // files smaller than that will be grouped with other small files in a single data block #define FSA_COST_PER_FILE 16384 // how much it cost to copy an empty file/dir/link: used to eval the progress bar #define FSA_MAX_LABELLEN 512 #define FSA_MIN_PASSLEN 6 #define FSA_MAX_PASSLEN 64 #define FSA_FILESYSID_NULL 0xFFFF #define FSA_CHECKPASSBUF_SIZE 4096 #define FSA_FILEFLAGS_SPARSE 1<<0 // set when a regfile is a sparse file // ----------------------------- fsarchiver magics -------------------------------------------------- #define FSA_SIZEOF_MAGIC 4 #define FSA_MAGIC_VOLH "FsA0" // volume header (one per volume at the very beginning) #define FSA_MAGIC_VOLF "FsAE" // volume footer (one per volume at the very end) #define FSA_MAGIC_MAIN "ArCh" // archive header (one per archive at the beginning of the first volume) #define FSA_MAGIC_FSIN "FsIn" // filesys info (one per filesystem at the beginning of the archive) #define FSA_MAGIC_FSYB "FsYs" // filesys begin (one per filesystem when the filesys contents start) #define FSA_MAGIC_DIRS "DiRs" // dirs info (one per archive after mainhead before flat dirs/files) #define FSA_MAGIC_OBJT "ObJt" // object header (one per object: regfiles, dirs, symlinks, ...) #define FSA_MAGIC_BLKH "BlKh" // datablk header (one per data block, each regfile may have [0-n]) #define FSA_MAGIC_FILF "FiLf" // filedat footer (one per regfile, after the list of data blocks) #define FSA_MAGIC_DATF "DaEn" // data footer (one per file system, at the end of its contents, or after the contents of the flatfiles) // ------------ global variables --------------------------- extern char *valid_magic[]; // -------------------------------- version_number to u64 ------------------------------------------- #define FSA_VERSION_BUILD(a, b, c, d) ((u64)((((u64)a&0xFFFF)<<48)+(((u64)b&0xFFFF)<<32)+(((u64)c&0xFFFF)<<16)+(((u64)d&0xFFFF)<<0))) #define FSA_VERSION_GET_A(ver) ((((u64)ver)>>48)&0xFFFF) #define FSA_VERSION_GET_B(ver) ((((u64)ver)>>32)&0xFFFF) #define FSA_VERSION_GET_C(ver) ((((u64)ver)>>16)&0xFFFF) #define FSA_VERSION_GET_D(ver) ((((u64)ver)>>0)&0xFFFF) #endif // __FSARCHIVER_H__ fsarchiver-0.8.5/src/strdico.c0000644000176100017610000001706513242523705013223 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ /* * Defines an object to store a dictionnary where the key and the * associated value are both strings. It's used to store string of * parameters such as "id=0,dest=/dev/sda1,mkfs=reiserfs" * cstrdico *d; * d=strdico_alloc(); * strdico_set_valid_keys(d, "name,phone,fax"); * strdico_parse_string(d, "name=john,phone=123456789,fax="); * strdico_parse_string(d, "phone=987654321"); * strdico_get_string(d, mybuffer, sizeof(mybuffer), "phone"); * strdico_destroy(d); */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include "fsarchiver.h" #include "strdico.h" #include "common.h" #include "error.h" cstrdico *strdico_alloc() { cstrdico *d; if ((d=malloc(sizeof(cstrdico)))==NULL) return NULL; d->head=NULL; d->validkeys=NULL; return d; } int strdico_destroy(cstrdico *d) { cstrdicoitem *item, *next; assert(d); item=d->head; while (item!=NULL) { next=item->next; free(item->key); if (item->value!=NULL) free(item->value); free(item); item=next; } if (d->validkeys!=NULL) free(d->validkeys); free(d); return FSAERR_SUCCESS; } int strdico_set_valid_keys(cstrdico *d, const char *keys) { assert(d); if ((d->validkeys=strdup(keys))==NULL) { errprintf("strdup() failed: out of memory\n"); return FSAERR_ENOMEM; } return FSAERR_SUCCESS; } int strdico_parse_string(cstrdico *d, const char *strdefs) { char *bakdefs; char *saveptr; char *result; char delims[]=",;\t\n"; char key[1024]; char value[1024]; int i, pos; int res; assert(d); assert(strdefs); // init if ((bakdefs=strdup(strdefs))==NULL) { errprintf("strdup() failed: out of memory\n"); return FSAERR_ENOMEM; } result=strtok_r(bakdefs, delims, &saveptr); while (result!=NULL) { memset(key, 0, sizeof(key)); memset(value, 0, sizeof(value)); for (i=0; (result[i]!=0) && (result[i]!='=') && (i #include #include #include "fsarchiver.h" #include "dico.h" #include "regmulti.h" #include "common.h" #include "queue.h" #include "error.h" int regmulti_empty(cregmulti *m) { int i; if (!m) { errprintf("invalid param\n"); return -1; } m->count=0; m->usedsize=0; for (i=0; i < m->maxitems; i++) m->objhead[i]=NULL; return 0; } int regmulti_init(cregmulti *m, u32 maxblksize) { if (!m) { errprintf("invalid param\n"); return -1; } m->maxitems=FSA_MAX_SMALLFILECOUNT; m->maxblksize=min(maxblksize, FSA_MAX_BLKSIZE); return regmulti_empty(m); } int regmulti_count(cregmulti *m, cdico *header, char *data, u32 datsize) { if (!m) { errprintf("invalid param\n"); return -1; } return m->count; } bool regmulti_save_enough_space_for_new_file(cregmulti *m, u32 filesize) { if (!m) { errprintf("invalid param\n"); return false; } if (m->count >= m->maxitems) return false; if (m->usedsize + filesize > m->maxblksize) return false; return true; } int regmulti_save_addfile(cregmulti *m, cdico *header, char *data, u32 datsize) { if (!m) { errprintf("invalid param\n"); return -1; } if (m->count >= m->maxitems) { errprintf("regmulti is full: it contains %ld items\n", (long)m->count); return -1; } if (m->usedsize+datsize > m->maxblksize) { errprintf("block is too small to store that new sub-block of data\n"); return -1; } m->objhead[m->count]=header; memcpy(m->data+m->usedsize, data, datsize); m->usedsize+=datsize; m->count++; return 0; } // add headers and datblock at the end of the queue int regmulti_save_enqueue(cregmulti *m, cqueue *q, int fsid) { cblockinfo blkinfo; char *dynblock; u32 offset=0; u64 filesize; int i; if (!m) { errprintf("invalid param\n"); return -1; } // don't do anything if block is empty if (m->count==0) return 0; for (i=0; i < m->count; i++) { if (m->objhead[i]==NULL) { errprintf("error: objhead[%d]==NULL\n", i); return -1; } // get file size from header if (dico_get_u64(m->objhead[i], DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_SIZE, &filesize)!=0) { errprintf("Cannot read filesize DISKITEMKEY_SIZE from archive\n"); return -1; } // the extraction function needs to know how many small-files are packed together if (dico_add_u32(m->objhead[i], DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_MULTIFILESCOUNT, (u32)m->count)!=0) { errprintf("dico_add_u32(DISKITEMKEY_MULTIFILESCOUNT) failed\n"); return -1; } // the extraction function needs to know where the data for this file are in the block if (dico_add_u32(m->objhead[i], DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_MULTIFILESOFFSET, (u32)offset)!=0) { errprintf("dico_add_u32(DISKITEMKEY_MULTIFILESCOUNT) failed\n"); return -1; } offset+=(u32)filesize; if (queue_add_header(q, m->objhead[i], FSA_MAGIC_OBJT, fsid)!=0) { errprintf("queue_add_header() failed\n"); return -1; } } // make a copy of the static block to dynamic memory if ((dynblock=malloc(m->usedsize)) == NULL) { errprintf("malloc(%ld) failed: out of memory\n", (long)m->usedsize); return -1; } memcpy(dynblock, m->data, m->usedsize); memset(&blkinfo, 0, sizeof(blkinfo)); blkinfo.blkrealsize=m->usedsize; blkinfo.blkdata=(char*)dynblock; blkinfo.blkoffset=0; // no meaning for multi-regfiles blkinfo.blkfsid=fsid; if (queue_add_block(q, &blkinfo, QITEM_STATUS_TODO)!=0) { errprintf("queue_add_block() failed\n"); return -1; } return 0; } int regmulti_rest_addheader(cregmulti *m, cdico *header) { if (!m) { errprintf("invalid param\n"); return -1; } if (m->count >= m->maxitems) { errprintf("regmulti is full: it contains %ld items\n", (long)m->count); return -1; } m->objhead[m->count]=header; m->count++; return 0; } int regmulti_rest_setdatablock(cregmulti *m, char *data, u32 datsize) { if (!m) { errprintf("invalid param\n"); return -1; } if (m->usedsize+datsize > m->maxblksize) { errprintf("block is too small to store that new sub-block of data\n"); return -1; } memcpy(m->data, data, datsize); m->usedsize=datsize; return 0; } int regmulti_rest_getfile(cregmulti *m, int index, cdico **filehead, char *data, u64 *datsize, u32 bufsize) { u32 offset; u64 filesize; if (!m || !filehead) { errprintf("invalid param\n"); return -1; } if (index >= m->count) { errprintf("index=%d out of scope: the structure only contains %ld items\n", index, (long)m->count); return -1; } // ---- return the header to the calling function *filehead=m->objhead[index]; // ---- return the data to the calling function if (dico_get_u64(m->objhead[index], DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_SIZE, &filesize)!=0) { errprintf("Cannot read filesize DISKITEMKEY_SIZE from archive\n"); return -1; } if (dico_get_u32(m->objhead[index], DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_MULTIFILESOFFSET, &offset)!=0) { errprintf("Cannot read filesize DISKITEMKEY_SIZE from archive\n"); return -1; } *datsize=filesize; memcpy(data, m->data+offset, filesize); return 0; } fsarchiver-0.8.5/src/comp_lzma.c0000644000176100017610000000757013242523705013535 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "fsarchiver.h" #include "common.h" #include "comp_lzma.h" #include "error.h" #ifdef OPTION_LZMA_SUPPORT #include int compress_block_lzma(u64 origsize, u64 *compsize, u8 *origbuf, u8 *compbuf, u64 compbufsize, int level) { lzma_stream lzma = LZMA_STREAM_INIT; int res; // init lzma structures lzma.next_in = origbuf; lzma.avail_in = origsize; lzma.next_out = compbuf; lzma.avail_out = compbufsize; // Initialize a coder to the lzma_stream if ((res=lzma_easy_encoder(&lzma, level, LZMA_CHECK_CRC32))!=LZMA_OK) { switch (res) { case LZMA_MEM_ERROR: errprintf("lzma_easy_encoder(%d): LZMA compression failed " "with an out of memory error.\nYou should use a lower " "compression level to reduce the memory requirement.\n", level); lzma_end(&lzma); return FSAERR_ENOMEM; default: errprintf("lzma_easy_encoder(%d) failed with res=%d\n", level, res); lzma_end(&lzma); return FSAERR_UNKNOWN; } } if ((res=lzma_code(&lzma, LZMA_RUN))!=LZMA_OK) { errprintf("lzma_code(LZMA_RUN) failed with res=%d\n", res); lzma_end(&lzma); return FSAERR_UNKNOWN; } if ((res=lzma_code(&lzma, LZMA_FINISH))!=LZMA_STREAM_END && res!=LZMA_OK) { errprintf("lzma_code(LZMA_FINISH) failed with res=%d\n", res); lzma_end(&lzma); return FSAERR_UNKNOWN; } *compsize=(u64)(lzma.total_out); lzma_end(&lzma); return FSAERR_SUCCESS; } int uncompress_block_lzma(u64 compsize, u64 *origsize, u8 *origbuf, u64 origbufsize, u8 *compbuf) { lzma_stream lzma = LZMA_STREAM_INIT; u64 maxmemlimit=3ULL*1024ULL*1024ULL*1024ULL; u64 memlimit=96*1024*1024; int res; // init lzma structures lzma.next_in = compbuf; lzma.avail_in = compsize; lzma.next_out = origbuf; lzma.avail_out = origbufsize; // Initialize a coder to the lzma_stream if ((res=lzma_auto_decoder(&lzma, memlimit, 0))!=LZMA_OK) { errprintf("lzma_auto_decoder() failed with res=%d\n", res); lzma_end(&lzma); return FSAERR_UNKNOWN; } do // retry if lzma_code() returns LZMA_MEMLIMIT_ERROR (increase the memory limit) { if ((res=lzma_code(&lzma, LZMA_RUN)) != LZMA_STREAM_END) // if error { if (res == LZMA_MEMLIMIT_ERROR) // we have to raise the memory limit { memlimit+=64*1024*1024; lzma_memlimit_set(&lzma, memlimit); msgprintf(MSG_VERB2, "lzma_memlimit_set(%lld)\n", (long long)memlimit); } else // another error { errprintf("lzma_code(LZMA_RUN) failed with res=%d\n", res); lzma_end(&lzma); return FSAERR_UNKNOWN; } } } while ((res == LZMA_MEMLIMIT_ERROR) && (memlimit < maxmemlimit)); *origsize=(u64)(lzma.total_out); lzma_end(&lzma); switch (res) { case LZMA_STREAM_END: return FSAERR_SUCCESS; case LZMA_MEMLIMIT_ERROR: return FSAERR_ENOMEM; default: return FSAERR_UNKNOWN; } } #endif // OPTION_LZMA_SUPPORT fsarchiver-0.8.5/src/strlist.c0000644000176100017610000001370513242523705013255 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "fsarchiver.h" #include "strlist.h" #include "common.h" #include "error.h" int strlist_init(cstrlist *l) { if (l==NULL) return -1; l->head=NULL; return 0; } int strlist_destroy(cstrlist *l) { if (l==NULL) return -1; strlist_empty(l); return 0; } int strlist_empty(cstrlist *l) { cstrlistitem *item, *next; if (l==NULL) return -1; for (item=l->head; item!=NULL; item=next) { next=item->next; free(item->str); free(item); } l->head=NULL; return 0; } int strlist_add(cstrlist *l, char *str) { cstrlistitem *item, *lnew; int len; if (!l || !str || !strlen(str)) { errprintf("invalid param\n"); return -1; } if (strlist_exists(l, str)==true) { errprintf("canot add dring: [%s] is already in the list\n", str); return -1; } if ((lnew=malloc(sizeof(cstrlistitem)))==NULL) { errprintf("malloc() failed\n"); return -1; } memset(lnew, 0, sizeof(cstrlistitem)); lnew->next=NULL; len=strlen(str); if ((lnew->str=malloc(len+1))==NULL) { errprintf("malloc() failed\n"); free(lnew); return -1; } memcpy(lnew->str, str, len+1); // go to the end of the item and check for duplicates if (l->head==NULL) // item is empty { l->head=lnew; } else // item is not empty { for (item=l->head; (item!=NULL) && (item->next!=NULL); item=item->next); item->next=lnew; } return 0; } int strlist_getitem(cstrlist *l, int index, char *buf, int bufsize) { cstrlistitem *item; int pos=0; if (!l || !buf || bufsize<=0) { errprintf("invalid param\n"); return -1; } for (item=l->head; (item!=NULL) && (pos++ < index); item=item->next); if (item!=NULL) { snprintf(buf, bufsize, "%s", item->str); return 0; } else { return -1; } } int strlist_remove(cstrlist *l, char *str) { cstrlistitem *item, *next; if (!l || !str) { errprintf("invalid param\n"); return -1; } if (!l->head) return -1; // not found // if item to remove found in first pos item=l->head; if (strcmp(item->str, str)==0) { free(item->str); l->head=item->next; free(item); return 0; // item removed } // item to remove not in first pos for (item=l->head; (item!=NULL) && (item->next!=NULL); item=item->next) { next=item->next; if (strcmp(next->str, str)==0) { free(next->str); item->next=next->next; free(next); return 0; // item removed } } return -1; // not found } char *strlist_merge(cstrlist *l, char *bufdat, int bufsize, char sep) { cstrlistitem *item; if (!l || !bufdat || bufsize<=0) { errprintf("invalid param\n"); return NULL; } // init memset(bufdat, 0, bufsize); // item to remove not in first pos for (item=l->head; item!=NULL; item=item->next) { if (item!=l->head) // not the first item: write separator strlcatf(bufdat, bufsize, "%c", sep); strlcatf(bufdat, bufsize, "%s", item->str); } return bufdat; } int strlist_exists(cstrlist *l, char *str) { cstrlistitem *item; if (!l || !str) { errprintf("invalid param\n"); return -1; // error } if (!l->head) return false; // not found // item to remove not in first pos for (item=l->head; item!=NULL; item=item->next) if (strcmp(item->str, str)==0) return true; // item found return false; // not found } int strlist_split(cstrlist *l, char *text, char sep) { char *textcopy; char delims[4]; char *saveptr; char *result; int len; if (!l || !text) { errprintf("invalid param\n"); return -1; } // init len=strlen(text); snprintf(delims, sizeof(delims), "%c", sep); strlist_empty(l); if ((textcopy=malloc(len+1))==NULL) { errprintf("malloc(%d) failed\n", len+1); return -1; } memcpy(textcopy, text, len+1); for (result=strtok_r(textcopy, delims, &saveptr); result!=NULL; result=strtok_r(NULL, delims, &saveptr)) { if (strlist_add(l, result)!=0) { errprintf("strlist_add(l, [%s]) failed\n", result); free(textcopy); return -1; } } free(textcopy); return 0; } int strlist_count(cstrlist *l) { cstrlistitem *item; int count=0; if (!l) { errprintf("invalid param\n"); return -1; // error } if (!l->head) { return 0; } else { for (item=l->head; (item!=NULL); item=item->next) count++; } return count; } int strlist_show(cstrlist *l) { cstrlistitem *item; int count=0; if (!l) { errprintf("invalid param\n"); return -1; // error } if (!l->head) { printf("list is empty"); } else { for (item=l->head; (item!=NULL); item=item->next) printf("item[%d]: [%s]\n", count++, item->str); } return 0; } fsarchiver-0.8.5/src/crypto.h0000644000176100017610000000153513242523705013074 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __CRYPTO_H__ #define __CRYPTO_H__ #include "types.h" int crypto_init(); int crypto_blowfish(u64 insize, u64 *outsize, u8 *inbuf, u8 *outbuf, u8 *password, int passlen, int enc); int crypto_random(u8 *buf, int bufsize); int crypto_cleanup(); #endif // __CRYPTO_H__ fsarchiver-0.8.5/src/writebuf.c0000644000176100017610000001753013242523705013400 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include "fsarchiver.h" #include "writebuf.h" #include "common.h" #include "error.h" #include "queue.h" #include "dico.h" cwritebuf *writebuf_alloc() { cwritebuf *wb; if ((wb=malloc(sizeof(cwritebuf)))==NULL) { errprintf("malloc(%d) failed: cannot allocate memory for writebuf\n", (int)sizeof(cwritebuf)); return NULL; } wb->size=0; wb->data=NULL; return wb; } int writebuf_destroy(cwritebuf *wb) { if (wb==NULL) { errprintf("wb is NULL\n"); return -1; } if (wb->data) { free(wb->data); wb->data=NULL; } wb->size=0; free(wb); return 0; } int writebuf_add_data(cwritebuf *wb, void *data, u64 size) { u64 newsize; if (wb==NULL) { errprintf("wb is NULL\n"); return -1; } if (size==0) { errprintf("size=0\n"); return -1; } newsize=wb->size+size; wb->data=realloc(wb->data, newsize+4); // "+4" required else the last byte of the buffer may be alterred (see release-0.3.3) if (!wb->data) { errprintf("realloc(oldsize=%ld, newsize=%ld) failed\n", (long)wb->size, (long)newsize+4); return -1; } memcpy(wb->data+wb->size, data, size); wb->size+=size; return 0; } int writebuf_add_dico(cwritebuf *wb, cdico *d, char *magic) { struct s_dicoitem *item; int itemnum; u32 headerlen; u32 checksum; u8 *buffer; u8 *bufpos; u16 temp16; u32 temp32; u16 count; if (!wb || !d) { errprintf("a parameter is null\n"); return -1; } // 0. debugging msgprintf(MSG_DEBUG2, "archio_write_dico(wb=%p, dico=%p, magic=[%c%c%c%c])\n", wb, d, magic[0], magic[1], magic[2], magic[3]); for (item=d->head; item!=NULL; item=item->next) if ((item->section==DICO_OBJ_SECTION_STDATTR) && (item->key==DISKITEMKEY_PATH) && (memcmp(magic, "ObJt", 4)==0)) msgprintf(MSG_DEBUG2, "filepath=[%s]\n", item->data); // 1. how many valid items there are count=dico_count_all_sections(d); msgprintf(MSG_DEBUG2, "dico_count_all_sections(dico=%p)=%d\n", d, (int)count); // 2. calculate len of header headerlen=sizeof(u16); // count for (item=d->head; item!=NULL; item=item->next) { headerlen+=sizeof(u8); // type headerlen+=sizeof(u8); // section headerlen+=sizeof(u16); // key headerlen+=sizeof(u16); // data size headerlen+=item->size; // data } msgprintf(MSG_DEBUG2, "calculated headerlen for that dico: headerlen=%d\n", (int)headerlen); // 3. allocate memory for header bufpos=buffer=malloc(headerlen); if (!buffer) { errprintf("cannot allocate memory for buffer"); return -1; } // 4. write items count in buffer temp16=cpu_to_le16(count); msgprintf(MSG_DEBUG2, "mempcpy items count to buffer: u16 count=%d\n", (int)count); bufpos=mempcpy(bufpos, &temp16, sizeof(temp16)); // 5. write all items in buffer for (item=d->head, itemnum=0; item!=NULL; item=item->next, itemnum++) { msgprintf(MSG_DEBUG2, "itemnum=%d (type=%d, section=%d, key=%d, size=%d)\n", (int)itemnum++, (int)item->type, (int)item->section, (int)item->key, (int)item->size); // a. write data type buffer bufpos=mempcpy(bufpos, &item->type, sizeof(item->type)); // b. write section to buffer bufpos=mempcpy(bufpos, &item->section, sizeof(item->section)); // c. write key to buffer temp16=cpu_to_le16(item->key); bufpos=mempcpy(bufpos, &temp16, sizeof(temp16)); // d. write sizeof(data) to buffer temp16=cpu_to_le16(item->size); bufpos=mempcpy(bufpos, &temp16, sizeof(temp16)); // e. write data to buffer if (item->size>0) bufpos=mempcpy(bufpos, item->data, item->size); } msgprintf(MSG_DEBUG2, "all %d items mempcopied to buffer\n", (int)itemnum); // 6. write header-len, header-data, header-checksum temp32=cpu_to_le32(headerlen); if (writebuf_add_data(wb, &temp32, sizeof(temp32))!=0) { free(buffer); return -1; } if (writebuf_add_data(wb, buffer, headerlen)!=0) { free(buffer); return -1; } checksum=fletcher32(buffer, headerlen); temp32=cpu_to_le32(checksum); if (writebuf_add_data(wb, &temp32, sizeof(temp32))!=0) { free(buffer); return -1; } free(buffer); msgprintf(MSG_DEBUG2, "end of archio_write_dico(wb=%p, dico=%p, magic=[%c%c%c%c])\n", wb, d, magic[0], magic[1], magic[2], magic[3]); return 0; } int writebuf_add_header(cwritebuf *wb, cdico *d, char *magic, u32 archid, u16 fsid) { u16 temp16; u32 temp32; if (!wb || !d || !magic) { errprintf("a parameter is null\n"); return -1; } // A. write dico magic string if (writebuf_add_data(wb, magic, FSA_SIZEOF_MAGIC)!=0) { errprintf("writebuf_add_data() failed to write FSA_SIZEOF_MAGIC\n"); return -2; } // B. write archive id temp32=cpu_to_le32(archid); if (writebuf_add_data(wb, &temp32, sizeof(temp32))!=0) { errprintf("writebuf_add_data() failed to write archid\n"); return -3; } // C. write filesystem id temp16=cpu_to_le16(fsid); if (writebuf_add_data(wb, &temp16, sizeof(temp16))!=0) { errprintf("writebuf_add_data() failed to write fsid\n"); return -3; } // D. write the dico of the header if (writebuf_add_dico(wb, d, magic) != 0) { errprintf("archio_write_dico() failed to write the header dico\n"); return -4; } return 0; } int writebuf_add_block(cwritebuf *wb, struct s_blockinfo *blkinfo, u32 archid, u16 fsid) { cdico *blkdico; // header written in file int res; if (!wb || !blkinfo) { errprintf("a parameter is null\n"); return -1; } if ((blkdico=dico_alloc())==NULL) { errprintf("dico_alloc() failed\n"); return -1; } if (blkinfo->blkarsize==0) { errprintf("blkinfo->blkarsize=0: block is empty\n"); return -1; } // prepare header dico_add_u64(blkdico, 0, BLOCKHEADITEMKEY_BLOCKOFFSET, blkinfo->blkoffset); dico_add_u32(blkdico, 0, BLOCKHEADITEMKEY_REALSIZE, blkinfo->blkrealsize); dico_add_u32(blkdico, 0, BLOCKHEADITEMKEY_ARSIZE, blkinfo->blkarsize); dico_add_u32(blkdico, 0, BLOCKHEADITEMKEY_COMPSIZE, blkinfo->blkcompsize); dico_add_u32(blkdico, 0, BLOCKHEADITEMKEY_ARCSUM, blkinfo->blkarcsum); dico_add_u16(blkdico, 0, BLOCKHEADITEMKEY_COMPRESSALGO, blkinfo->blkcompalgo); dico_add_u16(blkdico, 0, BLOCKHEADITEMKEY_ENCRYPTALGO, blkinfo->blkcryptalgo); // write block header res=writebuf_add_header(wb, blkdico, FSA_MAGIC_BLKH, archid, fsid); dico_destroy(blkdico); if (res!=0) { msgprintf(MSG_STACK, "cannot write FSA_MAGIC_BLKH block-header\n"); return -1; } // write block data if (writebuf_add_data(wb, blkinfo->blkdata, blkinfo->blkarsize)!=0) { msgprintf(MSG_STACK, "cannot write data block: writebuf_add_data() failed\n"); return -1; } return 0; } fsarchiver-0.8.5/src/comp_gzip.c0000644000176100017610000000350213242523705013532 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "fsarchiver.h" #include "common.h" #include "comp_gzip.h" #include "error.h" int compress_block_gzip(u64 origsize, u64 *compsize, u8 *origbuf, u8 *compbuf, u64 compbufsize, int level) { uLong gzsize; Bytef *gzbuffer; gzsize=(uLong)compbufsize; gzbuffer=(Bytef *)compbuf; switch (compress2(gzbuffer, &gzsize, (const Bytef*)origbuf, (uLong)origsize, level)) { case Z_OK: *compsize=(u64)gzsize; return FSAERR_SUCCESS; case Z_MEM_ERROR: return FSAERR_ENOMEM; default: return FSAERR_UNKNOWN; } return FSAERR_UNKNOWN; } int uncompress_block_gzip(u64 compsize, u64 *origsize, u8 *origbuf, u64 origbufsize, u8 *compbuf) { uLong gzsize=(uLong)origbufsize; Bytef *gzbuffer=(Bytef *)origbuf; int res; switch ((res=uncompress(gzbuffer, &gzsize, (const Bytef*)compbuf, (uLong)compsize))) { case Z_OK: *origsize=(u64)gzsize; return FSAERR_SUCCESS; case Z_MEM_ERROR: return FSAERR_ENOMEM; default: errprintf("uncompress() failed, res=%d\n", res); return FSAERR_UNKNOWN; } } fsarchiver-0.8.5/src/queue.h0000644000176100017610000001172613242523705012703 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __QUEUE_H__ #define __QUEUE_H__ #include enum {QITEM_STATUS_NULL=0, QITEM_STATUS_TODO, QITEM_STATUS_PROGRESS, QITEM_STATUS_DONE}; enum {QITEM_TYPE_NULL=0, QITEM_TYPE_BLOCK, QITEM_TYPE_HEADER}; struct s_dico; struct s_blockinfo; typedef struct s_blockinfo cblockinfo; struct s_headinfo; typedef struct s_headinfo cheadinfo; struct s_queueitem; typedef struct s_queueitem cqueueitem; struct s_queue; typedef struct s_queue cqueue; struct s_blockinfo // used when (type==QITEM_TYPE_BLOCK) { char *blkdata; // pointer to data block as it is at a particular time (compressed or uncompressed) u32 blkrealsize; // size of the data in the normal state (not compressed and not crypted) u64 blkoffset; // offset of the block in the normal file u32 blkarcsum; // checksum of the block as it it when it's in the archive (compressed and encrypted) u32 blkarsize; // size of the block as it is in the archive (compressed and encrypted) u16 blkcompalgo; // algo used to compressed the block u32 blkcompsize; // size of the block after compression and before encryption u16 blkcryptalgo; // algo used to compressed the block u16 blkfsid; // id of filesystem to which the block belongs bool blklocked; // true if locked (being processed in the compress/crypt thread) }; struct s_headinfo // used when (type==QITEM_TYPE_HEADER) { char magic[FSA_SIZEOF_MAGIC+1]; // magic which is used to identify the type of header u16 fsid; // the filesystem to which this header belongs to, or FSA_FILESYSID_NULL if global header struct s_dico *dico; }; struct s_queueitem { int type; // QITEM_TYPE_BLOCK or QITEM_TYPE_HEADER int status; // compressed, being-compressed, not-yet-compressed s64 itemnum; // unique identifier of the item in the queue cqueueitem *next; // next block in the linked list cblockinfo blkinfo; // used when type==QITEM_TYPE_BLOCK (for blocks only) cheadinfo headinfo; // used when type==QITEM_TYPE_HEADER (for headers only) }; struct s_queue { cqueueitem *head; // head of the queue: first item pthread_mutex_t mutex; // pthread mutex for data protection pthread_cond_t cond; // condition for pthread synchronization s64 curitemnum; // unique id given to every new item (block or header) u64 itemcount; // how many items there are (headers + blocks) u64 blkcount; // how many blocks items there are (items where type==QITEM_TYPE_BLOCK only) u64 blkmax; // how many blocks items there can be before the queue is considered as full bool endofqueue; // set to true when no more data to put in queue (like eof): reader must stop }; // ----return status // a) ">0" means success for functions that return item numbers // b) =0 means success for functions that do not return item numbers // c) "<0" QERR error number // init and destroy s64 queue_init(cqueue *l, s64 blkmax); s64 queue_destroy(cqueue *l); // information functions s64 queue_count(cqueue *l); s64 queue_count_status(struct s_queue *l, int status); s64 queue_is_first_item_ready(struct s_queue *q); s64 queue_check_next_item(cqueue *q, int *type, char *magic); s64 queue_count_items_todo(cqueue *q); // modification functions s64 queue_add_block(cqueue *q, cblockinfo *blkinfo, int status); s64 queue_add_header(cqueue *q, struct s_dico *d, char *magic, u16 fsid); s64 queue_add_header_internal(cqueue *q, cheadinfo *headinfo); s64 queue_replace_block(cqueue *q, s64 itemnum, cblockinfo *blkinfo, int newstatus); s64 queue_destroy_first_item(cqueue *q); // end of queue functions s64 queue_set_end_of_queue(cqueue *q, bool state); bool queue_get_end_of_queue(cqueue *q); // get item from queue functions s64 queue_get_first_block_todo(cqueue *q, cblockinfo *blkinfo); s64 queue_dequeue_header(cqueue *q, struct s_dico **d, char *magicbuf, u16 *fsid); s64 queue_dequeue_header_internal(cqueue *q, cheadinfo *headinfo); s64 queue_dequeue_block(cqueue *q, cblockinfo *blkinfo); s64 queue_dequeue_first(cqueue *q, int *type, cheadinfo *headinfo, cblockinfo *blkinfo); #endif // __QUEUE_H__ fsarchiver-0.8.5/src/comp_lzo.h0000644000176100017610000000167513242523705013403 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __COMPRESS_LZO_H__ #define __COMPRESS_LZO_H__ #ifdef OPTION_LZO_SUPPORT #include int compress_block_lzo(u64 origsize, u64 *compsize, u8 *origbuf, u8 *compbuf, u64 compbufsize, int level); int uncompress_block_lzo(u64 compsize, u64 *origsize, u8 *origbuf, u64 origbufsize, u8 *compbuf); #endif // OPTION_LZO_SUPPORT #endif // __COMPRESS_LZO_H__ fsarchiver-0.8.5/src/options.h0000644000176100017610000000260613242523705013247 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __OPTIONS_H__ #define __OPTIONS_H__ #include "strlist.h" struct s_options; typedef struct s_options coptions; // struct that stores the options passed on the command line struct s_options { bool overwrite; bool allowsaverw; bool experimental; bool dontcheckmountopts; int verboselevel; int debuglevel; int compresslevel; int compressjobs; u16 compressalgo; u32 datablocksize; u32 smallfilethresh; u64 splitsize; u16 encryptalgo; u16 fsacomplevel; char archlabel[FSA_MAX_LABELLEN]; u8 encryptpass[FSA_MAX_PASSLEN+1]; cstrlist exclude; }; extern coptions g_options; int options_init(); int options_destroy(); int options_select_compress_level(int opt); #endif // __OPTIONS_H__ fsarchiver-0.8.5/src/comp_zstd.h0000644000176100017610000000170013242523705013550 00000000000000 /* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __COMPRESS_ZSTD_H__ #define __COMPRESS_ZSTD_H__ #ifdef OPTION_ZSTD_SUPPORT #include int compress_block_zstd(u64 origsize, u64 *compsize, u8 *origbuf, u8 *compbuf, u64 compbufsize, int level); int uncompress_block_zstd(u64 compsize, u64 *origsize, u8 *origbuf, u64 origbufsize, u8 *compbuf); #endif // OPTION_ZSTD_SUPPORT #endif // __COMPRESS_ZSTD_H__ fsarchiver-0.8.5/src/fs_vfat.h0000644000176100017610000000322013242523705013175 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifndef __FS_VFAT_H__ #define __FS_VFAT_H__ struct s_dico; struct s_strlist; int vfat_mkfs(struct s_dico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid); int vfat_getinfo(struct s_dico *d, char *devname); int vfat_mount(char *partition, char *mntbuf, char *fsbuf, int flags, char *mntinfo); int vfat_get_reqmntopt(char *partition, struct s_strlist *reqopt, struct s_strlist *badopt); int vfat_umount(char *partition, char *mntbuf); int vfat_test(char *devname); int vfat_check_compatibility(u64 compat, u64 ro_compat, u64 incompat, u64 log_incompat); #define VFAT_SB_MAGIC 0x55AA enum fat_type {FAT_TYPE_FAT32=0, FAT_TYPE_FAT16}; struct vfat_superblock { u8 jump[3]; u8 oem_id[8]; u16 u8s_per_sector; u8 sectors_per_cluster; u16 num_boot_sectors; u8 num_fats; u16 num_root_dir_ents; u16 total_sectors; u8 media_id; u16 sectors_per_fat; u16 sectors_per_track; u16 heads; u32 hidden_sectors; u32 total_sectors_large; u8 boot_code[474]; u16 magic; } __attribute__((packed)); #endif // __FS_VFAT_H__ fsarchiver-0.8.5/src/fsarchiver.c0000644000176100017610000005203213242523705013701 00000000000000/* * fsarchiver: Filesystem Archiver * * Copyright (C) 2008-2018 Francois Dupoux. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. * * Homepage: http://www.fsarchiver.org */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include "fsarchiver.h" #include "dico.h" #include "common.h" #include "oper_restore.h" #include "oper_save.h" #include "oper_probe.h" #include "archinfo.h" #include "syncthread.h" #include "comp_lzo.h" #include "comp_lz4.h" #include "crypto.h" #include "options.h" #include "logfile.h" #include "error.h" #include "queue.h" char *valid_magic[]={FSA_MAGIC_MAIN, FSA_MAGIC_VOLH, FSA_MAGIC_VOLF, FSA_MAGIC_FSIN, FSA_MAGIC_FSYB, FSA_MAGIC_DATF, FSA_MAGIC_OBJT, FSA_MAGIC_BLKH, FSA_MAGIC_FILF, FSA_MAGIC_DIRS, NULL}; void usage(char *progname, bool examples) { int lzo, lzma, lz4, zstd; #ifdef OPTION_LZO_SUPPORT lzo=true; #else lzo=false; #endif // OPTION_LZO_SUPPORT #ifdef OPTION_LZMA_SUPPORT lzma=true; #else lzma=false; #endif // OPTION_LZMA_SUPPORT #ifdef OPTION_LZ4_SUPPORT lz4=true; #else lz4=false; #endif // OPTION_lZ4_SUPPORT #ifdef OPTION_ZSTD_SUPPORT zstd=true; #else zstd=false; #endif // OPTION_ZSTD_SUPPORT msgprintf(MSG_FORCE, "====> fsarchiver version %s (%s) - http://www.fsarchiver.org <====\n", FSA_VERSION, FSA_RELDATE); msgprintf(MSG_FORCE, "Distributed under the GPL v2 license (GNU General Public License v2).\n"); msgprintf(MSG_FORCE, " * usage: %s [] [ [ [...]]]\n", progname); msgprintf(MSG_FORCE, "\n"); msgprintf(MSG_FORCE, " * savefs: save filesystems to an archive file (backup a device to a file)\n"); msgprintf(MSG_FORCE, " * restfs: restore filesystems from an archive (overwrites the existing data)\n"); msgprintf(MSG_FORCE, " * savedir: save directories to the archive (similar to a compressed tarball)\n"); msgprintf(MSG_FORCE, " * restdir: restore data from an archive which is not based on a filesystem\n"); msgprintf(MSG_FORCE, " * archinfo: show information about an existing archive file and its contents\n"); msgprintf(MSG_FORCE, " * probe [detailed]: show list of filesystems detected on the disks\n"); msgprintf(MSG_FORCE, "\n"); msgprintf(MSG_FORCE, " -o: overwrite the archive if it already exists instead of failing\n"); msgprintf(MSG_FORCE, " -v: verbose mode (can be used several times to increase the level of details)\n"); msgprintf(MSG_FORCE, " -d: debug mode (can be used several times to increase the level of details)\n"); msgprintf(MSG_FORCE, " -A: allow to save a filesystem which is mounted in read-write (live backup)\n"); msgprintf(MSG_FORCE, " -a: allow to save a filesystem when acls and xattrs are not supported\n"); msgprintf(MSG_FORCE, " -x: enable support for experimental features (they are disabled by default)\n"); msgprintf(MSG_FORCE, " -e : exclude files and directories that match that pattern\n"); msgprintf(MSG_FORCE, " -L