Merge branch 'master' into errno

This commit is contained in:
Ben RUBSON 2017-08-07 09:53:56 +02:00 committed by GitHub
commit 21d1d3dcfa
511 changed files with 117495 additions and 14915 deletions

View File

@ -1,9 +1,12 @@
dist: trusty
language: cpp language: cpp
sudo: false sudo: true
compiler: compiler:
- clang - clang
- gcc
branches: branches:
only: only:
@ -18,12 +21,11 @@ env:
- secure: "KuAAwjiIqkk4vqSX/M3ZZIvQs6edm+tV8IADiklTUYZIFyxu8FgZ6RbDdMD2sef5bNZA1OZhlcbeRtiKff5CfMtvzc607Lg3NUkpi+ShMynWgqS/e0uCMf9ogEJlUiZMxf4juBi7v6DyMl/WV6pAdJmdfHtzcj8GF2mgTfQjkO8=" - secure: "KuAAwjiIqkk4vqSX/M3ZZIvQs6edm+tV8IADiklTUYZIFyxu8FgZ6RbDdMD2sef5bNZA1OZhlcbeRtiKff5CfMtvzc607Lg3NUkpi+ShMynWgqS/e0uCMf9ogEJlUiZMxf4juBi7v6DyMl/WV6pAdJmdfHtzcj8GF2mgTfQjkO8="
before_script: before_script:
- mkdir build - sudo modprobe fuse
- cd build - cmake --version
- cmake ..
script: script:
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make && ./checkops ; fi - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./build.sh && ./test.sh ; fi
addons: addons:
coverity_scan: coverity_scan:
@ -39,7 +41,9 @@ addons:
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
packages: packages:
- attr
- clang - clang
- cmake - fuse
- libfuse-dev - libfuse-dev
- gettext
- cmake3

View File

@ -1,15 +1,19 @@
# 3.1 preferred, but we can often get by with 2.8. # 3.0.2 preferred, but we can often get by with 2.8.
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} LESS 3.0.2)
message(WARNING "You should use cmake 3.0.2 or newer for configuration to run correctly.")
endif()
project(EncFS C CXX) project(EncFS C CXX)
set (ENCFS_MAJOR 1) set (ENCFS_MAJOR 1)
set (ENCFS_MINOR 9) set (ENCFS_MINOR 9)
set (ENCFS_PATCH 1) set (ENCFS_PATCH 2)
set (ENCFS_VERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}.${ENCFS_PATCH}") set (ENCFS_VERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}.${ENCFS_PATCH}")
set (ENCFS_SOVERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}") set (ENCFS_SOVERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}")
set (ENCFS_NAME "Encrypted Filesystem") set (ENCFS_NAME "Encrypted Filesystem")
option(IWYU "Build with IWYU analyais." OFF) option(IWYU "Build with IWYU analysis." OFF)
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_LIST_DIR}/cmake") "${CMAKE_CURRENT_LIST_DIR}/cmake")
@ -18,6 +22,7 @@ option (BUILD_SHARED_LIBS "build shared libraries" OFF)
option (USE_INTERNAL_TINYXML "use built-in TinyXML2" ON) option (USE_INTERNAL_TINYXML "use built-in TinyXML2" ON)
option (ENABLE_NLS "compile with Native Language Support (using gettext)" ON) option (ENABLE_NLS "compile with Native Language Support (using gettext)" ON)
option (INSTALL_LIBENCFS "install libencfs" OFF) option (INSTALL_LIBENCFS "install libencfs" OFF)
option (LINT "enable lint output" OFF)
if (NOT DEFINED LIB_INSTALL_DIR) if (NOT DEFINED LIB_INSTALL_DIR)
set (LIB_INSTALL_DIR lib) set (LIB_INSTALL_DIR lib)
@ -31,10 +36,10 @@ if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.0)
else () else ()
if (CMAKE_COMPILER_IS_GNUCXX) if (CMAKE_COMPILER_IS_GNUCXX)
message ("** Assuming that GNU CXX uses -std=c++11 flag for C++11 compatibility.") message ("** Assuming that GNU CXX uses -std=c++11 flag for C++11 compatibility.")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") list(APPEND CMAKE_CXX_FLAGS "-std=c++11")
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
message ("** Assuming that Clang uses -std=c++11 flag for C++11 compatibility.") message ("** Assuming that Clang uses -std=c++11 flag for C++11 compatibility.")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") list(APPEND CMAKE_CXX_FLAGS "-std=c++11")
else() else()
message ("** No CMAKE C++11 check. If the build breaks, you're on your own.") message ("** No CMAKE C++11 check. If the build breaks, you're on your own.")
endif() endif()
@ -55,6 +60,12 @@ if (APPLE)
endif() endif()
endif() endif()
if (WIN32 OR APPLE)
set(DEFAULT_CASE_INSENSITIVE TRUE)
else()
set(DEFAULT_CASE_INSENSITIVE FALSE)
endif()
# Check for FUSE. # Check for FUSE.
find_package (FUSE REQUIRED) find_package (FUSE REQUIRED)
include_directories (${FUSE_INCLUDE_DIR}) include_directories (${FUSE_INCLUDE_DIR})
@ -64,17 +75,6 @@ add_definitions (-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26)
find_package (OpenSSL REQUIRED) find_package (OpenSSL REQUIRED)
include_directories (${OPENSSL_INCLUDE_DIR}) include_directories (${OPENSSL_INCLUDE_DIR})
if (USE_INTERNAL_TINYXML)
message("-- Using local TinyXML2 copy")
add_subdirectory(internal/tinyxml2-3.0.0)
include_directories(${CMAKE_CURRENT_LIST_DIR}/internal/tinyxml2-3.0.0)
link_directories(${CMAKE_BINARY_DIR}/internal/tinyxml2-3.0.0)
set(TINYXML_LIBRARIES tinyxml2)
else ()
find_package (TinyXML REQUIRED)
include_directories (${TINYXML_INCLUDE_DIR})
endif ()
find_program (POD2MAN pod2man) find_program (POD2MAN pod2man)
# Check for include files and stdlib properties. # Check for include files and stdlib properties.
@ -82,21 +82,21 @@ include (CheckIncludeFileCXX)
check_include_file_cxx (attr/xattr.h HAVE_ATTR_XATTR_H) check_include_file_cxx (attr/xattr.h HAVE_ATTR_XATTR_H)
check_include_file_cxx (sys/xattr.h HAVE_SYS_XATTR_H) check_include_file_cxx (sys/xattr.h HAVE_SYS_XATTR_H)
include(CheckStructHasMember)
check_struct_has_member(dirent d_type dirent.h HAVE_DIRENT_D_TYPE LANGUAGE CXX)
# Check if xattr functions take extra arguments, as they do on OSX. # Check if xattr functions take extra arguments, as they do on OSX.
# Output error is misleading, so do this test quietly.
include (CheckCXXSourceCompiles) include (CheckCXXSourceCompiles)
set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
set (CMAKE_REQUIRED_QUIET True)
check_cxx_source_compiles ("#include <sys/types.h> check_cxx_source_compiles ("#include <sys/types.h>
#include <sys/xattr.h> #include <sys/xattr.h>
int main() { getxattr(0,0,0,0,0,0); return 1; } int main() { getxattr(0,0,0,0,0,0); return 1; }
" XATTR_ADD_OPT) " XATTR_ADD_OPT)
set (CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
# Check if we have some standard functions. # Check if we have some standard functions.
include (CheckFuncs) include (CheckFuncs)
check_function_exists_glibc (lchmod HAVE_LCHMOD) check_function_exists_glibc (lchmod HAVE_LCHMOD)
check_function_exists_glibc (utimensat HAVE_UTIMENSAT) check_function_exists_glibc (utimensat HAVE_UTIMENSAT)
check_function_exists_glibc (fdatasync HAVE_FDATASYNC)
set (CMAKE_THREAD_PREFER_PTHREAD) set (CMAKE_THREAD_PREFER_PTHREAD)
find_package (Threads REQUIRED) find_package (Threads REQUIRED)
@ -139,6 +139,40 @@ if (ENABLE_NLS)
add_definitions(-DLOCALEDIR="${CMAKE_INSTALL_PREFIX}/share/locale") add_definitions(-DLOCALEDIR="${CMAKE_INSTALL_PREFIX}/share/locale")
endif (ENABLE_NLS) endif (ENABLE_NLS)
if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.5) # Need 3.6 or above.
find_program(CLANG_TIDY_EXE NAMES "clang-tidy" DOC "Path to clang-tidy executable")
if(NOT CLANG_TIDY_EXE)
message(STATUS "clang-tidy not found.")
else()
message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}")
set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" "-checks=*,-modernize-loop-convert,-cppcoreguidelines-pro-*,-readability-inconsistent-declaration-parameter-name,-google-readability-casting,-cert-err58-cpp,-google-runtime-int,-readability-named-parameter,-google-build-using-namespace,-misc-unused-parameters,-google-runtime-references")
#set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" "-fix" "-checks=-*,google-readability-redundant-smartptr-get")
endif()
endif()
if (USE_INTERNAL_TINYXML)
message("-- Using vendored TinyXML2")
set(TINYXML_DIR vendor/github.com/leethomason/tinyxml2)
set(BUILD_STATIC_LIBS ON CACHE BOOL "build static libs")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "build shared libs")
set(BUILD_TESTS OFF CACHE BOOL "build tests")
add_subdirectory(${TINYXML_DIR})
include_directories(${CMAKE_CURRENT_LIST_DIR}/${TINYXML_DIR})
link_directories(${CMAKE_BINARY_DIR}/${TINYXML_DIR})
set(TINYXML_LIBRARIES tinyxml2_static)
else ()
find_package (TinyXML REQUIRED)
include_directories (${TINYXML_INCLUDE_DIR})
endif ()
message("-- Using vendored easylogging++")
set(EASYLOGGING_DIR vendor/github.com/muflihun/easyloggingpp)
set(build_static_lib ON CACHE BOOL "build static libs")
add_subdirectory(${EASYLOGGING_DIR})
include_directories(${CMAKE_CURRENT_LIST_DIR}/${EASYLOGGING_DIR}/src)
link_directories(${CMAKE_BINARY_DIR}/${EASYLOGGING_DIR})
set(EASYLOGGING_LIBRARIES easyloggingpp)
set(SOURCE_FILES set(SOURCE_FILES
encfs/autosprintf.cpp encfs/autosprintf.cpp
encfs/base64.cpp encfs/base64.cpp
@ -177,6 +211,7 @@ target_link_libraries(encfs
${FUSE_LIBRARIES} ${FUSE_LIBRARIES}
${OPENSSL_LIBRARIES} ${OPENSSL_LIBRARIES}
${TINYXML_LIBRARIES} ${TINYXML_LIBRARIES}
${EASYLOGGING_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
${Intl_LIBRARIES} ${Intl_LIBRARIES}
) )
@ -203,6 +238,11 @@ target_link_libraries (encfs-bin encfs)
set_target_properties (encfs-bin PROPERTIES OUTPUT_NAME "encfs") set_target_properties (encfs-bin PROPERTIES OUTPUT_NAME "encfs")
install (TARGETS encfs-bin DESTINATION bin) install (TARGETS encfs-bin DESTINATION bin)
if(LINT AND CLANG_TIDY_EXE)
set_target_properties(encfs PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
set_target_properties(encfs-bin PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
endif()
add_executable (encfsctl encfs/encfsctl.cpp) add_executable (encfsctl encfs/encfsctl.cpp)
target_link_libraries (encfsctl encfs) target_link_libraries (encfsctl encfs)
install (TARGETS encfsctl DESTINATION bin) install (TARGETS encfsctl DESTINATION bin)
@ -213,13 +253,18 @@ target_link_libraries (makekey encfs)
add_executable (checkops encfs/test.cpp) add_executable (checkops encfs/test.cpp)
target_link_libraries (checkops encfs) target_link_libraries (checkops encfs)
install (FILES encfs/encfssh DESTINATION bin) install (PROGRAMS encfs/encfssh DESTINATION bin)
# Reference all headers, to make certain IDEs happy. # Reference all headers, to make certain IDEs happy.
file (GLOB_RECURSE all_headers ${CMAKE_CURRENT_LIST_DIR}/*.h) file (GLOB_RECURSE all_headers ${CMAKE_CURRENT_LIST_DIR}/*.h)
add_custom_target (all_placeholder SOURCES ${all_headers}) add_custom_target (all_placeholder SOURCES ${all_headers})
if (POD2MAN) if (POD2MAN)
set (MAN_DESTINATION "share/man/man1")
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
set (MAN_DESTINATION "man/man1")
endif()
add_custom_target (encfs-man ALL add_custom_target (encfs-man ALL
COMMAND ${POD2MAN} -u --section=1 --release=${ENCFS_VERSION} --center=${ENCFS_NAME} COMMAND ${POD2MAN} -u --section=1 --release=${ENCFS_VERSION} --center=${ENCFS_NAME}
${CMAKE_CURRENT_LIST_DIR}/encfs/encfs.pod encfs.1) ${CMAKE_CURRENT_LIST_DIR}/encfs/encfs.pod encfs.1)
@ -229,20 +274,8 @@ if (POD2MAN)
${CMAKE_CURRENT_LIST_DIR}/encfs/encfsctl.pod encfsctl.1) ${CMAKE_CURRENT_LIST_DIR}/encfs/encfsctl.pod encfsctl.1)
install (FILES ${CMAKE_BINARY_DIR}/encfs.1 ${CMAKE_BINARY_DIR}/encfsctl.1 install (FILES ${CMAKE_BINARY_DIR}/encfs.1 ${CMAKE_BINARY_DIR}/encfsctl.1
DESTINATION share/man/man1) DESTINATION ${MAN_DESTINATION})
endif (POD2MAN) endif (POD2MAN)
# Tests add_custom_target(tests COMMAND ${CMAKE_CURRENT_LIST_DIR}/test.sh)
enable_testing()
add_test (NAME checkops
COMMAND checkops)
find_program (PERL_PROGRAM perl)
if (PERL_PROGRAM)
file(GLOB pl_test_files "tests/*.t.pl")
#add_test (NAME scriptedtests
# COMMAND ${PERL_PROGRAM} -I ${CMAKE_CURRENT_LIST_DIR}
# -MTest::Harness
# -e "$$Test::Harness::verbose=1; runtests @ARGV;"
# ${pl_test_files})
endif (PERL_PROGRAM)

View File

@ -1,6 +1,15 @@
v1.9.2 / 2017-07-25
===================
* fix a use-after-free bug that was introduced in v1.9-rc1 (#214)
* cast booleans to int before writing the XML config (#343)
* support reading the config file from pipes (#253)
* add "-t" option to set syslog tag
* allow read/write in standard reverse mode (#301)
* reject empty passwords
* support building with openssl 1.1
v1.9.1 / 2016-09-18 v1.9.1 / 2016-09-18
================== ===================
* add filehandle null check * add filehandle null check
* bump version to 1.9.1 * bump version to 1.9.1
* prevent crash in elpp when verbose logging is enabled * prevent crash in elpp when verbose logging is enabled

View File

@ -46,7 +46,7 @@ EncFS depends on a number of libraries:
* tinyxml2 : for reading and writing XML configuration files * tinyxml2 : for reading and writing XML configuration files
* gettext : internationalization support * gettext : internationalization support
* libintl : internationalization support * libintl : internationalization support
* cmake : version 3.2 or newer * cmake : version 3.0.2 (Debian jessie version) or newer
* GNU make or ninja-build : to run the build for cmake * GNU make or ninja-build : to run the build for cmake
Compiling on Debian and Ubuntu Compiling on Debian and Ubuntu

View File

@ -1,15 +1,15 @@
#!/bin/bash #!/bin/bash -eu
set -eu # Make sure we are in the directory this script is in.
cd "$(dirname "$0")"
if [ ! -d build ] if [[ ! -d build ]]
then then
mkdir build mkdir build
cd build cd build
cmake .. cmake ..
else cd ..
cd build
fi fi
make make -j2 -C build

View File

@ -2,4 +2,4 @@ set -x
set -e set -e
mkdir build mkdir build
cd build cd build
cmake -DCMAKE_INSTALL_PREFIX:PATH=/tmp/encfs -DCMAKE_BUILD_TYPE=Debug -DMINIGLOG=ON .. cmake -DCMAKE_INSTALL_PREFIX:PATH=/tmp/encfs -DCMAKE_BUILD_TYPE=Debug ..

View File

@ -1,7 +0,0 @@
set -x
set -e
if [ ! -e ci/cmake/bin/cmake ]; then
wget http://www.cmake.org/files/v3.1/cmake-3.1.3-Linux-x86_64.tar.gz
tar -xzf cmake-3.1.3-Linux-x86_64.tar.gz
mv cmake-3.1.3-Linux-x86_64 ci/cmake
fi

View File

@ -10,5 +10,5 @@ dependencies:
test: test:
override: override:
- bash ./ci/config.sh - bash ./ci/config.sh
- cd build && make && make test && make install - cd build && make && ./checkops && make install
- /tmp/encfs/bin/encfsctl --version - /tmp/encfs/bin/encfsctl --version

View File

@ -13,8 +13,8 @@ if (APPLE)
set (FUSE_NAMES libosxfuse.dylib fuse) set (FUSE_NAMES libosxfuse.dylib fuse)
set (FUSE_SUFFIXES osxfuse fuse) set (FUSE_SUFFIXES osxfuse fuse)
else (APPLE) else (APPLE)
set (FUSE_NAMES fuse) set (FUSE_NAMES fuse refuse)
set (FUSE_SUFFIXES fuse) set (FUSE_SUFFIXES fuse refuse)
endif (APPLE) endif (APPLE)
# find includes # find includes

59
cmake/FindIntl.cmake Normal file
View File

@ -0,0 +1,59 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#.rst:
# FindIntl
# --------
#
# Find the Gettext libintl headers and libraries.
#
# This module reports information about the Gettext libintl
# installation in several variables. General variables::
#
# Intl_FOUND - true if the libintl headers and libraries were found
# Intl_INCLUDE_DIRS - the directory containing the libintl headers
# Intl_LIBRARIES - libintl libraries to be linked
#
# The following cache variables may also be set::
#
# Intl_INCLUDE_DIR - the directory containing the libintl headers
# Intl_LIBRARY - the libintl library (if any)
#
# .. note::
# On some platforms, such as Linux with GNU libc, the gettext
# functions are present in the C standard library and libintl
# is not required. ``Intl_LIBRARIES`` will be empty in this
# case.
#
# .. note::
# If you wish to use the Gettext tools (``msgmerge``,
# ``msgfmt``, etc.), use :module:`FindGettext`.
# Written by Roger Leigh <rleigh@codelibre.net>
# Find include directory
find_path(Intl_INCLUDE_DIR
NAMES "libintl.h"
DOC "libintl include directory")
mark_as_advanced(Intl_INCLUDE_DIR)
# Find all Intl libraries
find_library(Intl_LIBRARY "intl"
DOC "libintl libraries (if not in the C library)")
mark_as_advanced(Intl_LIBRARY)
#include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Intl
FOUND_VAR Intl_FOUND
REQUIRED_VARS Intl_INCLUDE_DIR
FAIL_MESSAGE "Failed to find Gettext libintl")
if(Intl_FOUND)
set(Intl_INCLUDE_DIRS "${Intl_INCLUDE_DIR}")
if(Intl_LIBRARY)
set(Intl_LIBRARIES "${Intl_LIBRARY}")
else()
unset(Intl_LIBRARIES)
endif()
endif()

View File

@ -3,8 +3,14 @@
#cmakedefine HAVE_ATTR_XATTR_H #cmakedefine HAVE_ATTR_XATTR_H
#cmakedefine HAVE_SYS_XATTR_H #cmakedefine HAVE_SYS_XATTR_H
#cmakedefine XATTR_ADD_OPT #cmakedefine XATTR_ADD_OPT
#cmakedefine XATTR_LLIST
#cmakedefine HAVE_LCHMOD #cmakedefine HAVE_LCHMOD
#cmakedefine HAVE_FDATASYNC
#cmakedefine HAVE_DIRENT_D_TYPE
#cmakedefine DEFAULT_CASE_INSENSITIVE
/* TODO: add other thread library support. */ /* TODO: add other thread library support. */
#cmakedefine CMAKE_USE_PTHREADS_INIT #cmakedefine CMAKE_USE_PTHREADS_INIT

View File

@ -1,5 +1,5 @@
# Script which sets up the CMake build for Debug mode. # Script which sets up the CMake build for Debug mode.
# After running, chdir to the build subdir ane run "make" # After running, chdir to the build subdir ane run "make"
mkdir build mkdir build
cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug \ cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug -DLINT=ON \
-DCMAKE_CXX_FLAGS="-O1 -fsanitize=address -fno-omit-frame-pointer" $@ -DCMAKE_CXX_FLAGS="-O1 -fsanitize=address -fno-omit-frame-pointer" $@

View File

@ -67,31 +67,34 @@ ssize_t BlockFileIO::cacheReadOneBlock(const IORequest &req) const {
* in the last block of a file, which may be smaller than the blocksize. * in the last block of a file, which may be smaller than the blocksize.
* For reverse encryption, the cache must not be used at all, because * For reverse encryption, the cache must not be used at all, because
* the lower file may have changed behind our back. */ * the lower file may have changed behind our back. */
if ((_noCache == false) && (req.offset == _cache.offset) && if ((!_noCache) && (req.offset == _cache.offset) && (_cache.dataLen != 0)) {
(_cache.dataLen != 0)) {
// satisfy request from cache // satisfy request from cache
int len = req.dataLen; int len = req.dataLen;
if (_cache.dataLen < len) len = _cache.dataLen; // Don't read past EOF if (_cache.dataLen < len) {
len = _cache.dataLen; // Don't read past EOF
}
memcpy(req.data, _cache.data, len); memcpy(req.data, _cache.data, len);
return len; return len;
} else {
if (_cache.dataLen > 0) clearCache(_cache, _blockSize);
// cache results of read -- issue reads for full blocks
IORequest tmp;
tmp.offset = req.offset;
tmp.data = _cache.data;
tmp.dataLen = _blockSize;
ssize_t result = readOneBlock(tmp);
if (result > 0) {
_cache.offset = req.offset;
_cache.dataLen = result; // the amount we really have
if (result > req.dataLen)
result = req.dataLen; // only as much as requested
memcpy(req.data, _cache.data, result);
}
return result;
} }
if (_cache.dataLen > 0) {
clearCache(_cache, _blockSize);
}
// cache results of read -- issue reads for full blocks
IORequest tmp;
tmp.offset = req.offset;
tmp.data = _cache.data;
tmp.dataLen = _blockSize;
ssize_t result = readOneBlock(tmp);
if (result > 0) {
_cache.offset = req.offset;
_cache.dataLen = result; // the amount we really have
if (result > req.dataLen) {
result = req.dataLen; // only as much as requested
}
memcpy(req.data, _cache.data, result);
}
return result;
} }
int BlockFileIO::cacheWriteOneBlock(const IORequest &req) { int BlockFileIO::cacheWriteOneBlock(const IORequest &req) {
@ -101,7 +104,9 @@ int BlockFileIO::cacheWriteOneBlock(const IORequest &req) {
_cache.offset = req.offset; _cache.offset = req.offset;
_cache.dataLen = req.dataLen; _cache.dataLen = req.dataLen;
int res = writeOneBlock(req); int res = writeOneBlock(req);
if (res < 0) clearCache(_cache, _blockSize); if (res < 0) {
clearCache(_cache, _blockSize);
}
return res; return res;
} }
@ -124,53 +129,59 @@ ssize_t BlockFileIO::read(const IORequest &req) const {
// read completely within a single block -- can be handled as-is by // read completely within a single block -- can be handled as-is by
// readOneBlock(). // readOneBlock().
return cacheReadOneBlock(req); return cacheReadOneBlock(req);
} else { }
size_t size = req.dataLen; size_t size = req.dataLen;
// if the request is larger then a block, then request each block // if the request is larger then a block, then request each block
// individually // individually
MemBlock mb; // in case we need to allocate a temporary block.. MemBlock mb; // in case we need to allocate a temporary block..
IORequest blockReq; // for requests we may need to make IORequest blockReq; // for requests we may need to make
blockReq.dataLen = _blockSize; blockReq.dataLen = _blockSize;
blockReq.data = NULL; blockReq.data = nullptr;
unsigned char *out = req.data; unsigned char *out = req.data;
while (size) { while (size != 0u) {
blockReq.offset = blockNum * _blockSize; blockReq.offset = blockNum * _blockSize;
// if we're reading a full block, then read directly into the // if we're reading a full block, then read directly into the
// result buffer instead of using a temporary // result buffer instead of using a temporary
if (partialOffset == 0 && size >= (size_t)_blockSize) if (partialOffset == 0 && size >= (size_t)_blockSize) {
blockReq.data = out; blockReq.data = out;
else { } else {
if (!mb.data) mb = MemoryPool::allocate(_blockSize); if (mb.data == nullptr) {
blockReq.data = mb.data; mb = MemoryPool::allocate(_blockSize);
} }
blockReq.data = mb.data;
ssize_t readSize = cacheReadOneBlock(blockReq);
if (readSize < 0) {
result = readSize;
break;
}
if (readSize <= partialOffset) break; // didn't get enough bytes
int cpySize = min((size_t)(readSize - partialOffset), size);
CHECK(cpySize <= readSize);
// if we read to a temporary buffer, then move the data
if (blockReq.data != out)
memcpy(out, blockReq.data + partialOffset, cpySize);
result += cpySize;
size -= cpySize;
out += cpySize;
++blockNum;
partialOffset = 0;
if (readSize < _blockSize) break;
} }
if (mb.data) MemoryPool::release(mb); ssize_t readSize = cacheReadOneBlock(blockReq);
if (readSize < 0) {
result = readSize;
break;
}
if (readSize <= partialOffset) break; // didn't get enough bytes
int cpySize = min((size_t)(readSize - partialOffset), size);
CHECK(cpySize <= readSize);
// if we read to a temporary buffer, then move the data
if (blockReq.data != out) {
memcpy(out, blockReq.data + partialOffset, cpySize);
}
result += cpySize;
size -= cpySize;
out += cpySize;
++blockNum;
partialOffset = 0;
if (readSize < _blockSize) {
break;
}
}
if (mb.data != nullptr) {
MemoryPool::release(mb);
} }
return result; return result;
@ -184,7 +195,9 @@ int BlockFileIO::write(const IORequest &req) {
CHECK(_blockSize != 0); CHECK(_blockSize != 0);
off_t fileSize = getSize(); off_t fileSize = getSize();
if (fileSize < 0) return fileSize; if (fileSize < 0) {
return fileSize;
}
// where write request begins // where write request begins
off_t blockNum = req.offset / _blockSize; off_t blockNum = req.offset / _blockSize;
@ -195,39 +208,45 @@ int BlockFileIO::write(const IORequest &req) {
ssize_t lastBlockSize = fileSize % _blockSize; ssize_t lastBlockSize = fileSize % _blockSize;
off_t lastNonEmptyBlock = lastFileBlock; off_t lastNonEmptyBlock = lastFileBlock;
if (lastBlockSize == 0) --lastNonEmptyBlock; if (lastBlockSize == 0) {
--lastNonEmptyBlock;
}
if (req.offset > fileSize) { if (req.offset > fileSize) {
// extend file first to fill hole with 0's.. // extend file first to fill hole with 0's..
const bool forceWrite = false; const bool forceWrite = false;
int res = padFile(fileSize, req.offset, forceWrite); int res = padFile(fileSize, req.offset, forceWrite);
if (res < 0) if (res < 0) {
return res; return res;
}
} }
// check against edge cases where we can just let the base class handle the // check against edge cases where we can just let the base class handle the
// request as-is.. // request as-is..
if (partialOffset == 0 && req.dataLen <= _blockSize) { if (partialOffset == 0 && req.dataLen <= _blockSize) {
// if writing a full block.. pretty safe.. // if writing a full block.. pretty safe..
if (req.dataLen == _blockSize) return cacheWriteOneBlock(req); if (req.dataLen == _blockSize) {
return cacheWriteOneBlock(req);
}
// if writing a partial block, but at least as much as what is // if writing a partial block, but at least as much as what is
// already there.. // already there..
if (blockNum == lastFileBlock && req.dataLen >= lastBlockSize) if (blockNum == lastFileBlock && req.dataLen >= lastBlockSize) {
return cacheWriteOneBlock(req); return cacheWriteOneBlock(req);
}
} }
// have to merge data with existing block(s).. // have to merge data with existing block(s)..
MemBlock mb; MemBlock mb;
IORequest blockReq; IORequest blockReq;
blockReq.data = NULL; blockReq.data = nullptr;
blockReq.dataLen = _blockSize; blockReq.dataLen = _blockSize;
int res = 0; int res = 0;
size_t size = req.dataLen; size_t size = req.dataLen;
unsigned char *inPtr = req.data; unsigned char *inPtr = req.data;
while (size) { while (size != 0u) {
blockReq.offset = blockNum * _blockSize; blockReq.offset = blockNum * _blockSize;
int toCopy = min((size_t)(_blockSize - partialOffset), size); int toCopy = min((size_t)(_blockSize - partialOffset), size);
@ -241,7 +260,9 @@ int BlockFileIO::write(const IORequest &req) {
} else { } else {
// need a temporary buffer, since we have to either merge or pad // need a temporary buffer, since we have to either merge or pad
// the data. // the data.
if (!mb.data) mb = MemoryPool::allocate(_blockSize); if (mb.data == nullptr) {
mb = MemoryPool::allocate(_blockSize);
}
memset(mb.data, 0, _blockSize); memset(mb.data, 0, _blockSize);
blockReq.data = mb.data; blockReq.data = mb.data;
@ -257,8 +278,9 @@ int BlockFileIO::write(const IORequest &req) {
} }
// extend data if necessary.. // extend data if necessary..
if (partialOffset + toCopy > blockReq.dataLen) if (partialOffset + toCopy > blockReq.dataLen) {
blockReq.dataLen = partialOffset + toCopy; blockReq.dataLen = partialOffset + toCopy;
}
} }
// merge in the data to be written.. // merge in the data to be written..
memcpy(blockReq.data + partialOffset, inPtr, toCopy); memcpy(blockReq.data + partialOffset, inPtr, toCopy);
@ -277,7 +299,9 @@ int BlockFileIO::write(const IORequest &req) {
partialOffset = 0; partialOffset = 0;
} }
if (mb.data) MemoryPool::release(mb); if (mb.data != nullptr) {
MemoryPool::release(mb);
}
return res; return res;
} }
@ -309,7 +333,7 @@ int BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) {
req.dataLen = oldSize % _blockSize; req.dataLen = oldSize % _blockSize;
int outSize = newSize % _blockSize; // outSize > req.dataLen int outSize = newSize % _blockSize; // outSize > req.dataLen
if (outSize) { if (outSize != 0) {
memset(mb.data, 0, outSize); memset(mb.data, 0, outSize);
if ((res = cacheReadOneBlock(req)) >= 0) { if ((res = cacheReadOneBlock(req)) >= 0) {
req.dataLen = outSize; req.dataLen = outSize;
@ -360,7 +384,9 @@ int BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) {
} }
} }
if (mb.data) MemoryPool::release(mb); if (mb.data != nullptr) {
MemoryPool::release(mb);
}
return res; return res;
} }
@ -376,14 +402,17 @@ int BlockFileIO::truncateBase(off_t size, FileIO *base) {
// states that it will pad with 0's. // states that it will pad with 0's.
// do the truncate so that the underlying filesystem can allocate // do the truncate so that the underlying filesystem can allocate
// the space, and then we'll fill it in padFile.. // the space, and then we'll fill it in padFile..
if (base) res = base->truncate(size); if (base != nullptr) {
res = base->truncate(size);
}
const bool forceWrite = true; const bool forceWrite = true;
if (!(res < 0)) if (!(res < 0)) {
res = padFile(oldSize, size, forceWrite); res = padFile(oldSize, size, forceWrite);
}
} else if (size == oldSize) { } else if (size == oldSize) {
// the easiest case, but least likely.... // the easiest case, but least likely....
} else if (partialBlock) { } else if (partialBlock != 0) {
// partial block after truncate. Need to read in the block being // partial block after truncate. Need to read in the block being
// truncated before the truncate. Then write it back out afterwards, // truncated before the truncate. Then write it back out afterwards,
// since the encoding will change.. // since the encoding will change..
@ -396,23 +425,28 @@ int BlockFileIO::truncateBase(off_t size, FileIO *base) {
req.data = mb.data; req.data = mb.data;
ssize_t rdSz = cacheReadOneBlock(req); ssize_t rdSz = cacheReadOneBlock(req);
if (rdSz < 0) if (rdSz < 0) {
res = rdSz; res = rdSz;
}
// do the truncate // do the truncate
else if (base) else if (base != nullptr) {
res = base->truncate(size); res = base->truncate(size);
}
// write back out partial block // write back out partial block
req.dataLen = partialBlock; req.dataLen = partialBlock;
if (!res) if (!(res < 0)) {
res = cacheWriteOneBlock(req); res = cacheWriteOneBlock(req);
}
MemoryPool::release(mb); MemoryPool::release(mb);
} else { } else {
// truncating on a block bounday. No need to re-encode the last // truncating on a block bounday. No need to re-encode the last
// block.. // block..
if (base) res = base->truncate(size); if (base != nullptr) {
res = base->truncate(size);
}
} }
return res; return res;

View File

@ -22,6 +22,7 @@
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <utility>
#include "Cipher.h" #include "Cipher.h"
#include "CipherKey.h" #include "CipherKey.h"
@ -29,7 +30,7 @@
#include "Interface.h" #include "Interface.h"
#include "NameIO.h" #include "NameIO.h"
#include "base64.h" #include "base64.h"
#include "internal/easylogging++.h" #include "easylogging++.h"
#include "intl/gettext.h" #include "intl/gettext.h"
namespace encfs { namespace encfs {
@ -38,7 +39,9 @@ static std::shared_ptr<NameIO> NewBlockNameIO(
const Interface &iface, const std::shared_ptr<Cipher> &cipher, const Interface &iface, const std::shared_ptr<Cipher> &cipher,
const CipherKey &key) { const CipherKey &key) {
int blockSize = 8; int blockSize = 8;
if (cipher) blockSize = cipher->cipherBlockSize(); if (cipher) {
blockSize = cipher->cipherBlockSize();
}
return std::shared_ptr<NameIO>( return std::shared_ptr<NameIO>(
new BlockNameIO(iface, cipher, key, blockSize, false)); new BlockNameIO(iface, cipher, key, blockSize, false));
@ -48,7 +51,9 @@ static std::shared_ptr<NameIO> NewBlockNameIO32(
const Interface &iface, const std::shared_ptr<Cipher> &cipher, const Interface &iface, const std::shared_ptr<Cipher> &cipher,
const CipherKey &key) { const CipherKey &key) {
int blockSize = 8; int blockSize = 8;
if (cipher) blockSize = cipher->cipherBlockSize(); if (cipher) {
blockSize = cipher->cipherBlockSize();
}
return std::shared_ptr<NameIO>( return std::shared_ptr<NameIO>(
new BlockNameIO(iface, cipher, key, blockSize, true)); new BlockNameIO(iface, cipher, key, blockSize, true));
@ -88,26 +93,25 @@ static bool BlockIO32_registered = NameIO::Register(
*/ */
Interface BlockNameIO::CurrentInterface(bool caseInsensitive) { Interface BlockNameIO::CurrentInterface(bool caseInsensitive) {
// implement major version 4 plus support for two prior versions // implement major version 4 plus support for two prior versions
if (caseInsensitive) if (caseInsensitive) {
return Interface("nameio/block32", 4, 0, 2); return Interface("nameio/block32", 4, 0, 2);
else }
return Interface("nameio/block", 4, 0, 2); return Interface("nameio/block", 4, 0, 2);
} }
BlockNameIO::BlockNameIO(const Interface &iface, BlockNameIO::BlockNameIO(const Interface &iface, std::shared_ptr<Cipher> cipher,
const std::shared_ptr<Cipher> &cipher, CipherKey key, int blockSize,
const CipherKey &key, int blockSize,
bool caseInsensitiveEncoding) bool caseInsensitiveEncoding)
: _interface(iface.current()), : _interface(iface.current()),
_bs(blockSize), _bs(blockSize),
_cipher(cipher), _cipher(std::move(cipher)),
_key(key), _key(std::move(key)),
_caseInsensitive(caseInsensitiveEncoding) { _caseInsensitive(caseInsensitiveEncoding) {
// just to be safe.. // just to be safe..
rAssert(blockSize < 128); rAssert(blockSize < 128);
} }
BlockNameIO::~BlockNameIO() {} BlockNameIO::~BlockNameIO() = default;
Interface BlockNameIO::interface() const { Interface BlockNameIO::interface() const {
return CurrentInterface(_caseInsensitive); return CurrentInterface(_caseInsensitive);
@ -118,10 +122,10 @@ int BlockNameIO::maxEncodedNameLen(int plaintextNameLen) const {
// the size of too much space rather then too little. // the size of too much space rather then too little.
int numBlocks = (plaintextNameLen + _bs) / _bs; int numBlocks = (plaintextNameLen + _bs) / _bs;
int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes
if (_caseInsensitive) if (_caseInsensitive) {
return B256ToB32Bytes(encodedNameLen); return B256ToB32Bytes(encodedNameLen);
else }
return B256ToB64Bytes(encodedNameLen); return B256ToB64Bytes(encodedNameLen);
} }
int BlockNameIO::maxDecodedNameLen(int encodedNameLen) const { int BlockNameIO::maxDecodedNameLen(int encodedNameLen) const {
@ -135,7 +139,9 @@ int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
// Pad encryption buffer to block boundary.. // Pad encryption buffer to block boundary..
int padding = _bs - length % _bs; int padding = _bs - length % _bs;
if (padding == 0) padding = _bs; // padding a full extra block! if (padding == 0) {
padding = _bs; // padding a full extra block!
}
rAssert(bufferLength >= length + 2 + padding); rAssert(bufferLength >= length + 2 + padding);
memset(encodedName + length + 2, (unsigned char)padding, padding); memset(encodedName + length + 2, (unsigned char)padding, padding);
@ -145,7 +151,9 @@ int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
// store the IV before it is modified by the MAC call. // store the IV before it is modified by the MAC call.
uint64_t tmpIV = 0; uint64_t tmpIV = 0;
if (iv && _interface >= 3) tmpIV = *iv; if ((iv != nullptr) && _interface >= 3) {
tmpIV = *iv;
}
// include padding in MAC computation // include padding in MAC computation
unsigned int mac = _cipher->MAC_16((unsigned char *)encodedName + 2, unsigned int mac = _cipher->MAC_16((unsigned char *)encodedName + 2,
@ -210,7 +218,9 @@ int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
((unsigned int)((unsigned char)tmpBuf[1])); ((unsigned int)((unsigned char)tmpBuf[1]));
uint64_t tmpIV = 0; uint64_t tmpIV = 0;
if (iv && _interface >= 3) tmpIV = *iv; if ((iv != nullptr) && _interface >= 3) {
tmpIV = *iv;
}
bool ok; bool ok;
ok = _cipher->blockDecode((unsigned char *)tmpBuf + 2, decodedStreamLen, ok = _cipher->blockDecode((unsigned char *)tmpBuf + 2, decodedStreamLen,

View File

@ -41,8 +41,8 @@ class BlockNameIO : public NameIO {
public: public:
static Interface CurrentInterface(bool caseInsensitive = false); static Interface CurrentInterface(bool caseInsensitive = false);
BlockNameIO(const Interface &iface, const std::shared_ptr<Cipher> &cipher, BlockNameIO(const Interface &iface, std::shared_ptr<Cipher> cipher,
const CipherKey &key, int blockSize, CipherKey key, int blockSize,
bool caseInsensitiveEncoding = false); bool caseInsensitiveEncoding = false);
virtual ~BlockNameIO(); virtual ~BlockNameIO();

View File

@ -18,10 +18,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <cstddef>
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <map> #include <map>
#include <stddef.h>
#include <string> #include <string>
#include <utility> #include <utility>
@ -56,8 +56,8 @@ struct CipherAlg {
Range blockSize; Range blockSize;
}; };
typedef multimap<string, CipherAlg> CipherMap_t; using CipherMap_t = multimap<string, CipherAlg>;
static CipherMap_t *gCipherMap = NULL; static CipherMap_t *gCipherMap = nullptr;
std::list<Cipher::CipherAlgorithm> Cipher::GetAlgorithmList( std::list<Cipher::CipherAlgorithm> Cipher::GetAlgorithmList(
bool includeHidden) { bool includeHidden) {
@ -65,7 +65,9 @@ std::list<Cipher::CipherAlgorithm> Cipher::GetAlgorithmList(
list<CipherAlgorithm> result; list<CipherAlgorithm> result;
if (!gCipherMap) return result; if (gCipherMap == nullptr) {
return result;
}
CipherMap_t::const_iterator it; CipherMap_t::const_iterator it;
CipherMap_t::const_iterator mapEnd = gCipherMap->end(); CipherMap_t::const_iterator mapEnd = gCipherMap->end();
@ -98,7 +100,9 @@ bool Cipher::Register(const char *name, const char *description,
const Interface &iface, const Range &keyLength, const Interface &iface, const Range &keyLength,
const Range &blockSize, CipherConstructor fn, const Range &blockSize, CipherConstructor fn,
bool hidden) { bool hidden) {
if (!gCipherMap) gCipherMap = new CipherMap_t; if (gCipherMap == nullptr) {
gCipherMap = new CipherMap_t;
}
CipherAlg ca; CipherAlg ca;
ca.hidden = hidden; ca.hidden = hidden;
@ -114,7 +118,7 @@ bool Cipher::Register(const char *name, const char *description,
std::shared_ptr<Cipher> Cipher::New(const string &name, int keyLen) { std::shared_ptr<Cipher> Cipher::New(const string &name, int keyLen) {
std::shared_ptr<Cipher> result; std::shared_ptr<Cipher> result;
if (gCipherMap) { if (gCipherMap != nullptr) {
CipherMap_t::const_iterator it = gCipherMap->find(name); CipherMap_t::const_iterator it = gCipherMap->find(name);
if (it != gCipherMap->end()) { if (it != gCipherMap->end()) {
CipherConstructor fn = it->second.constructor; CipherConstructor fn = it->second.constructor;
@ -127,7 +131,7 @@ std::shared_ptr<Cipher> Cipher::New(const string &name, int keyLen) {
} }
std::shared_ptr<Cipher> Cipher::New(const Interface &iface, int keyLen) { std::shared_ptr<Cipher> Cipher::New(const Interface &iface, int keyLen) {
std::shared_ptr<Cipher> result; std::shared_ptr<Cipher> result;
if (gCipherMap) { if (gCipherMap != nullptr) {
CipherMap_t::const_iterator it; CipherMap_t::const_iterator it;
CipherMap_t::const_iterator mapEnd = gCipherMap->end(); CipherMap_t::const_iterator mapEnd = gCipherMap->end();
@ -148,9 +152,9 @@ std::shared_ptr<Cipher> Cipher::New(const Interface &iface, int keyLen) {
return result; return result;
} }
Cipher::Cipher() {} Cipher::Cipher() = default;
Cipher::~Cipher() {} Cipher::~Cipher() = default;
unsigned int Cipher::MAC_32(const unsigned char *src, int len, unsigned int Cipher::MAC_32(const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV) const { const CipherKey &key, uint64_t *chainedIV) const {
@ -184,13 +188,13 @@ bool Cipher::nameDecode(unsigned char *data, int len, uint64_t iv64,
string Cipher::encodeAsString(const CipherKey &key, string Cipher::encodeAsString(const CipherKey &key,
const CipherKey &encodingKey) { const CipherKey &encodingKey) {
int encodedKeySize = this->encodedKeySize(); int encodedKeySize = this->encodedKeySize();
unsigned char *keyBuf = new unsigned char[encodedKeySize]; auto *keyBuf = new unsigned char[encodedKeySize];
// write the key, encoding it with itself. // write the key, encoding it with itself.
this->writeKey(key, keyBuf, encodingKey); this->writeKey(key, keyBuf, encodingKey);
int b64Len = B256ToB64Bytes(encodedKeySize); int b64Len = B256ToB64Bytes(encodedKeySize);
unsigned char *b64Key = new unsigned char[b64Len + 1]; auto *b64Key = new unsigned char[b64Len + 1];
changeBase2(keyBuf, encodedKeySize, 8, b64Key, b64Len, 6); changeBase2(keyBuf, encodedKeySize, 8, b64Key, b64Len, 6);
B64ToAscii(b64Key, b64Len); B64ToAscii(b64Key, b64Len);

View File

@ -44,8 +44,8 @@ class Cipher {
public: public:
// if no key length was indicated when cipher was registered, then keyLen // if no key length was indicated when cipher was registered, then keyLen
// <= 0 will be used. // <= 0 will be used.
typedef std::shared_ptr<Cipher> (*CipherConstructor)(const Interface &iface, using CipherConstructor = std::shared_ptr<Cipher> (*)(const Interface &iface,
int keyLenBits); int keyLenBits);
struct CipherAlgorithm { struct CipherAlgorithm {
std::string name; std::string name;
@ -55,7 +55,7 @@ class Cipher {
Range blockSize; Range blockSize;
}; };
typedef std::list<CipherAlgorithm> AlgorithmList; using AlgorithmList = std::list<CipherAlgorithm>;
static AlgorithmList GetAlgorithmList(bool includeHidden = false); static AlgorithmList GetAlgorithmList(bool includeHidden = false);
static std::shared_ptr<Cipher> New(const Interface &iface, int keyLen = -1); static std::shared_ptr<Cipher> New(const Interface &iface, int keyLen = -1);

View File

@ -20,14 +20,15 @@
#include "CipherFileIO.h" #include "CipherFileIO.h"
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <cerrno> #include <cerrno>
#include <cinttypes>
#include <cstring>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h>
#include <memory> #include <memory>
#include <openssl/sha.h> #include <openssl/sha.h>
#include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <utility>
#include "BlockFileIO.h" #include "BlockFileIO.h"
#include "Cipher.h" #include "Cipher.h"
@ -47,10 +48,10 @@ static Interface CipherFileIO_iface("FileIO/Cipher", 2, 0, 1);
const int HEADER_SIZE = 8; // 64 bit initialization vector.. const int HEADER_SIZE = 8; // 64 bit initialization vector..
CipherFileIO::CipherFileIO(const std::shared_ptr<FileIO> &_base, CipherFileIO::CipherFileIO(std::shared_ptr<FileIO> _base,
const FSConfigPtr &cfg) const FSConfigPtr &cfg)
: BlockFileIO(cfg->config->blockSize, cfg), : BlockFileIO(cfg->config->blockSize, cfg),
base(_base), base(std::move(_base)),
haveHeader(cfg->config->uniqueIV), haveHeader(cfg->config->uniqueIV),
externalIV(0), externalIV(0),
fileIV(0), fileIV(0),
@ -63,14 +64,16 @@ CipherFileIO::CipherFileIO(const std::shared_ptr<FileIO> &_base,
<< "FS block size must be multiple of cipher block size"; << "FS block size must be multiple of cipher block size";
} }
CipherFileIO::~CipherFileIO() {} CipherFileIO::~CipherFileIO() = default;
Interface CipherFileIO::interface() const { return CipherFileIO_iface; } Interface CipherFileIO::interface() const { return CipherFileIO_iface; }
int CipherFileIO::open(int flags) { int CipherFileIO::open(int flags) {
int res = base->open(flags); int res = base->open(flags);
if (res >= 0) lastFlags = flags; if (res >= 0) {
lastFlags = flags;
}
return res; return res;
} }
@ -109,8 +112,9 @@ bool CipherFileIO::setIV(uint64_t iv) {
} }
} }
if (fileIV == 0) { if (fileIV == 0) {
if (initHeader() < 0) if (initHeader() < 0) {
return false; return false;
}
} }
uint64_t oldIV = externalIV; uint64_t oldIV = externalIV;
@ -185,14 +189,18 @@ int CipherFileIO::initHeader() {
req.data = buf; req.data = buf;
req.dataLen = 8; req.dataLen = 8;
ssize_t readSize = base->read(req); ssize_t readSize = base->read(req);
if(readSize < 0) if(readSize < 0) {
return readSize; return readSize;
}
if(!cipher->streamDecode(buf, sizeof(buf), externalIV, key)) if(!cipher->streamDecode(buf, sizeof(buf), externalIV, key)) {
return -EBADMSG; return -EBADMSG;
}
fileIV = 0; fileIV = 0;
for (int i = 0; i < 8; ++i) fileIV = (fileIV << 8) | (uint64_t)buf[i]; for (int i = 0; i < 8; ++i) {
fileIV = (fileIV << 8) | (uint64_t)buf[i];
}
rAssert(fileIV != 0); // 0 is never used.. rAssert(fileIV != 0); // 0 is never used..
} else { } else {
@ -206,15 +214,19 @@ int CipherFileIO::initHeader() {
} }
fileIV = 0; fileIV = 0;
for (int i = 0; i < 8; ++i) fileIV = (fileIV << 8) | (uint64_t)buf[i]; for (int i = 0; i < 8; ++i) {
fileIV = (fileIV << 8) | (uint64_t)buf[i];
}
if (fileIV == 0) if (fileIV == 0) {
RLOG(WARNING) << "Unexpected result: randomize returned 8 null bytes!"; RLOG(WARNING) << "Unexpected result: randomize returned 8 null bytes!";
}
} while (fileIV == 0); // don't accept 0 as an option.. } while (fileIV == 0); // don't accept 0 as an option..
if (base->isWritable()) { if (base->isWritable()) {
if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key)) if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key)) {
return -EBADMSG; return -EBADMSG;
}
IORequest req; IORequest req;
req.offset = 0; req.offset = 0;
@ -222,8 +234,9 @@ int CipherFileIO::initHeader() {
req.dataLen = 8; req.dataLen = 8;
int res = base->write(req); int res = base->write(req);
if (res < 0) if (res < 0) {
return res; return res;
}
} else { } else {
VLOG(1) << "base not writable, IV not written.."; VLOG(1) << "base not writable, IV not written..";
} }
@ -244,16 +257,18 @@ bool CipherFileIO::writeHeader() {
fileIV >>= 8; fileIV >>= 8;
} }
if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key)) if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key)) {
return false; return false;
}
IORequest req; IORequest req;
req.offset = 0; req.offset = 0;
req.data = buf; req.data = buf;
req.dataLen = 8; req.dataLen = 8;
if (base->write(req) < 0) if (base->write(req) < 0) {
return false; return false;
}
return true; return true;
} }
@ -331,8 +346,9 @@ ssize_t CipherFileIO::readOneBlock(const IORequest &req) const {
if (readSize > 0) { if (readSize > 0) {
if (haveHeader && fileIV == 0) { if (haveHeader && fileIV == 0) {
int res = const_cast<CipherFileIO *>(this)->initHeader(); int res = const_cast<CipherFileIO *>(this)->initHeader();
if (res < 0) if (res < 0) {
return res; return res;
}
} }
if (readSize != bs) { if (readSize != bs) {
@ -367,8 +383,9 @@ int CipherFileIO::writeOneBlock(const IORequest &req) {
if (haveHeader && fileIV == 0) { if (haveHeader && fileIV == 0) {
int res = initHeader(); int res = initHeader();
if (res < 0) if (res < 0) {
return res; return res;
}
} }
bool ok; bool ok;
@ -397,43 +414,45 @@ int CipherFileIO::writeOneBlock(const IORequest &req) {
bool CipherFileIO::blockWrite(unsigned char *buf, int size, bool CipherFileIO::blockWrite(unsigned char *buf, int size,
uint64_t _iv64) const { uint64_t _iv64) const {
VLOG(1) << "Called blockWrite"; VLOG(1) << "Called blockWrite";
if (!fsConfig->reverseEncryption) if (!fsConfig->reverseEncryption) {
return cipher->blockEncode(buf, size, _iv64, key); return cipher->blockEncode(buf, size, _iv64, key);
else }
return cipher->blockDecode(buf, size, _iv64, key); return cipher->blockDecode(buf, size, _iv64, key);
} }
bool CipherFileIO::streamWrite(unsigned char *buf, int size, bool CipherFileIO::streamWrite(unsigned char *buf, int size,
uint64_t _iv64) const { uint64_t _iv64) const {
VLOG(1) << "Called streamWrite"; VLOG(1) << "Called streamWrite";
if (!fsConfig->reverseEncryption) if (!fsConfig->reverseEncryption) {
return cipher->streamEncode(buf, size, _iv64, key); return cipher->streamEncode(buf, size, _iv64, key);
else }
return cipher->streamDecode(buf, size, _iv64, key); return cipher->streamDecode(buf, size, _iv64, key);
} }
bool CipherFileIO::blockRead(unsigned char *buf, int size, bool CipherFileIO::blockRead(unsigned char *buf, int size,
uint64_t _iv64) const { uint64_t _iv64) const {
if (fsConfig->reverseEncryption) if (fsConfig->reverseEncryption) {
return cipher->blockEncode(buf, size, _iv64, key); return cipher->blockEncode(buf, size, _iv64, key);
else {
if (_allowHoles) {
// special case - leave all 0's alone
for (int i = 0; i < size; ++i)
if (buf[i] != 0) return cipher->blockDecode(buf, size, _iv64, key);
return true;
} else
return cipher->blockDecode(buf, size, _iv64, key);
} }
if (_allowHoles) {
// special case - leave all 0's alone
for (int i = 0; i < size; ++i) {
if (buf[i] != 0) {
return cipher->blockDecode(buf, size, _iv64, key);
}
}
return true;
}
return cipher->blockDecode(buf, size, _iv64, key);
} }
bool CipherFileIO::streamRead(unsigned char *buf, int size, bool CipherFileIO::streamRead(unsigned char *buf, int size,
uint64_t _iv64) const { uint64_t _iv64) const {
if (fsConfig->reverseEncryption) if (fsConfig->reverseEncryption) {
return cipher->streamEncode(buf, size, _iv64, key); return cipher->streamEncode(buf, size, _iv64, key);
else }
return cipher->streamDecode(buf, size, _iv64, key); return cipher->streamDecode(buf, size, _iv64, key);
} }
int CipherFileIO::truncate(off_t size) { int CipherFileIO::truncate(off_t size) {
@ -453,15 +472,18 @@ int CipherFileIO::truncate(off_t size) {
} }
} }
int res = initHeader(); int res = initHeader();
if (res < 0) if (res < 0) {
return res; return res;
}
} }
// can't let BlockFileIO call base->truncate(), since it would be using // can't let BlockFileIO call base->truncate(), since it would be using
// the wrong size.. // the wrong size..
res = BlockFileIO::truncateBase(size, 0); res = BlockFileIO::truncateBase(size, nullptr);
if (!(res < 0)) res = base->truncate(size + HEADER_SIZE); if (!(res < 0)) {
res = base->truncate(size + HEADER_SIZE);
}
} }
return res; return res;
} }
@ -486,8 +508,9 @@ ssize_t CipherFileIO::read(const IORequest &origReq) const {
// this is needed in any case - without IV the file cannot be decoded // this is needed in any case - without IV the file cannot be decoded
unsigned char headerBuf[HEADER_SIZE]; unsigned char headerBuf[HEADER_SIZE];
int res = const_cast<CipherFileIO *>(this)->generateReverseHeader(headerBuf); int res = const_cast<CipherFileIO *>(this)->generateReverseHeader(headerBuf);
if (res < 0) if (res < 0) {
return res; return res;
}
// Copy the request so we can modify it without affecting the caller // Copy the request so we can modify it without affecting the caller
IORequest req = origReq; IORequest req = origReq;
@ -502,8 +525,9 @@ ssize_t CipherFileIO::read(const IORequest &origReq) const {
* to the data. */ * to the data. */
if (req.offset < 0) { if (req.offset < 0) {
headerBytes = -req.offset; headerBytes = -req.offset;
if (req.dataLen < headerBytes) if (req.dataLen < headerBytes) {
headerBytes = req.dataLen; // only up to the number of bytes requested headerBytes = req.dataLen; // only up to the number of bytes requested
}
VLOG(1) << "Adding " << headerBytes << " header bytes"; VLOG(1) << "Adding " << headerBytes << " header bytes";
// copy the header bytes into the data // copy the header bytes into the data
@ -511,7 +535,9 @@ ssize_t CipherFileIO::read(const IORequest &origReq) const {
memcpy(req.data, &headerBuf[headerOffset], headerBytes); memcpy(req.data, &headerBuf[headerOffset], headerBytes);
// the read does not want data beyond the header // the read does not want data beyond the header
if (headerBytes == req.dataLen) return headerBytes; if (headerBytes == req.dataLen) {
return headerBytes;
}
/* The rest of the request will be read from the backing file. /* The rest of the request will be read from the backing file.
* As we have already generated n=headerBytes bytes, the request is * As we have already generated n=headerBytes bytes, the request is
@ -525,13 +551,12 @@ ssize_t CipherFileIO::read(const IORequest &origReq) const {
// read the payload // read the payload
ssize_t readBytes = BlockFileIO::read(req); ssize_t readBytes = BlockFileIO::read(req);
VLOG(1) << "read " << readBytes << " bytes from backing file"; VLOG(1) << "read " << readBytes << " bytes from backing file";
if (readBytes < 0) if (readBytes < 0) {
return readBytes; // Return error code return readBytes; // Return error code
else {
ssize_t sum = headerBytes + readBytes;
VLOG(1) << "returning sum=" << sum;
return sum;
} }
ssize_t sum = headerBytes + readBytes;
VLOG(1) << "returning sum=" << sum;
return sum;
} }
bool CipherFileIO::isWritable() const { return base->isWritable(); } bool CipherFileIO::isWritable() const { return base->isWritable(); }

View File

@ -45,7 +45,7 @@ struct IORequest;
*/ */
class CipherFileIO : public BlockFileIO { class CipherFileIO : public BlockFileIO {
public: public:
CipherFileIO(const std::shared_ptr<FileIO> &base, const FSConfigPtr &cfg); CipherFileIO(std::shared_ptr<FileIO> base, const FSConfigPtr &cfg);
virtual ~CipherFileIO(); virtual ~CipherFileIO();
virtual Interface interface() const; virtual Interface interface() const;

View File

@ -22,8 +22,8 @@
namespace encfs { namespace encfs {
AbstractCipherKey::AbstractCipherKey() {} AbstractCipherKey::AbstractCipherKey() = default;
AbstractCipherKey::~AbstractCipherKey() {} AbstractCipherKey::~AbstractCipherKey() = default;
} // namespace encfs } // namespace encfs

View File

@ -31,7 +31,7 @@ class AbstractCipherKey {
virtual ~AbstractCipherKey(); virtual ~AbstractCipherKey();
}; };
typedef std::shared_ptr<AbstractCipherKey> CipherKey; using CipherKey = std::shared_ptr<AbstractCipherKey>;
} // namespace encfs } // namespace encfs

View File

@ -33,23 +33,27 @@ using namespace std;
namespace encfs { namespace encfs {
ConfigReader::ConfigReader() {} ConfigReader::ConfigReader() = default;
ConfigReader::~ConfigReader() {} ConfigReader::~ConfigReader() = default;
// read the entire file into a ConfigVar instance and then use that to decode // read the entire file into a ConfigVar instance and then use that to decode
// into mapped variables. // into mapped variables.
bool ConfigReader::load(const char *fileName) { bool ConfigReader::load(const char *fileName) {
struct stat stbuf; struct stat stbuf;
memset(&stbuf, 0, sizeof(struct stat)); memset(&stbuf, 0, sizeof(struct stat));
if (lstat(fileName, &stbuf) != 0) return false; if (lstat(fileName, &stbuf) != 0) {
return false;
}
int size = stbuf.st_size; int size = stbuf.st_size;
int fd = open(fileName, O_RDONLY); int fd = open(fileName, O_RDONLY);
if (fd < 0) return false; if (fd < 0) {
return false;
}
char *buf = new char[size]; auto *buf = new char[size];
int res = ::read(fd, buf, size); int res = ::read(fd, buf, size);
close(fd); close(fd);
@ -126,11 +130,11 @@ ConfigVar ConfigReader::toVar() const {
ConfigVar ConfigReader::operator[](const std::string &varName) const { ConfigVar ConfigReader::operator[](const std::string &varName) const {
// read only // read only
map<string, ConfigVar>::const_iterator it = vars.find(varName); auto it = vars.find(varName);
if (it == vars.end()) if (it == vars.end()) {
return ConfigVar(); return ConfigVar();
else }
return it->second; return it->second;
} }
ConfigVar &ConfigReader::operator[](const std::string &varName) { ConfigVar &ConfigReader::operator[](const std::string &varName) {

View File

@ -20,7 +20,7 @@
#include "ConfigVar.h" #include "ConfigVar.h"
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <cstring> #include <cstring>
#include "Error.h" #include "Error.h"
@ -43,10 +43,10 @@ ConfigVar::ConfigVar(const ConfigVar &src) { pd = src.pd; }
ConfigVar::~ConfigVar() { pd.reset(); } ConfigVar::~ConfigVar() { pd.reset(); }
ConfigVar &ConfigVar::operator=(const ConfigVar &src) { ConfigVar &ConfigVar::operator=(const ConfigVar &src) {
if (src.pd == pd) if (src.pd == pd) {
return *this; return *this;
else }
pd = src.pd; pd = src.pd;
return *this; return *this;
} }
@ -56,7 +56,9 @@ void ConfigVar::resetOffset() { pd->offset = 0; }
int ConfigVar::read(unsigned char *buffer_, int bytes) const { int ConfigVar::read(unsigned char *buffer_, int bytes) const {
int toCopy = MIN(bytes, pd->buffer.size() - pd->offset); int toCopy = MIN(bytes, pd->buffer.size() - pd->offset);
if (toCopy > 0) memcpy(buffer_, pd->buffer.data() + pd->offset, toCopy); if (toCopy > 0) {
memcpy(buffer_, pd->buffer.data() + pd->offset, toCopy);
}
pd->offset += toCopy; pd->offset += toCopy;
@ -106,13 +108,15 @@ void ConfigVar::writeInt(int val) {
// find the starting point - we only need to output starting at the most // find the starting point - we only need to output starting at the most
// significant non-zero digit.. // significant non-zero digit..
int start = 0; int start = 0;
while (digit[start] == 0x80) ++start; while (digit[start] == 0x80) {
++start;
}
write(digit + start, 5 - start); write(digit + start, 5 - start);
} }
int ConfigVar::readInt() const { int ConfigVar::readInt() const {
const unsigned char *buf = (const unsigned char *)buffer(); const auto *buf = (const unsigned char *)buffer();
int bytes = this->size(); int bytes = this->size();
int offset = at(); int offset = at();
int value = 0; int value = 0;
@ -122,7 +126,7 @@ int ConfigVar::readInt() const {
do { do {
unsigned char tmp = buf[offset++]; unsigned char tmp = buf[offset++];
highBitSet = tmp & 0x80; highBitSet = ((tmp & 0x80) != 0);
value = (value << 7) | (int)(tmp & 0x7f); value = (value << 7) | (int)(tmp & 0x7f);
} while (highBitSet && offset < bytes); } while (highBitSet && offset < bytes);
@ -139,10 +143,10 @@ int ConfigVar::readInt(int defaultValue) const {
int bytes = this->size(); int bytes = this->size();
int offset = at(); int offset = at();
if (offset >= bytes) if (offset >= bytes) {
return defaultValue; return defaultValue;
else }
return readInt(); return readInt();
} }
bool ConfigVar::readBool(bool defaultValue) const { bool ConfigVar::readBool(bool defaultValue) const {
@ -184,7 +188,7 @@ const ConfigVar &operator>>(const ConfigVar &src, std::string &result) {
unsigned char tmpBuf[32]; unsigned char tmpBuf[32];
if (length > (int)sizeof(tmpBuf)) { if (length > (int)sizeof(tmpBuf)) {
unsigned char *ptr = new unsigned char[length]; auto *ptr = new unsigned char[length];
readLen = src.read(ptr, length); readLen = src.read(ptr, length);
result.assign((char *)ptr, length); result.assign((char *)ptr, length);
delete[] ptr; delete[] ptr;

View File

@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <utility> #include <utility>
#include "Context.h" #include "Context.h"
@ -29,11 +29,12 @@
namespace encfs { namespace encfs {
EncFS_Context::EncFS_Context() { EncFS_Context::EncFS_Context() {
pthread_cond_init(&wakeupCond, 0); pthread_cond_init(&wakeupCond, nullptr);
pthread_mutex_init(&wakeupMutex, 0); pthread_mutex_init(&wakeupMutex, nullptr);
pthread_mutex_init(&contextMutex, 0); pthread_mutex_init(&contextMutex, nullptr);
usageCount = 0; usageCount = 0;
currentFuseFh = 1;
} }
EncFS_Context::~EncFS_Context() { EncFS_Context::~EncFS_Context() {
@ -69,31 +70,28 @@ void EncFS_Context::setRoot(const std::shared_ptr<DirNode> &r) {
Lock lock(contextMutex); Lock lock(contextMutex);
root = r; root = r;
if (r) rootCipherDir = r->rootDirectory(); if (r) {
rootCipherDir = r->rootDirectory();
}
} }
bool EncFS_Context::isMounted() { return root.get() != nullptr; } bool EncFS_Context::isMounted() { return root != nullptr; }
int EncFS_Context::getAndResetUsageCounter() { void EncFS_Context::getAndResetUsageCounter(int *usage, int *openCount) {
Lock lock(contextMutex); Lock lock(contextMutex);
int count = usageCount; *usage = usageCount;
usageCount = 0; usageCount = 0;
return count; *openCount = openFiles.size();
} }
int EncFS_Context::openFileCount() const {
Lock lock(contextMutex);
return openFiles.size();
}
std::shared_ptr<FileNode> EncFS_Context::lookupNode(const char *path) { std::shared_ptr<FileNode> EncFS_Context::lookupNode(const char *path) {
Lock lock(contextMutex); Lock lock(contextMutex);
FileMap::iterator it = openFiles.find(std::string(path)); auto it = openFiles.find(std::string(path));
if (it != openFiles.end()) { if (it != openFiles.end()) {
// all the items in the set point to the same node.. so just use the // every entry in the list is fine... so just use the
// first // first
return it->second.front(); return it->second.front();
} }
@ -103,7 +101,7 @@ std::shared_ptr<FileNode> EncFS_Context::lookupNode(const char *path) {
void EncFS_Context::renameNode(const char *from, const char *to) { void EncFS_Context::renameNode(const char *from, const char *to) {
Lock lock(contextMutex); Lock lock(contextMutex);
FileMap::iterator it = openFiles.find(std::string(from)); auto it = openFiles.find(std::string(from));
if (it != openFiles.end()) { if (it != openFiles.end()) {
auto val = it->second; auto val = it->second;
openFiles.erase(it); openFiles.erase(it);
@ -111,26 +109,61 @@ void EncFS_Context::renameNode(const char *from, const char *to) {
} }
} }
FileNode *EncFS_Context::putNode(const char *path, // putNode stores "node" under key "path" in the "openFiles" map. It
std::shared_ptr<FileNode> &&node) { // increments the reference count if the key already exists.
void EncFS_Context::putNode(const char *path, std::shared_ptr<FileNode> node) {
Lock lock(contextMutex); Lock lock(contextMutex);
auto &list = openFiles[std::string(path)]; auto &list = openFiles[std::string(path)];
list.push_front(std::move(node)); // The length of "list" serves as the reference count.
return list.front().get(); list.push_front(node);
fuseFhMap[node->fuseFh] = node;
} }
void EncFS_Context::eraseNode(const char *path, FileNode *pl) { // eraseNode is called by encfs_release in response to the RELEASE
// FUSE-command we get from the kernel.
void EncFS_Context::eraseNode(const char *path,
std::shared_ptr<FileNode> fnode) {
Lock lock(contextMutex); Lock lock(contextMutex);
FileMap::iterator it = openFiles.find(std::string(path)); auto it = openFiles.find(std::string(path));
rAssert(it != openFiles.end()); rAssert(it != openFiles.end());
auto &list = it->second;
it->second.pop_front(); // Find "fnode" in the list of FileNodes registered under this path.
auto findIter = std::find(list.begin(), list.end(), fnode);
rAssert(findIter != list.end());
list.erase(findIter);
// if no more references to this file, remove the record all together // If no reference to "fnode" remains, drop the entry from fuseFhMap
if (it->second.empty()) { // and overwrite the canary.
findIter = std::find(list.begin(), list.end(), fnode);
if (findIter == list.end()) {
fuseFhMap.erase(fnode->fuseFh);
fnode->canary = CANARY_RELEASED;
}
// If no FileNode is registered at this path anymore, drop the entry
// from openFiles.
if (list.empty()) {
openFiles.erase(it); openFiles.erase(it);
} }
} }
// nextFuseFh returns the next unused uint64 to serve as the FUSE file
// handle for the kernel.
uint64_t EncFS_Context::nextFuseFh(void) {
// This is thread-safe because currentFuseFh is declared as std::atomic
return currentFuseFh++;
}
// lookupFuseFh finds "n" in "fuseFhMap" and returns the FileNode.
std::shared_ptr<FileNode> EncFS_Context::lookupFuseFh(uint64_t n) {
Lock lock(contextMutex);
auto it = fuseFhMap.find(n);
if (it == fuseFhMap.end()) {
return nullptr;
}
return it->second;
}
} // namespace encfs } // namespace encfs

View File

@ -21,7 +21,9 @@
#ifndef _Context_incl_ #ifndef _Context_incl_
#define _Context_incl_ #define _Context_incl_
#include <forward_list> #include <algorithm>
#include <atomic>
#include <list>
#include <memory> #include <memory>
#include <pthread.h> #include <pthread.h>
#include <set> #include <set>
@ -44,12 +46,11 @@ class EncFS_Context {
std::shared_ptr<FileNode> lookupNode(const char *path); std::shared_ptr<FileNode> lookupNode(const char *path);
int getAndResetUsageCounter(); void getAndResetUsageCounter(int *usage, int *openCount);
int openFileCount() const;
FileNode *putNode(const char *path, std::shared_ptr<FileNode> &&node); void putNode(const char *path, std::shared_ptr<FileNode> node);
void eraseNode(const char *path, FileNode *fnode); void eraseNode(const char *path, std::shared_ptr<FileNode> fnode);
void renameNode(const char *oldName, const char *newName); void renameNode(const char *oldName, const char *newName);
@ -70,6 +71,9 @@ class EncFS_Context {
pthread_cond_t wakeupCond; pthread_cond_t wakeupCond;
pthread_mutex_t wakeupMutex; pthread_mutex_t wakeupMutex;
uint64_t nextFuseFh();
std::shared_ptr<FileNode> lookupFuseFh(uint64_t);
private: private:
/* This placeholder is what is referenced in FUSE context (passed to /* This placeholder is what is referenced in FUSE context (passed to
* callbacks). * callbacks).
@ -81,15 +85,17 @@ class EncFS_Context {
* us. * us.
*/ */
typedef std::unordered_map<std::string, using FileMap =
std::forward_list<std::shared_ptr<FileNode>>> std::unordered_map<std::string, std::list<std::shared_ptr<FileNode>>>;
FileMap;
mutable pthread_mutex_t contextMutex; mutable pthread_mutex_t contextMutex;
FileMap openFiles; FileMap openFiles;
int usageCount; int usageCount;
std::shared_ptr<DirNode> root; std::shared_ptr<DirNode> root;
std::atomic<std::uint64_t> currentFuseFh;
std::unordered_map<uint64_t, std::shared_ptr<FileNode>> fuseFhMap;
}; };
int remountFS(EncFS_Context *ctx); int remountFS(EncFS_Context *ctx);

View File

@ -35,8 +35,9 @@
#include <sys/fsuid.h> #include <sys/fsuid.h>
#endif #endif
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <cstring> #include <cstring>
#include <utility>
#include "Context.h" #include "Context.h"
#include "Error.h" #include "Error.h"
@ -51,20 +52,13 @@ class DirDeleter {
void operator()(DIR *d) { ::closedir(d); } void operator()(DIR *d) { ::closedir(d); }
}; };
DirTraverse::DirTraverse(const std::shared_ptr<DIR> &_dirPtr, uint64_t _iv, DirTraverse::DirTraverse(std::shared_ptr<DIR> _dirPtr, uint64_t _iv,
const std::shared_ptr<NameIO> &_naming) std::shared_ptr<NameIO> _naming)
: dir(_dirPtr), iv(_iv), naming(_naming) {} : dir(std::move(_dirPtr)), iv(_iv), naming(std::move(_naming)) {}
DirTraverse::DirTraverse(const DirTraverse &src) DirTraverse::DirTraverse(const DirTraverse &src) = default;
: dir(src.dir), iv(src.iv), naming(src.naming) {}
DirTraverse &DirTraverse::operator=(const DirTraverse &src) { DirTraverse &DirTraverse::operator=(const DirTraverse &src) = default;
dir = src.dir;
iv = src.iv;
naming = src.naming;
return *this;
}
DirTraverse::~DirTraverse() { DirTraverse::~DirTraverse() {
dir.reset(); dir.reset();
@ -76,25 +70,28 @@ static bool _nextName(struct dirent *&de, const std::shared_ptr<DIR> &dir,
int *fileType, ino_t *inode) { int *fileType, ino_t *inode) {
de = ::readdir(dir.get()); de = ::readdir(dir.get());
if (de) { if (de != nullptr) {
if (fileType) { if (fileType != nullptr) {
#if defined(_DIRENT_HAVE_D_TYPE) || defined(__FreeBSD__) || defined(__APPLE__) #if defined(HAVE_DIRENT_D_TYPE)
*fileType = de->d_type; *fileType = de->d_type;
#else #else
#warning "struct dirent.d_type not supported" #warning "struct dirent.d_type not supported"
*fileType = 0; *fileType = 0;
#endif #endif
} }
if (inode) *inode = de->d_ino; if (inode != nullptr) {
*inode = de->d_ino;
}
return true; return true;
} else {
if (fileType) *fileType = 0;
return false;
} }
if (fileType != nullptr) {
*fileType = 0;
}
return false;
} }
std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) { std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) {
struct dirent *de = 0; struct dirent *de = nullptr;
while (_nextName(de, dir, fileType, inode)) { while (_nextName(de, dir, fileType, inode)) {
try { try {
uint64_t localIv = iv; uint64_t localIv = iv;
@ -109,9 +106,9 @@ std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) {
} }
std::string DirTraverse::nextInvalid() { std::string DirTraverse::nextInvalid() {
struct dirent *de = 0; struct dirent *de = nullptr;
// find the first name which produces a decoding error... // find the first name which produces a decoding error...
while (_nextName(de, dir, (int *)0, (ino_t *)0)) { while (_nextName(de, dir, (int *)nullptr, (ino_t *)nullptr)) {
try { try {
uint64_t localIv = iv; uint64_t localIv = iv;
naming->decodePath(de->d_name, &localIv); naming->decodePath(de->d_name, &localIv);
@ -143,17 +140,16 @@ class RenameOp {
list<RenameEl>::const_iterator last; list<RenameEl>::const_iterator last;
public: public:
RenameOp(DirNode *_dn, const std::shared_ptr<list<RenameEl> > &_renameList) RenameOp(DirNode *_dn, std::shared_ptr<list<RenameEl> > _renameList)
: dn(_dn), renameList(_renameList) { : dn(_dn), renameList(std::move(_renameList)) {
last = renameList->begin(); last = renameList->begin();
} }
RenameOp(const RenameOp &src) RenameOp(const RenameOp &src) = default;
: dn(src.dn), renameList(src.renameList), last(src.last) {}
~RenameOp(); ~RenameOp();
operator bool() const { return renameList.get() != nullptr; } operator bool() const { return renameList != nullptr; }
bool apply(); bool apply();
void undo(); void undo();
@ -220,7 +216,7 @@ void RenameOp::undo() {
// list has to be processed backwards, otherwise we may rename // list has to be processed backwards, otherwise we may rename
// directories and directory contents in the wrong order! // directories and directory contents in the wrong order!
int undoCount = 0; int undoCount = 0;
list<RenameEl>::const_iterator it = last; auto it = last;
while (it != renameList->begin()) { while (it != renameList->begin()) {
--it; --it;
@ -242,7 +238,7 @@ void RenameOp::undo() {
DirNode::DirNode(EncFS_Context *_ctx, const string &sourceDir, DirNode::DirNode(EncFS_Context *_ctx, const string &sourceDir,
const FSConfigPtr &_config) { const FSConfigPtr &_config) {
pthread_mutex_init(&mutex, 0); pthread_mutex_init(&mutex, nullptr);
Lock _lock(mutex); Lock _lock(mutex);
@ -253,7 +249,7 @@ DirNode::DirNode(EncFS_Context *_ctx, const string &sourceDir,
naming = fsConfig->nameCoding; naming = fsConfig->nameCoding;
} }
DirNode::~DirNode() {} DirNode::~DirNode() = default;
bool DirNode::hasDirectoryNameDependency() const { bool DirNode::hasDirectoryNameDependency() const {
return naming ? naming->getChainedNameIV() : false; return naming ? naming->getChainedNameIV() : false;
@ -355,23 +351,24 @@ DirTraverse DirNode::openDir(const char *plaintextPath) {
string cyName = rootDir + naming->encodePath(plaintextPath); string cyName = rootDir + naming->encodePath(plaintextPath);
DIR *dir = ::opendir(cyName.c_str()); DIR *dir = ::opendir(cyName.c_str());
if (dir == NULL) { if (dir == nullptr) {
int eno = errno; int eno = errno;
VLOG(1) << "opendir error " << strerror(eno); VLOG(1) << "opendir error " << strerror(eno);
return DirTraverse(shared_ptr<DIR>(), 0, std::shared_ptr<NameIO>()); return DirTraverse(shared_ptr<DIR>(), 0, std::shared_ptr<NameIO>());
} else {
std::shared_ptr<DIR> dp(dir, DirDeleter());
uint64_t iv = 0;
// if we're using chained IV mode, then compute the IV at this
// directory level..
try {
if (naming->getChainedNameIV()) naming->encodePath(plaintextPath, &iv);
} catch (encfs::Error &err) {
RLOG(ERROR) << "encode err: " << err.what();
}
return DirTraverse(dp, iv, naming);
} }
std::shared_ptr<DIR> dp(dir, DirDeleter());
uint64_t iv = 0;
// if we're using chained IV mode, then compute the IV at this
// directory level..
try {
if (naming->getChainedNameIV()) {
naming->encodePath(plaintextPath, &iv);
}
} catch (encfs::Error &err) {
RLOG(ERROR) << "encode err: " << err.what();
}
return DirTraverse(dp, iv, naming);
} }
bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP, bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP,
@ -386,16 +383,20 @@ bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP,
string sourcePath = rootDir + fromCPart; string sourcePath = rootDir + fromCPart;
// ok..... we wish it was so simple.. should almost never happen // ok..... we wish it was so simple.. should almost never happen
if (fromIV == toIV) return true; if (fromIV == toIV) {
return true;
}
// generate the real destination path, where we expect to find the files.. // generate the real destination path, where we expect to find the files..
VLOG(1) << "opendir " << sourcePath; VLOG(1) << "opendir " << sourcePath;
std::shared_ptr<DIR> dir = std::shared_ptr<DIR> dir =
std::shared_ptr<DIR>(opendir(sourcePath.c_str()), DirDeleter()); std::shared_ptr<DIR>(opendir(sourcePath.c_str()), DirDeleter());
if (!dir) return false; if (!dir) {
return false;
}
struct dirent *de = NULL; struct dirent *de = nullptr;
while ((de = ::readdir(dir.get())) != NULL) { while ((de = ::readdir(dir.get())) != nullptr) {
// decode the name using the oldIV // decode the name using the oldIV
uint64_t localIV = fromIV; uint64_t localIV = fromIV;
string plainName; string plainName;
@ -431,7 +432,7 @@ bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP,
ren.newPName = string(toP) + '/' + plainName; ren.newPName = string(toP) + '/' + plainName;
bool isDir; bool isDir;
#if defined(_DIRENT_HAVE_D_TYPE) #if defined(HAVE_DIRENT_D_TYPE)
if (de->d_type != DT_UNKNOWN) { if (de->d_type != DT_UNKNOWN) {
isDir = (de->d_type == DT_DIR); isDir = (de->d_type == DT_DIR);
} else } else
@ -477,16 +478,17 @@ bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP,
will have changed.. will have changed..
Returns a list of renamed items on success, a null list on failure. Returns a list of renamed items on success, a null list on failure.
*/ std::shared_ptr<RenameOp> DirNode::newRenameOp(const char *fromP, */
const char *toP) { std::shared_ptr<RenameOp> DirNode::newRenameOp(const char *fromP,
const char *toP) {
// Do the rename in two stages to avoid chasing our tail // Do the rename in two stages to avoid chasing our tail
// Undo everything if we encounter an error! // Undo everything if we encounter an error!
std::shared_ptr<list<RenameEl> > renameList(new list<RenameEl>); std::shared_ptr<list<RenameEl> > renameList(new list<RenameEl>);
if (!genRenameList(*renameList.get(), fromP, toP)) { if (!genRenameList(*renameList.get(), fromP, toP)) {
RLOG(WARNING) << "Error during generation of recursive rename list"; RLOG(WARNING) << "Error during generation of recursive rename list";
return std::shared_ptr<RenameOp>(); return std::shared_ptr<RenameOp>();
} else }
return std::shared_ptr<RenameOp>(new RenameOp(this, renameList)); return std::make_shared<RenameOp>(this, renameList);
} }
int DirNode::mkdir(const char *plaintextPath, mode_t mode, uid_t uid, int DirNode::mkdir(const char *plaintextPath, mode_t mode, uid_t uid,
@ -499,21 +501,30 @@ int DirNode::mkdir(const char *plaintextPath, mode_t mode, uid_t uid,
// if uid or gid are set, then that should be the directory owner // if uid or gid are set, then that should be the directory owner
int olduid = -1; int olduid = -1;
int oldgid = -1; int oldgid = -1;
if (uid != 0) olduid = setfsuid(uid); if (uid != 0) {
if (gid != 0) oldgid = setfsgid(gid); olduid = setfsuid(uid);
}
if (gid != 0) {
oldgid = setfsgid(gid);
}
int res = ::mkdir(cyName.c_str(), mode); int res = ::mkdir(cyName.c_str(), mode);
if (olduid >= 0) setfsuid(olduid); if (olduid >= 0) {
if (oldgid >= 0) setfsgid(oldgid); setfsuid(olduid);
}
if (oldgid >= 0) {
setfsgid(oldgid);
}
if (res == -1) { if (res == -1) {
int eno = errno; int eno = errno;
RLOG(WARNING) << "mkdir error on " << cyName << " mode " << mode << ": " RLOG(WARNING) << "mkdir error on " << cyName << " mode " << mode << ": "
<< strerror(eno); << strerror(eno);
res = -eno; res = -eno;
} else } else {
res = 0; res = 0;
}
return res; return res;
} }
@ -536,7 +547,9 @@ int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) {
renameOp = newRenameOp(fromPlaintext, toPlaintext); renameOp = newRenameOp(fromPlaintext, toPlaintext);
if (!renameOp || !renameOp->apply()) { if (!renameOp || !renameOp->apply()) {
if (renameOp) renameOp->undo(); if (renameOp) {
renameOp->undo();
}
RLOG(WARNING) << "rename aborted"; RLOG(WARNING) << "rename aborted";
return -EACCES; return -EACCES;
@ -557,7 +570,9 @@ int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) {
res = -errno; res = -errno;
renameNode(toPlaintext, fromPlaintext, false); renameNode(toPlaintext, fromPlaintext, false);
if (renameOp) renameOp->undo(); if (renameOp) {
renameOp->undo();
}
} else if (preserve_mtime) { } else if (preserve_mtime) {
struct utimbuf ut; struct utimbuf ut;
ut.actime = st.st_atime; ut.actime = st.st_atime;
@ -593,10 +608,11 @@ int DirNode::link(const char *from, const char *to) {
VLOG(1) << "hard links not supported with external IV chaining!"; VLOG(1) << "hard links not supported with external IV chaining!";
} else { } else {
res = ::link(fromCName.c_str(), toCName.c_str()); res = ::link(fromCName.c_str(), toCName.c_str());
if (res == -1) if (res == -1) {
res = -errno; res = -errno;
else } else {
res = 0; res = 0;
}
} }
return res; return res;
@ -605,10 +621,12 @@ int DirNode::link(const char *from, const char *to) {
/* /*
The node is keyed by filename, so a rename means the internal node names The node is keyed by filename, so a rename means the internal node names
must be changed. must be changed.
*/ std::shared_ptr<FileNode> DirNode::renameNode(const char *from, */
const char *to) { std::shared_ptr<FileNode> DirNode::renameNode(const char *from,
const char *to) {
return renameNode(from, to, true); return renameNode(from, to, true);
} }
std::shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to, std::shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to,
bool forwardMode) { bool forwardMode) {
std::shared_ptr<FileNode> node = findOrCreate(from); std::shared_ptr<FileNode> node = findOrCreate(from);
@ -621,7 +639,9 @@ std::shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to,
<< cname; << cname;
if (node->setName(to, cname.c_str(), newIV, forwardMode)) { if (node->setName(to, cname.c_str(), newIV, forwardMode)) {
if (ctx) ctx->renameNode(from, to); if (ctx != nullptr) {
ctx->renameNode(from, to);
}
} else { } else {
// rename error! - put it back // rename error! - put it back
RLOG(ERROR) << "renameNode failed"; RLOG(ERROR) << "renameNode failed";
@ -631,18 +651,30 @@ std::shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to,
return node; return node;
} }
// findOrCreate checks if we already have a FileNode for "plainName" and
// creates a new one if we don't. Returns the FileNode.
std::shared_ptr<FileNode> DirNode::findOrCreate(const char *plainName) { std::shared_ptr<FileNode> DirNode::findOrCreate(const char *plainName) {
std::shared_ptr<FileNode> node; std::shared_ptr<FileNode> node;
if (ctx) node = ctx->lookupNode(plainName);
if (!node) {
uint64_t iv = 0;
string cipherName = naming->encodePath(plainName, &iv);
node.reset(new FileNode(this, fsConfig, plainName,
(rootDir + cipherName).c_str()));
if (fsConfig->config->externalIVChaining) node->setName(0, 0, iv); // See if we already have a FileNode for this path.
if (ctx != nullptr) {
node = ctx->lookupNode(plainName);
VLOG(1) << "created FileNode for " << node->cipherName(); // If we don't, create a new one.
if (!node) {
uint64_t iv = 0;
string cipherName = naming->encodePath(plainName, &iv);
uint64_t fuseFh = ctx->nextFuseFh();
node.reset(new FileNode(this, fsConfig, plainName,
(rootDir + cipherName).c_str(), fuseFh));
if (fsConfig->config->externalIVChaining) {
node->setName(nullptr, nullptr, iv);
}
VLOG(1) << "created FileNode for " << node->cipherName();
}
} }
return node; return node;
@ -656,21 +688,23 @@ shared_ptr<FileNode> DirNode::lookupNode(const char *plainName,
/* /*
Similar to lookupNode, except that we also call open() and only return a Similar to lookupNode, except that we also call open() and only return a
node on sucess.. This is done in one step to avoid any race conditions node on sucess. This is done in one step to avoid any race conditions
with the stored state of the file. with the stored state of the file.
*/ std::shared_ptr<FileNode> DirNode::openNode(const char *plainName, "result" is set to -1 on failure, a value >= 0 on success.
const char *requestor, int flags, */
int *result) { std::shared_ptr<FileNode> DirNode::openNode(const char *plainName,
const char *requestor, int flags,
int *result) {
(void)requestor; (void)requestor;
rAssert(result != NULL); rAssert(result != nullptr);
Lock _lock(mutex); Lock _lock(mutex);
std::shared_ptr<FileNode> node = findOrCreate(plainName); std::shared_ptr<FileNode> node = findOrCreate(plainName);
if (node && (*result = node->open(flags)) >= 0) if (node && (*result = node->open(flags)) >= 0) {
return node; return node;
else }
return std::shared_ptr<FileNode>(); return std::shared_ptr<FileNode>();
} }
int DirNode::unlink(const char *plaintextName) { int DirNode::unlink(const char *plaintextName) {
@ -680,7 +714,7 @@ int DirNode::unlink(const char *plaintextName) {
Lock _lock(mutex); Lock _lock(mutex);
int res = 0; int res = 0;
if (ctx && ctx->lookupNode(plaintextName)) { if ((ctx != nullptr) && ctx->lookupNode(plaintextName)) {
// If FUSE is running with "hard_remove" option where it doesn't // If FUSE is running with "hard_remove" option where it doesn't
// hide open files for us, then we can't allow an unlink of an open // hide open files for us, then we can't allow an unlink of an open
// file.. // file..

View File

@ -48,8 +48,8 @@ struct RenameEl;
class DirTraverse { class DirTraverse {
public: public:
DirTraverse(const std::shared_ptr<DIR> &dirPtr, uint64_t iv, DirTraverse(std::shared_ptr<DIR> dirPtr, uint64_t iv,
const std::shared_ptr<NameIO> &naming); std::shared_ptr<NameIO> naming);
DirTraverse(const DirTraverse &src); DirTraverse(const DirTraverse &src);
~DirTraverse(); ~DirTraverse();

View File

@ -1,22 +1,34 @@
#include "Error.h" #include "Error.h"
INITIALIZE_EASYLOGGINGPP
namespace encfs { namespace encfs {
el::base::DispatchAction rlogAction = el::base::DispatchAction::NormalLog; el::base::DispatchAction rlogAction = el::base::DispatchAction::NormalLog;
Error::Error(const char *msg) : runtime_error(msg) {} Error::Error(const char *msg) : runtime_error(msg) {}
void initLogging(bool enable_debug) { void initLogging(bool enable_debug, bool is_daemon) {
el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput);
el::Configurations defaultConf; el::Configurations defaultConf;
defaultConf.setToDefault(); defaultConf.setToDefault();
defaultConf.set(el::Level::Verbose, el::ConfigurationType::Format,
std::string("%datetime %level [%fbase:%line] %msg"));
defaultConf.set(el::Level::Global, el::ConfigurationType::ToFile, "false"); defaultConf.set(el::Level::Global, el::ConfigurationType::ToFile, "false");
if (!enable_debug) { std::string prefix = "%datetime ";
defaultConf.set(el::Level::Debug, el::ConfigurationType::Enabled, "false"); std::string suffix = " [%fbase:%line]";
if (is_daemon) {
prefix = "";
encfs::rlogAction = el::base::DispatchAction::SysLog;
} else {
el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput);
} }
if (!enable_debug) {
suffix = "";
defaultConf.set(el::Level::Debug, el::ConfigurationType::Enabled, "false");
} else {
el::Loggers::setVerboseLevel(1);
}
defaultConf.setGlobally(el::ConfigurationType::Format,
prefix + std::string("%level %msg") + suffix);
el::Loggers::reconfigureLogger("default", defaultConf); el::Loggers::reconfigureLogger("default", defaultConf);
} }

View File

@ -3,7 +3,7 @@
// Provides compatibility with RLog's rAssert, which throws an Error exception. // Provides compatibility with RLog's rAssert, which throws an Error exception.
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <stdexcept> #include <stdexcept>
namespace encfs { namespace encfs {
@ -21,9 +21,9 @@ class Error : public std::runtime_error {
RLOG(ERROR) << "Assert failed: " << STR(cond); \ RLOG(ERROR) << "Assert failed: " << STR(cond); \
throw encfs::Error(STR(cond)); \ throw encfs::Error(STR(cond)); \
} \ } \
} while (0) } while (false)
void initLogging(bool enable_debug = false); void initLogging(bool enable_debug = false, bool is_daemon = false);
// This can be changed to change log action between normal and syslog logging. // This can be changed to change log action between normal and syslog logging.
// Not thread-safe, so any change must occur outside of threading context. // Not thread-safe, so any change must occur outside of threading context.

View File

@ -130,7 +130,7 @@ struct FSConfig {
: forceDecode(false), reverseEncryption(false), idleTracking(false) {} : forceDecode(false), reverseEncryption(false), idleTracking(false) {}
}; };
typedef std::shared_ptr<FSConfig> FSConfigPtr; using FSConfigPtr = std::shared_ptr<FSConfig>;
} // namespace encfs } // namespace encfs

View File

@ -22,9 +22,9 @@
namespace encfs { namespace encfs {
FileIO::FileIO() {} FileIO::FileIO() = default;
FileIO::~FileIO() {} FileIO::~FileIO() = default;
int FileIO::blockSize() const { return 1; } int FileIO::blockSize() const { return 1; }

View File

@ -18,9 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <errno.h> #include <cerrno>
#include <cinttypes>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
@ -53,29 +53,38 @@ namespace encfs {
*/ */
FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg, FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
const char *plaintextName_, const char *cipherName_) { const char *plaintextName_, const char *cipherName_,
pthread_mutex_init(&mutex, 0); uint64_t fuseFh) {
pthread_mutex_init(&mutex, nullptr);
Lock _lock(mutex); Lock _lock(mutex);
this->canary = CANARY_OK;
this->_pname = plaintextName_; this->_pname = plaintextName_;
this->_cname = cipherName_; this->_cname = cipherName_;
this->parent = parent_; this->parent = parent_;
this->fsConfig = cfg; this->fsConfig = cfg;
this->fuseFh = fuseFh;
// chain RawFileIO & CipherFileIO // chain RawFileIO & CipherFileIO
std::shared_ptr<FileIO> rawIO(new RawFileIO(_cname)); std::shared_ptr<FileIO> rawIO(new RawFileIO(_cname));
io = std::shared_ptr<FileIO>(new CipherFileIO(rawIO, fsConfig)); io = std::shared_ptr<FileIO>(new CipherFileIO(rawIO, fsConfig));
if (cfg->config->blockMACBytes || cfg->config->blockMACRandBytes) if ((cfg->config->blockMACBytes != 0) ||
(cfg->config->blockMACRandBytes != 0)) {
io = std::shared_ptr<FileIO>(new MACFileIO(io, fsConfig)); io = std::shared_ptr<FileIO>(new MACFileIO(io, fsConfig));
}
} }
FileNode::~FileNode() { FileNode::~FileNode() {
// FileNode mutex should be locked before the destructor is called // FileNode mutex should be locked before the destructor is called
// pthread_mutex_lock( &mutex ); // pthread_mutex_lock( &mutex );
canary = CANARY_DESTROYED;
_pname.assign(_pname.length(), '\0'); _pname.assign(_pname.length(), '\0');
_cname.assign(_cname.length(), '\0'); _cname.assign(_cname.length(), '\0');
io.reset(); io.reset();
@ -91,23 +100,29 @@ string FileNode::plaintextParent() const { return parentDirectory(_pname); }
static bool setIV(const std::shared_ptr<FileIO> &io, uint64_t iv) { static bool setIV(const std::shared_ptr<FileIO> &io, uint64_t iv) {
struct stat stbuf; struct stat stbuf;
if ((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode)) if ((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode)) {
return io->setIV(iv); return io->setIV(iv);
else }
return true; return true;
} }
bool FileNode::setName(const char *plaintextName_, const char *cipherName_, bool FileNode::setName(const char *plaintextName_, const char *cipherName_,
uint64_t iv, bool setIVFirst) { uint64_t iv, bool setIVFirst) {
// Lock _lock( mutex ); // Lock _lock( mutex );
if (cipherName_) VLOG(1) << "calling setIV on " << cipherName_; if (cipherName_ != nullptr) {
VLOG(1) << "calling setIV on " << cipherName_;
}
if (setIVFirst) { if (setIVFirst) {
if (fsConfig->config->externalIVChaining && !setIV(io, iv)) return false; if (fsConfig->config->externalIVChaining && !setIV(io, iv)) {
return false;
}
// now change the name.. // now change the name..
if (plaintextName_) this->_pname = plaintextName_; if (plaintextName_ != nullptr) {
if (cipherName_) { this->_pname = plaintextName_;
}
if (cipherName_ != nullptr) {
this->_cname = cipherName_; this->_cname = cipherName_;
io->setFileName(cipherName_); io->setFileName(cipherName_);
} }
@ -115,8 +130,10 @@ bool FileNode::setName(const char *plaintextName_, const char *cipherName_,
std::string oldPName = _pname; std::string oldPName = _pname;
std::string oldCName = _cname; std::string oldCName = _cname;
if (plaintextName_) this->_pname = plaintextName_; if (plaintextName_ != nullptr) {
if (cipherName_) { this->_pname = plaintextName_;
}
if (cipherName_ != nullptr) {
this->_cname = cipherName_; this->_cname = cipherName_;
io->setFileName(cipherName_); io->setFileName(cipherName_);
} }
@ -161,11 +178,14 @@ int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) {
*/ */
if (S_ISREG(mode)) { if (S_ISREG(mode)) {
res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode); res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode);
if (res >= 0) res = ::close(res); if (res >= 0) {
} else if (S_ISFIFO(mode)) res = ::close(res);
}
} else if (S_ISFIFO(mode)) {
res = ::mkfifo(_cname.c_str(), mode); res = ::mkfifo(_cname.c_str(), mode);
else } else {
res = ::mknod(_cname.c_str(), mode, rdev); res = ::mknod(_cname.c_str(), mode, rdev);
}
if (res == -1) { if (res == -1) {
int eno = errno; int eno = errno;
@ -173,8 +193,12 @@ int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) {
res = -eno; res = -eno;
} }
if (olduid >= 0) setfsuid(olduid); if (olduid >= 0) {
if (oldgid >= 0) setfsgid(oldgid); setfsuid(olduid);
}
if (oldgid >= 0) {
setfsgid(oldgid);
}
return res; return res;
} }
@ -236,21 +260,24 @@ int FileNode::sync(bool datasync) {
int fh = io->open(O_RDONLY); int fh = io->open(O_RDONLY);
if (fh >= 0) { if (fh >= 0) {
int res = -EIO; int res = -EIO;
#ifdef FDATASYNC #ifdef HAVE_FDATASYNC
if (datasync) if (datasync) {
res = fdatasync(fh); res = fdatasync(fh);
else } else {
res = fsync(fh); res = fsync(fh);
}
#else #else
(void)datasync; (void)datasync;
res = fsync(fh); res = fsync(fh);
#endif #endif
if (res == -1) res = -errno; if (res == -1) {
res = -errno;
}
return res; return res;
} else }
return fh; return fh;
} }
} // namespace encfs } // namespace encfs

View File

@ -21,6 +21,7 @@
#ifndef _FileNode_incl_ #ifndef _FileNode_incl_
#define _FileNode_incl_ #define _FileNode_incl_
#include <atomic>
#include <inttypes.h> #include <inttypes.h>
#include <memory> #include <memory>
#include <pthread.h> #include <pthread.h>
@ -33,6 +34,10 @@
#include "FileUtils.h" #include "FileUtils.h"
#include "encfs.h" #include "encfs.h"
#define CANARY_OK 0x46040975
#define CANARY_RELEASED 0x70c5610d
#define CANARY_DESTROYED 0x52cdad90
namespace encfs { namespace encfs {
class Cipher; class Cipher;
@ -42,9 +47,16 @@ class FileIO;
class FileNode { class FileNode {
public: public:
FileNode(DirNode *parent, const FSConfigPtr &cfg, const char *plaintextName, FileNode(DirNode *parent, const FSConfigPtr &cfg, const char *plaintextName,
const char *cipherName); const char *cipherName, uint64_t fuseFh);
~FileNode(); ~FileNode();
// Use an atomic type. The canary is accessed without holding any
// locks.
std::atomic<std::uint32_t> canary;
// FUSE file handle that is passed to the kernel
uint64_t fuseFh;
const char *plaintextName() const; const char *plaintextName() const;
const char *cipherName() const; const char *cipherName() const;

View File

@ -22,9 +22,10 @@
#ifdef linux #ifdef linux
#define _XOPEN_SOURCE 500 // make sure pwrite() is pulled in #define _XOPEN_SOURCE 500 // make sure pwrite() is pulled in
#endif #endif
#define _BSD_SOURCE // pick up setenv on RH7.3 #define _BSD_SOURCE // pick up setenv on RH7.3
#define _DEFAULT_SOURCE // Replaces _BSD_SOURCE
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <cctype> #include <cctype>
#include <cerrno> #include <cerrno>
#include <cstdio> #include <cstdio>
@ -111,54 +112,45 @@ struct ConfigInfo {
// backward compatible support for older versions // backward compatible support for older versions
{".encfs5", Config_V5, "ENCFS5_CONFIG", readV5Config, writeV5Config, {".encfs5", Config_V5, "ENCFS5_CONFIG", readV5Config, writeV5Config,
V5SubVersion, V5SubVersionDefault}, V5SubVersion, V5SubVersionDefault},
{".encfs4", Config_V4, NULL, readV4Config, writeV4Config, 0, 0}, {".encfs4", Config_V4, nullptr, readV4Config, writeV4Config, 0, 0},
// no longer support earlier versions // no longer support earlier versions
{".encfs3", Config_V3, NULL, NULL, NULL, 0, 0}, {".encfs3", Config_V3, nullptr, nullptr, nullptr, 0, 0},
{".encfs2", Config_Prehistoric, NULL, NULL, NULL, 0, 0}, {".encfs2", Config_Prehistoric, nullptr, nullptr, nullptr, 0, 0},
{".encfs", Config_Prehistoric, NULL, NULL, NULL, 0, 0}, {".encfs", Config_Prehistoric, nullptr, nullptr, nullptr, 0, 0},
{NULL, Config_None, NULL, NULL, NULL, 0, 0}}; {nullptr, Config_None, nullptr, nullptr, nullptr, 0, 0}};
EncFS_Root::EncFS_Root() {} EncFS_Root::EncFS_Root() = default;
EncFS_Root::~EncFS_Root() {} EncFS_Root::~EncFS_Root() = default;
bool fileExists(const char *fileName) { bool fileExists(const char *fileName) {
struct stat buf; struct stat buf;
if (!lstat(fileName, &buf)) { return lstat(fileName, &buf) == 0;
return true;
} else {
// XXX show perror?
return false;
}
} }
bool isDirectory(const char *fileName) { bool isDirectory(const char *fileName) {
struct stat buf; struct stat buf;
if (!lstat(fileName, &buf)) { if (lstat(fileName, &buf) == 0) {
return S_ISDIR(buf.st_mode); return S_ISDIR(buf.st_mode);
} else {
return false;
} }
return false;
} }
bool isAbsolutePath(const char *fileName) { bool isAbsolutePath(const char *fileName) {
if (fileName && fileName[0] != '\0' && fileName[0] == '/') return (fileName != nullptr) && fileName[0] != '\0' && fileName[0] == '/';
return true;
else
return false;
} }
const char *lastPathElement(const char *name) { const char *lastPathElement(const char *name) {
const char *loc = strrchr(name, '/'); const char *loc = strrchr(name, '/');
return loc ? loc + 1 : name; return loc != nullptr ? loc + 1 : name;
} }
std::string parentDirectory(const std::string &path) { std::string parentDirectory(const std::string &path) {
size_t last = path.find_last_of('/'); size_t last = path.find_last_of('/');
if (last == string::npos) if (last == string::npos) {
return string(""); return string("");
else }
return path.substr(0, last); return path.substr(0, last);
} }
bool userAllowMkdir(const char *path, mode_t mode) { bool userAllowMkdir(const char *path, mode_t mode) {
@ -171,7 +163,7 @@ bool userAllowMkdir(int promptno, const char *path, mode_t mode) {
// xgroup(setup) // xgroup(setup)
cerr << autosprintf( cerr << autosprintf(
_("The directory \"%s\" does not exist. Should it be created? " _("The directory \"%s\" does not exist. Should it be created? "
"(y,n) "), "(y,N) "),
path); path);
char answer[10]; char answer[10];
char *res; char *res;
@ -188,18 +180,17 @@ bool userAllowMkdir(int promptno, const char *path, mode_t mode) {
} }
res = fgets(answer, sizeof(answer), stdin); res = fgets(answer, sizeof(answer), stdin);
if (res != 0 && toupper(answer[0]) == 'Y') { if (res != nullptr && toupper(answer[0]) == 'Y') {
int result = mkdir(path, mode); int result = mkdir(path, mode);
if (result < 0) { if (result < 0) {
perror(_("Unable to create directory: ")); perror(_("Unable to create directory: "));
return false; return false;
} else }
return true; return true;
} else {
// Directory not created, by user request
cerr << _("Directory not created.") << "\n";
return false;
} }
// Directory not created, by user request
cerr << _("Directory not created.") << "\n";
return false;
} }
/** /**
@ -207,7 +198,7 @@ bool userAllowMkdir(int promptno, const char *path, mode_t mode) {
*/ */
ConfigType readConfig_load(ConfigInfo *nm, const char *path, ConfigType readConfig_load(ConfigInfo *nm, const char *path,
EncFSConfig *config) { EncFSConfig *config) {
if (nm->loadFunc) { if (nm->loadFunc != nullptr) {
try { try {
if ((*nm->loadFunc)(path, config, nm)) { if ((*nm->loadFunc)(path, config, nm)) {
config->cfgType = nm->type; config->cfgType = nm->type;
@ -233,11 +224,11 @@ ConfigType readConfig_load(ConfigInfo *nm, const char *path,
*/ */
ConfigType readConfig(const string &rootDir, EncFSConfig *config) { ConfigType readConfig(const string &rootDir, EncFSConfig *config) {
ConfigInfo *nm = ConfigFileMapping; ConfigInfo *nm = ConfigFileMapping;
while (nm->fileName) { while (nm->fileName != nullptr) {
// allow environment variable to override default config path // allow environment variable to override default config path
if (nm->environmentOverride != NULL) { if (nm->environmentOverride != nullptr) {
char *envFile = getenv(nm->environmentOverride); char *envFile = getenv(nm->environmentOverride);
if (envFile != NULL) { if (envFile != nullptr) {
if (!fileExists(envFile)) { if (!fileExists(envFile)) {
RLOG(ERROR) RLOG(ERROR)
<< "fatal: config file specified by environment does not exist: " << "fatal: config file specified by environment does not exist: "
@ -249,8 +240,9 @@ ConfigType readConfig(const string &rootDir, EncFSConfig *config) {
} }
// the standard place to look is in the root directory // the standard place to look is in the root directory
string path = rootDir + nm->fileName; string path = rootDir + nm->fileName;
if (fileExists(path.c_str())) if (fileExists(path.c_str())) {
return readConfig_load(nm, path.c_str(), config); return readConfig_load(nm, path.c_str(), config);
}
++nm; ++nm;
} }
@ -323,7 +315,7 @@ bool readV6Config(const char *configFile, EncFSConfig *cfg, ConfigInfo *info) {
int encodedSize; int encodedSize;
config->read("encodedKeySize", &encodedSize); config->read("encodedKeySize", &encodedSize);
unsigned char *key = new unsigned char[encodedSize]; auto *key = new unsigned char[encodedSize];
config->readB64("encodedKeyData", key, encodedSize); config->readB64("encodedKeyData", key, encodedSize);
cfg->assignKeyData(key, encodedSize); cfg->assignKeyData(key, encodedSize);
delete[] key; delete[] key;
@ -331,7 +323,7 @@ bool readV6Config(const char *configFile, EncFSConfig *cfg, ConfigInfo *info) {
if (cfg->subVersion >= 20080816) { if (cfg->subVersion >= 20080816) {
int saltLen; int saltLen;
config->read("saltLen", &saltLen); config->read("saltLen", &saltLen);
unsigned char *salt = new unsigned char[saltLen]; auto *salt = new unsigned char[saltLen];
config->readB64("saltData", salt, saltLen); config->readB64("saltData", salt, saltLen);
cfg->assignSaltData(salt, saltLen); cfg->assignSaltData(salt, saltLen);
delete[] salt; delete[] salt;
@ -445,13 +437,15 @@ bool saveConfig(ConfigType type, const string &rootDir,
bool ok = false; bool ok = false;
ConfigInfo *nm = ConfigFileMapping; ConfigInfo *nm = ConfigFileMapping;
while (nm->fileName) { while (nm->fileName != nullptr) {
if (nm->type == type && nm->saveFunc) { if (nm->type == type && (nm->saveFunc != nullptr)) {
string path = rootDir + nm->fileName; string path = rootDir + nm->fileName;
if (nm->environmentOverride != NULL) { if (nm->environmentOverride != nullptr) {
// use environment file if specified.. // use environment file if specified..
const char *envFile = getenv(nm->environmentOverride); const char *envFile = getenv(nm->environmentOverride);
if (envFile != NULL) path.assign(envFile); if (envFile != nullptr) {
path.assign(envFile);
}
} }
try { try {
@ -536,12 +530,12 @@ bool writeV6Config(const char *configFile, const EncFSConfig *cfg) {
addEl(doc, config, "nameAlg", cfg->nameIface); addEl(doc, config, "nameAlg", cfg->nameIface);
addEl(doc, config, "keySize", cfg->keySize); addEl(doc, config, "keySize", cfg->keySize);
addEl(doc, config, "blockSize", cfg->blockSize); addEl(doc, config, "blockSize", cfg->blockSize);
addEl(doc, config, "uniqueIV", cfg->uniqueIV); addEl(doc, config, "uniqueIV", (int)cfg->uniqueIV);
addEl(doc, config, "chainedNameIV", cfg->chainedNameIV); addEl(doc, config, "chainedNameIV", (int)cfg->chainedNameIV);
addEl(doc, config, "externalIVChaining", cfg->externalIVChaining); addEl(doc, config, "externalIVChaining", (int)cfg->externalIVChaining);
addEl(doc, config, "blockMACBytes", cfg->blockMACBytes); addEl(doc, config, "blockMACBytes", cfg->blockMACBytes);
addEl(doc, config, "blockMACRandBytes", cfg->blockMACRandBytes); addEl(doc, config, "blockMACRandBytes", cfg->blockMACRandBytes);
addEl(doc, config, "allowHoles", cfg->allowHoles); addEl(doc, config, "allowHoles", (int)cfg->allowHoles);
addEl(doc, config, "encodedKeySize", (int)cfg->keyData.size()); addEl(doc, config, "encodedKeySize", (int)cfg->keyData.size());
addEl(doc, config, "encodedKeyData", cfg->keyData); addEl(doc, config, "encodedKeyData", cfg->keyData);
addEl(doc, config, "saltLen", (int)cfg->salt.size()); addEl(doc, config, "saltLen", (int)cfg->salt.size());
@ -592,7 +586,8 @@ static Cipher::CipherAlgorithm findCipherAlgorithm(const char *name,
Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList();
Cipher::AlgorithmList::const_iterator it; Cipher::AlgorithmList::const_iterator it;
for (it = algorithms.begin(); it != algorithms.end(); ++it) { for (it = algorithms.begin(); it != algorithms.end(); ++it) {
if (!strcmp(name, it->name.c_str()) && it->keyLength.allowed(keySize)) { if ((strcmp(name, it->name.c_str()) == 0) &&
it->keyLength.allowed(keySize)) {
return *it; return *it;
} }
} }
@ -649,7 +644,7 @@ static Cipher::CipherAlgorithm selectCipherAlgorithm() {
cout << "\n" << _("Enter the number corresponding to your choice: "); cout << "\n" << _("Enter the number corresponding to your choice: ");
char answer[10]; char answer[10];
char *res = fgets(answer, sizeof(answer), stdin); char *res = fgets(answer, sizeof(answer), stdin);
int cipherNum = (res == 0 ? 0 : atoi(answer)); int cipherNum = (res == nullptr ? 0 : atoi(answer));
cout << "\n"; cout << "\n";
if (cipherNum < 1 || cipherNum > (int)algorithms.size()) { if (cipherNum < 1 || cipherNum > (int)algorithms.size()) {
@ -658,8 +653,9 @@ static Cipher::CipherAlgorithm selectCipherAlgorithm() {
} }
it = algorithms.begin(); it = algorithms.begin();
while (--cipherNum) // numbering starts at 1 while (--cipherNum != 0) { // numbering starts at 1
++it; ++it;
}
Cipher::CipherAlgorithm alg = *it; Cipher::CipherAlgorithm alg = *it;
@ -692,7 +688,7 @@ static Interface selectNameCoding() {
cout << "\n" << _("Enter the number corresponding to your choice: "); cout << "\n" << _("Enter the number corresponding to your choice: ");
char answer[10]; char answer[10];
char *res = fgets(answer, sizeof(answer), stdin); char *res = fgets(answer, sizeof(answer), stdin);
int algNum = (res == 0 ? 0 : atoi(answer)); int algNum = (res == nullptr ? 0 : atoi(answer));
cout << "\n"; cout << "\n";
if (algNum < 1 || algNum > (int)algorithms.size()) { if (algNum < 1 || algNum > (int)algorithms.size()) {
@ -701,8 +697,9 @@ static Interface selectNameCoding() {
} }
it = algorithms.begin(); it = algorithms.begin();
while (--algNum) // numbering starts at 1 while (--algNum != 0) { // numbering starts at 1
++it; ++it;
}
// xgroup(setup) // xgroup(setup)
cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str()) cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str())
@ -737,13 +734,17 @@ static int selectKeySize(const Cipher::CipherAlgorithm &alg) {
if (numAvail < 5) { if (numAvail < 5) {
// show them all // show them all
for (int i = 0; i <= numAvail; ++i) { for (int i = 0; i <= numAvail; ++i) {
if (i) cout << ", "; if (i != 0) {
cout << ", ";
}
cout << alg.keyLength.min() + i * alg.keyLength.inc(); cout << alg.keyLength.min() + i * alg.keyLength.inc();
} }
} else { } else {
// partial // partial
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
if (i) cout << ", "; if (i != 0) {
cout << ", ";
}
cout << alg.keyLength.min() + i * alg.keyLength.inc(); cout << alg.keyLength.min() + i * alg.keyLength.inc();
} }
cout << " ... " << alg.keyLength.max() - alg.keyLength.inc(); cout << " ... " << alg.keyLength.max() - alg.keyLength.inc();
@ -754,7 +755,7 @@ static int selectKeySize(const Cipher::CipherAlgorithm &alg) {
char answer[10]; char answer[10];
char *res = fgets(answer, sizeof(answer), stdin); char *res = fgets(answer, sizeof(answer), stdin);
int keySize = (res == 0 ? 0 : atoi(answer)); int keySize = (res == nullptr ? 0 : atoi(answer));
cout << "\n"; cout << "\n";
keySize = alg.keyLength.closest(keySize); keySize = alg.keyLength.closest(keySize);
@ -794,7 +795,9 @@ static int selectBlockSize(const Cipher::CipherAlgorithm &alg) {
char *res = fgets(answer, sizeof(answer), stdin); char *res = fgets(answer, sizeof(answer), stdin);
cout << "\n"; cout << "\n";
if (res != 0 && atoi(answer) >= alg.blockSize.min()) blockSize = atoi(answer); if (res != nullptr && atoi(answer) >= alg.blockSize.min()) {
blockSize = atoi(answer);
}
blockSize = alg.blockSize.closest(blockSize); blockSize = alg.blockSize.closest(blockSize);
@ -816,10 +819,11 @@ static bool boolDefault(const char *prompt, bool defaultValue) {
string yesno; string yesno;
if (defaultValue == true) if (defaultValue) {
yesno = "[y]/n: "; yesno = "[y]/n: ";
else } else {
yesno = "y/[n]: "; yesno = "y/[n]: ";
}
string response; string response;
bool value; bool value;
@ -831,10 +835,12 @@ static bool boolDefault(const char *prompt, bool defaultValue) {
if (cin.fail() || response == "") { if (cin.fail() || response == "") {
value = defaultValue; value = defaultValue;
break; break;
} else if (response == "y") { }
if (response == "y") {
value = true; value = true;
break; break;
} else if (response == "n") { }
if (response == "n") {
value = false; value = false;
break; break;
} }
@ -873,10 +879,11 @@ static void selectBlockMAC(int *macBytes, int *macRandBytes, bool forceMac) {
addMAC = true; addMAC = true;
} }
if (addMAC) if (addMAC) {
*macBytes = 8; *macBytes = 8;
else } else {
*macBytes = 0; *macBytes = 0;
}
// xgroup(setup) // xgroup(setup)
cout << _( cout << _(
@ -893,9 +900,13 @@ static void selectBlockMAC(int *macBytes, int *macRandBytes, bool forceMac) {
char *res = fgets(answer, sizeof(answer), stdin); char *res = fgets(answer, sizeof(answer), stdin);
cout << "\n"; cout << "\n";
randSize = (res == 0 ? 0 : atoi(answer)); randSize = (res == nullptr ? 0 : atoi(answer));
if (randSize < 0) randSize = 0; if (randSize < 0) {
if (randSize > 8) randSize = 8; randSize = 0;
}
if (randSize > 8) {
randSize = 8;
}
*macRandBytes = randSize; *macRandBytes = randSize;
} }
@ -956,9 +967,7 @@ RootPtr createV6Config(EncFS_Context *ctx,
const std::string passwordProgram = opts->passwordProgram; const std::string passwordProgram = opts->passwordProgram;
bool useStdin = opts->useStdin; bool useStdin = opts->useStdin;
bool reverseEncryption = opts->reverseEncryption; bool reverseEncryption = opts->reverseEncryption;
ConfigMode configMode = (useStdin && ConfigMode configMode = opts->configMode;
opts->configMode == Config_Prompt) ? Config_Standard
: opts->configMode;
bool annotate = opts->annotate; bool annotate = opts->annotate;
RootPtr rootInfo; RootPtr rootInfo;
@ -978,7 +987,9 @@ RootPtr createV6Config(EncFS_Context *ctx,
" anything else, or an empty line will select standard mode.\n" " anything else, or an empty line will select standard mode.\n"
"?> "); "?> ");
if (annotate) cerr << "$PROMPT$ config_option" << endl; if (annotate) {
cerr << "$PROMPT$ config_option" << endl;
}
char *res = fgets(answer, sizeof(answer), stdin); char *res = fgets(answer, sizeof(answer), stdin);
(void)res; (void)res;
@ -1024,7 +1035,7 @@ RootPtr createV6Config(EncFS_Context *ctx,
alg = findCipherAlgorithm("AES", keySize); alg = findCipherAlgorithm("AES", keySize);
// If case-insensitive system, opt for Block32 filename encoding // If case-insensitive system, opt for Block32 filename encoding
#if defined(__APPLE__) || defined(WIN32) #if DEFAULT_CASE_INSENSITIVE
nameIOIface = BlockNameIO::CurrentInterface(true); nameIOIface = BlockNameIO::CurrentInterface(true);
#else #else
nameIOIface = BlockNameIO::CurrentInterface(); nameIOIface = BlockNameIO::CurrentInterface();
@ -1053,6 +1064,14 @@ RootPtr createV6Config(EncFS_Context *ctx,
if (opts->requireMac) { if (opts->requireMac) {
blockMACBytes = 8; blockMACBytes = 8;
} }
if (reverseEncryption) {
/* Reverse mounts are read-only by default (set in main.cpp).
* If uniqueIV is off, writing can be allowed, because there
* is no header that could be overwritten */
if (!uniqueIV) {
opts->readOnly = false;
}
}
} }
if (answer[0] == 'x' || alg.name.empty()) { if (answer[0] == 'x' || alg.name.empty()) {
@ -1079,13 +1098,15 @@ RootPtr createV6Config(EncFS_Context *ctx,
/* Reverse mounts are read-only by default (set in main.cpp). /* Reverse mounts are read-only by default (set in main.cpp).
* If uniqueIV is off, writing can be allowed, because there * If uniqueIV is off, writing can be allowed, because there
* is no header that could be overwritten */ * is no header that could be overwritten */
if (uniqueIV == false) opts->readOnly = false; if (!uniqueIV) {
opts->readOnly = false;
}
} else { } else {
chainedIV = selectChainedIV(); chainedIV = selectChainedIV();
uniqueIV = selectUniqueIV(true); uniqueIV = selectUniqueIV(true);
if (chainedIV && uniqueIV) if (chainedIV && uniqueIV) {
externalIV = selectExternalChainedIV(); externalIV = selectExternalChainedIV();
else { } else {
// xgroup(setup) // xgroup(setup)
cout << _("External chained IV disabled, as both 'IV chaining'\n" cout << _("External chained IV disabled, as both 'IV chaining'\n"
"and 'unique IV' features are required for this option.") "and 'unique IV' features are required for this option.")
@ -1103,10 +1124,9 @@ RootPtr createV6Config(EncFS_Context *ctx,
_("Unable to instanciate cipher %s, key size %i, block size %i"), _("Unable to instanciate cipher %s, key size %i, block size %i"),
alg.name.c_str(), keySize, blockSize); alg.name.c_str(), keySize, blockSize);
return rootInfo; return rootInfo;
} else {
VLOG(1) << "Using cipher " << alg.name << ", key size " << keySize
<< ", block size " << blockSize;
} }
VLOG(1) << "Using cipher " << alg.name << ", key size " << keySize
<< ", block size " << blockSize;
std::shared_ptr<EncFSConfig> config(new EncFSConfig); std::shared_ptr<EncFSConfig> config(new EncFSConfig);
@ -1156,7 +1176,7 @@ RootPtr createV6Config(EncFS_Context *ctx,
"later using encfsctl.\n\n"); "later using encfsctl.\n\n");
int encodedKeySize = cipher->encodedKeySize(); int encodedKeySize = cipher->encodedKeySize();
unsigned char *encodedKey = new unsigned char[encodedKeySize]; auto *encodedKey = new unsigned char[encodedKeySize];
CipherKey volumeKey = cipher->newRandomKey(); CipherKey volumeKey = cipher->newRandomKey();
@ -1164,15 +1184,15 @@ RootPtr createV6Config(EncFS_Context *ctx,
CipherKey userKey; CipherKey userKey;
VLOG(1) << "useStdin: " << useStdin; VLOG(1) << "useStdin: " << useStdin;
if (useStdin) { if (useStdin) {
if (annotate) cerr << "$PROMPT$ new_passwd" << endl; if (annotate) {
cerr << "$PROMPT$ new_passwd" << endl;
}
userKey = config->getUserKey(useStdin); userKey = config->getUserKey(useStdin);
} else if (!passwordProgram.empty()) } else if (!passwordProgram.empty()) {
userKey = config->getUserKey(passwordProgram, rootDir); userKey = config->getUserKey(passwordProgram, rootDir);
else } else {
userKey = config->getNewUserKey(); userKey = config->getNewUserKey();
}
if (userKey == nullptr)
return rootInfo;
cipher->writeKey(volumeKey, encodedKey, userKey); cipher->writeKey(volumeKey, encodedKey, userKey);
userKey.reset(); userKey.reset();
@ -1214,11 +1234,10 @@ RootPtr createV6Config(EncFS_Context *ctx,
fsConfig->idleTracking = enableIdleTracking; fsConfig->idleTracking = enableIdleTracking;
fsConfig->opts = opts; fsConfig->opts = opts;
rootInfo = RootPtr(new EncFS_Root); rootInfo = std::make_shared<encfs::EncFS_Root>();
rootInfo->cipher = cipher; rootInfo->cipher = cipher;
rootInfo->volumeKey = volumeKey; rootInfo->volumeKey = volumeKey;
rootInfo->root = rootInfo->root = std::make_shared<DirNode>(ctx, rootDir, fsConfig);
std::shared_ptr<DirNode>(new DirNode(ctx, rootDir, fsConfig));
return rootInfo; return rootInfo;
} }
@ -1232,17 +1251,18 @@ void showFSInfo(const EncFSConfig *config) {
config->cipherIface.name().c_str(), config->cipherIface.current(), config->cipherIface.name().c_str(), config->cipherIface.current(),
config->cipherIface.revision(), config->cipherIface.age()); config->cipherIface.revision(), config->cipherIface.age());
// check if we support this interface.. // check if we support this interface..
if (!cipher) if (!cipher) {
cout << _(" (NOT supported)\n"); cout << _(" (NOT supported)\n");
else { } else {
// if we're using a newer interface, show the version number // if we're using a newer interface, show the version number
if (config->cipherIface != cipher->interface()) { if (config->cipherIface != cipher->interface()) {
Interface iface = cipher->interface(); Interface iface = cipher->interface();
// xgroup(diag) // xgroup(diag)
cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.current(), cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.current(),
iface.revision(), iface.age()); iface.revision(), iface.age());
} else } else {
cout << "\n"; cout << "\n";
}
} }
} }
{ {
@ -1264,8 +1284,9 @@ void showFSInfo(const EncFSConfig *config) {
Interface iface = nameCoder->interface(); Interface iface = nameCoder->interface();
cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.current(), cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.current(),
iface.revision(), iface.age()); iface.revision(), iface.age());
} else } else {
cout << "\n"; cout << "\n";
}
} }
} }
{ {
@ -1274,17 +1295,18 @@ void showFSInfo(const EncFSConfig *config) {
if (!cipher) { if (!cipher) {
// xgroup(diag) // xgroup(diag)
cout << _(" (NOT supported)\n"); cout << _(" (NOT supported)\n");
} else } else {
cout << "\n"; cout << "\n";
}
} }
if (config->kdfIterations > 0 && config->salt.size() > 0) { if (config->kdfIterations > 0 && !config->salt.empty()) {
cout << autosprintf(_("Using PBKDF2, with %i iterations"), cout << autosprintf(_("Using PBKDF2, with %i iterations"),
config->kdfIterations) config->kdfIterations)
<< "\n"; << "\n";
cout << autosprintf(_("Salt Size: %i bits"), (int)(8 * config->salt.size())) cout << autosprintf(_("Salt Size: %i bits"), (int)(8 * config->salt.size()))
<< "\n"; << "\n";
} }
if (config->blockMACBytes || config->blockMACRandBytes) { if ((config->blockMACBytes != 0) || (config->blockMACRandBytes != 0)) {
if (config->subVersion < 20040813) { if (config->subVersion < 20040813) {
cout << autosprintf( cout << autosprintf(
// xgroup(diag) // xgroup(diag)
@ -1353,14 +1375,19 @@ CipherKey EncFSConfig::makeKey(const char *password, int passwdLen) {
CipherKey userKey; CipherKey userKey;
std::shared_ptr<Cipher> cipher = getCipher(); std::shared_ptr<Cipher> cipher = getCipher();
if (passwdLen == 0) {
cerr << _("fatal: zero-length passwords are not allowed\n");
exit(1);
}
// if no salt is set and we're creating a new password for a new // if no salt is set and we're creating a new password for a new
// FS type, then initialize salt.. // FS type, then initialize salt..
if (salt.size() == 0 && kdfIterations == 0 && cfgType >= Config_V6) { if (salt.empty() && kdfIterations == 0 && cfgType >= Config_V6) {
// upgrade to using salt // upgrade to using salt
salt.resize(20); salt.resize(20);
} }
if (salt.size() > 0) { if (!salt.empty()) {
// if iterations isn't known, then we're creating a new key, so // if iterations isn't known, then we're creating a new key, so
// randomize the salt.. // randomize the salt..
if (kdfIterations == 0 && if (kdfIterations == 0 &&
@ -1385,8 +1412,9 @@ CipherKey EncFSConfig::getUserKey(bool useStdin) {
if (useStdin) { if (useStdin) {
res = fgets(passBuf, sizeof(passBuf), stdin); res = fgets(passBuf, sizeof(passBuf), stdin);
// Kill the trailing newline. // Kill the trailing newline.
if (passBuf[strlen(passBuf) - 1] == '\n') if (passBuf[strlen(passBuf) - 1] == '\n') {
passBuf[strlen(passBuf) - 1] = '\0'; passBuf[strlen(passBuf) - 1] = '\0';
}
} else { } else {
// xgroup(common) // xgroup(common)
res = readpassphrase(_("EncFS Password: "), passBuf, sizeof(passBuf), res = readpassphrase(_("EncFS Password: "), passBuf, sizeof(passBuf),
@ -1394,10 +1422,12 @@ CipherKey EncFSConfig::getUserKey(bool useStdin) {
} }
CipherKey userKey; CipherKey userKey;
if (!res) if (res == nullptr) {
cerr << _("Zero length password not allowed\n"); cerr << _("fatal: error reading password\n");
else exit(1);
} else {
userKey = makeKey(passBuf, strlen(passBuf)); userKey = makeKey(passBuf, strlen(passBuf));
}
memset(passBuf, 0, sizeof(passBuf)); memset(passBuf, 0, sizeof(passBuf));
@ -1408,21 +1438,23 @@ std::string readPassword(int FD) {
char buffer[1024]; char buffer[1024];
string result; string result;
while (1) { while (true) {
ssize_t rdSize = recv(FD, buffer, sizeof(buffer), 0); ssize_t rdSize = recv(FD, buffer, sizeof(buffer), 0);
if (rdSize > 0) { if (rdSize > 0) {
result.append(buffer, rdSize); result.append(buffer, rdSize);
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
} else } else {
break; break;
}
} }
// chop off trailing "\n" if present.. // chop off trailing "\n" if present..
// This is done so that we can use standard programs like ssh-askpass // This is done so that we can use standard programs like ssh-askpass
// without modification, as it returns trailing newline.. // without modification, as it returns trailing newline..
if (!result.empty() && result[result.length() - 1] == '\n') if (!result.empty() && result[result.length() - 1] == '\n') {
result.resize(result.length() - 1); result.resize(result.length() - 1);
}
return result; return result;
} }
@ -1454,7 +1486,7 @@ CipherKey EncFSConfig::getUserKey(const std::string &passProg,
argv[0] = "/bin/sh"; argv[0] = "/bin/sh";
argv[1] = "-c"; argv[1] = "-c";
argv[2] = passProg.c_str(); argv[2] = passProg.c_str();
argv[3] = 0; argv[3] = nullptr;
// child process.. run the command and send output to fds[0] // child process.. run the command and send output to fds[0]
close(fds[1]); // we don't use the other half.. close(fds[1]); // we don't use the other half..
@ -1492,7 +1524,7 @@ CipherKey EncFSConfig::getUserKey(const std::string &passProg,
string password = readPassword(fds[1]); string password = readPassword(fds[1]);
close(fds[1]); close(fds[1]);
waitpid(pid, NULL, 0); waitpid(pid, nullptr, 0);
// convert to key.. // convert to key..
result = makeKey(password.c_str(), password.length()); result = makeKey(password.c_str(), password.length());
@ -1516,7 +1548,8 @@ CipherKey EncFSConfig::getNewUserKey() {
char *res2 = readpassphrase(_("Verify Encfs Password: "), passBuf2, char *res2 = readpassphrase(_("Verify Encfs Password: "), passBuf2,
sizeof(passBuf2) - 1, RPP_ECHO_OFF); sizeof(passBuf2) - 1, RPP_ECHO_OFF);
if (res1 && res2 && !strcmp(passBuf, passBuf2)) { if ((res1 != nullptr) && (res2 != nullptr) &&
(strcmp(passBuf, passBuf2) == 0)) {
userKey = makeKey(passBuf, strlen(passBuf)); userKey = makeKey(passBuf, strlen(passBuf));
} else { } else {
// xgroup(common) -- probably not common, but group with the others // xgroup(common) -- probably not common, but group with the others
@ -1551,7 +1584,9 @@ RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts) {
/* Reverse mounts are read-only by default (set in main.cpp). /* Reverse mounts are read-only by default (set in main.cpp).
* If uniqueIV is off, writing can be allowed, because there * If uniqueIV is off, writing can be allowed, because there
* is no header that could be overwritten */ * is no header that could be overwritten */
if (config->uniqueIV == false) opts->readOnly = false; if (!config->uniqueIV) {
opts->readOnly = false;
}
} }
// first, instanciate the cipher. // first, instanciate the cipher.
@ -1567,7 +1602,7 @@ RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts) {
} }
if (opts->delayMount) { if (opts->delayMount) {
rootInfo = RootPtr(new EncFS_Root); rootInfo = std::make_shared<encfs::EncFS_Root>();
rootInfo->cipher = cipher; rootInfo->cipher = cipher;
rootInfo->root = std::shared_ptr<DirNode>(); rootInfo->root = std::shared_ptr<DirNode>();
return rootInfo; return rootInfo;
@ -1578,12 +1613,17 @@ RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts) {
if (opts->passwordProgram.empty()) { if (opts->passwordProgram.empty()) {
VLOG(1) << "useStdin: " << opts->useStdin; VLOG(1) << "useStdin: " << opts->useStdin;
if (opts->annotate) cerr << "$PROMPT$ passwd" << endl; if (opts->annotate) {
cerr << "$PROMPT$ passwd" << endl;
}
userKey = config->getUserKey(opts->useStdin); userKey = config->getUserKey(opts->useStdin);
} else } else {
userKey = config->getUserKey(opts->passwordProgram, opts->rootDir); userKey = config->getUserKey(opts->passwordProgram, opts->rootDir);
}
if (!userKey) return rootInfo; if (!userKey) {
return rootInfo;
}
VLOG(1) << "cipher key size = " << cipher->encodedKeySize(); VLOG(1) << "cipher key size = " << cipher->encodedKeySize();
// decode volume key.. // decode volume key..
@ -1623,11 +1663,10 @@ RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts) {
fsConfig->reverseEncryption = opts->reverseEncryption; fsConfig->reverseEncryption = opts->reverseEncryption;
fsConfig->opts = opts; fsConfig->opts = opts;
rootInfo = RootPtr(new EncFS_Root); rootInfo = std::make_shared<encfs::EncFS_Root>();
rootInfo->cipher = cipher; rootInfo->cipher = cipher;
rootInfo->volumeKey = volumeKey; rootInfo->volumeKey = volumeKey;
rootInfo->root = rootInfo->root = std::make_shared<DirNode>(ctx, opts->rootDir, fsConfig);
std::shared_ptr<DirNode>(new DirNode(ctx, opts->rootDir, fsConfig));
} else { } else {
if (opts->createIfNotFound) { if (opts->createIfNotFound) {
// creating a new encrypted filesystem // creating a new encrypted filesystem
@ -1645,10 +1684,9 @@ int remountFS(EncFS_Context *ctx) {
if (rootInfo) { if (rootInfo) {
ctx->setRoot(rootInfo->root); ctx->setRoot(rootInfo->root);
return 0; return 0;
} else {
RLOG(WARNING) << "Remount failed";
return -EACCES;
} }
RLOG(WARNING) << "Remount failed";
return -EACCES;
} }
} // namespace encfs } // namespace encfs

View File

@ -60,7 +60,7 @@ struct EncFS_Root {
~EncFS_Root(); ~EncFS_Root();
}; };
typedef std::shared_ptr<EncFS_Root> RootPtr; using RootPtr = std::shared_ptr<EncFS_Root>;
enum ConfigMode { Config_Prompt, Config_Standard, Config_Paranoia }; enum ConfigMode { Config_Prompt, Config_Standard, Config_Paranoia };

View File

@ -20,6 +20,8 @@
#include "Interface.h" #include "Interface.h"
#include <utility>
#include "ConfigVar.h" #include "ConfigVar.h"
#include "Error.h" #include "Error.h"
@ -28,25 +30,19 @@ namespace encfs {
Interface::Interface(const char *name_, int Current, int Revision, int Age) Interface::Interface(const char *name_, int Current, int Revision, int Age)
: _name(name_), _current(Current), _revision(Revision), _age(Age) {} : _name(name_), _current(Current), _revision(Revision), _age(Age) {}
Interface::Interface(const std::string &name_, int Current, int Revision, Interface::Interface(std::string name_, int Current, int Revision, int Age)
int Age) : _name(std::move(name_)),
: _name(name_), _current(Current), _revision(Revision), _age(Age) {} _current(Current),
_revision(Revision),
_age(Age) {}
Interface::Interface(const Interface &src) Interface::Interface(const Interface &src)
: _name(src._name),
_current(src._current), = default;
_revision(src._revision),
_age(src._age) {}
Interface::Interface() : _current(0), _revision(0), _age(0) {} Interface::Interface() : _current(0), _revision(0), _age(0) {}
Interface &Interface::operator=(const Interface &src) { Interface &Interface::operator=(const Interface &src) = default;
_name = src._name;
_current = src._current;
_revision = src._revision;
_age = src._age;
return *this;
}
const std::string &Interface::name() const { return _name; } const std::string &Interface::name() const { return _name; }
@ -87,12 +83,13 @@ static int sign( int a, int b )
#else #else
// simple, easy to check, unlikely to break due to unforseen events.. // simple, easy to check, unlikely to break due to unforseen events..
static int sign(int a, int b) { static int sign(int a, int b) {
if (a < b) if (a < b) {
return 0; return 0;
else if (a == b) }
if (a == b) {
return 1; return 1;
else }
return 2; return 2;
} }
#endif #endif
@ -111,7 +108,9 @@ bool Interface::implements(const Interface &B) const {
<< ":" << age() << ") implements " << B.name() << "(" << B.current() << ":" << age() << ") implements " << B.name() << "(" << B.current()
<< ":" << B.revision() << ")"; << ":" << B.revision() << ")";
if (name() != B.name()) return false; if (name() != B.name()) {
return false;
}
int currentDiff = current() - B.current(); int currentDiff = current() - B.current();
return (currentDiff >= 0 && currentDiff <= age()); return (currentDiff >= 0 && currentDiff <= age());
@ -120,29 +119,29 @@ bool Interface::implements(const Interface &B) const {
bool operator<(const Interface &A, const Interface &B) { bool operator<(const Interface &A, const Interface &B) {
if (A.name() == B.name()) { if (A.name() == B.name()) {
return (diffSum(A, B) < EqualVersion); return (diffSum(A, B) < EqualVersion);
} else }
return A.name() < B.name(); return A.name() < B.name();
} }
bool operator>(const Interface &A, const Interface &B) { bool operator>(const Interface &A, const Interface &B) {
if (A.name() == B.name()) { if (A.name() == B.name()) {
return (diffSum(A, B) > EqualVersion); return (diffSum(A, B) > EqualVersion);
} else }
return A.name() < B.name(); return A.name() < B.name();
} }
bool operator<=(const Interface &A, const Interface &B) { bool operator<=(const Interface &A, const Interface &B) {
if (A.name() == B.name()) { if (A.name() == B.name()) {
return (diffSum(A, B) <= EqualVersion); return (diffSum(A, B) <= EqualVersion);
} else }
return A.name() < B.name(); return A.name() < B.name();
} }
bool operator>=(const Interface &A, const Interface &B) { bool operator>=(const Interface &A, const Interface &B) {
if (A.name() == B.name()) { if (A.name() == B.name()) {
return (diffSum(A, B) >= EqualVersion); return (diffSum(A, B) >= EqualVersion);
} else }
return A.name() < B.name(); return A.name() < B.name();
} }
ConfigVar &operator<<(ConfigVar &dst, const Interface &iface) { ConfigVar &operator<<(ConfigVar &dst, const Interface &iface) {

View File

@ -37,7 +37,7 @@ class Interface {
are implemented. are implemented.
*/ */
Interface(const char *name, int Current, int Revision, int Age); Interface(const char *name, int Current, int Revision, int Age);
Interface(const std::string &name, int Current, int Revision, int Age); Interface(std::string name, int Current, int Revision, int Age);
Interface(const Interface &src); Interface(const Interface &src);
Interface(); Interface();

View File

@ -20,10 +20,11 @@
#include "MACFileIO.h" #include "MACFileIO.h"
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <cinttypes>
#include <cstring> #include <cstring>
#include <inttypes.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <utility>
#include "BlockFileIO.h" #include "BlockFileIO.h"
#include "Cipher.h" #include "Cipher.h"
@ -56,10 +57,9 @@ int dataBlockSize(const FSConfigPtr &cfg) {
cfg->config->blockMACRandBytes; cfg->config->blockMACRandBytes;
} }
MACFileIO::MACFileIO(const std::shared_ptr<FileIO> &_base, MACFileIO::MACFileIO(std::shared_ptr<FileIO> _base, const FSConfigPtr &cfg)
const FSConfigPtr &cfg)
: BlockFileIO(dataBlockSize(cfg), cfg), : BlockFileIO(dataBlockSize(cfg), cfg),
base(_base), base(std::move(_base)),
cipher(cfg->cipher), cipher(cfg->cipher),
key(cfg->key), key(cfg->key),
macBytes(cfg->config->blockMACBytes), macBytes(cfg->config->blockMACBytes),
@ -72,7 +72,7 @@ MACFileIO::MACFileIO(const std::shared_ptr<FileIO> &_base,
<< ", randBytes = " << cfg->config->blockMACRandBytes; << ", randBytes = " << cfg->config->blockMACRandBytes;
} }
MACFileIO::~MACFileIO() {} MACFileIO::~MACFileIO() = default;
Interface MACFileIO::interface() const { return MACFileIO_iface; } Interface MACFileIO::interface() const { return MACFileIO_iface; }
@ -137,7 +137,9 @@ off_t MACFileIO::getSize() const {
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
off_t size = base->getSize(); off_t size = base->getSize();
if (size > 0) size = locWithoutHeader(size, bs, headerSize); if (size > 0) {
size = locWithoutHeader(size, bs, headerSize);
}
return size; return size;
} }
@ -160,13 +162,15 @@ ssize_t MACFileIO::readOneBlock(const IORequest &req) const {
// don't store zeros if configured for zero-block pass-through // don't store zeros if configured for zero-block pass-through
bool skipBlock = true; bool skipBlock = true;
if (_allowHoles) { if (_allowHoles) {
for (int i = 0; i < readSize; ++i) for (int i = 0; i < readSize; ++i) {
if (tmp.data[i] != 0) { if (tmp.data[i] != 0) {
skipBlock = false; skipBlock = false;
break; break;
} }
} else if (macBytes > 0) }
} else if (macBytes > 0) {
skipBlock = false; skipBlock = false;
}
if (readSize > headerSize) { if (readSize > headerSize) {
if (!skipBlock) { if (!skipBlock) {
@ -200,7 +204,9 @@ ssize_t MACFileIO::readOneBlock(const IORequest &req) const {
memcpy(req.data, tmp.data + headerSize, readSize); memcpy(req.data, tmp.data + headerSize, readSize);
} else { } else {
VLOG(1) << "readSize " << readSize << " at offset " << req.offset; VLOG(1) << "readSize " << readSize << " at offset " << req.offset;
if (readSize > 0) readSize = 0; if (readSize > 0) {
readSize = 0;
}
} }
MemoryPool::release(mb); MemoryPool::release(mb);
@ -224,8 +230,9 @@ int MACFileIO::writeOneBlock(const IORequest &req) {
memset(newReq.data, 0, headerSize); memset(newReq.data, 0, headerSize);
memcpy(newReq.data + headerSize, req.data, req.dataLen); memcpy(newReq.data + headerSize, req.data, req.dataLen);
if (randBytes > 0) { if (randBytes > 0) {
if (!cipher->randomize(newReq.data + macBytes, randBytes, false)) if (!cipher->randomize(newReq.data + macBytes, randBytes, false)) {
return -EBADMSG; return -EBADMSG;
}
} }
if (macBytes > 0) { if (macBytes > 0) {
@ -251,9 +258,11 @@ int MACFileIO::truncate(off_t size) {
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
int res = BlockFileIO::truncateBase(size, 0); int res = BlockFileIO::truncateBase(size, nullptr);
if (!(res < 0)) res = base->truncate(locWithHeader(size, bs, headerSize)); if (!(res < 0)) {
res = base->truncate(locWithHeader(size, bs, headerSize));
}
return res; return res;
} }

View File

@ -44,7 +44,7 @@ class MACFileIO : public BlockFileIO {
result in a warning message from encfs -- the garbled data will still result in a warning message from encfs -- the garbled data will still
be made available.. be made available..
*/ */
MACFileIO(const std::shared_ptr<FileIO> &base, const FSConfigPtr &cfg); MACFileIO(std::shared_ptr<FileIO> base, const FSConfigPtr &cfg);
MACFileIO(); MACFileIO();
virtual ~MACFileIO(); virtual ~MACFileIO();

View File

@ -44,7 +44,7 @@ struct BlockList {
}; };
static BlockList *allocBlock(int size) { static BlockList *allocBlock(int size) {
BlockList *block = new BlockList; auto *block = new BlockList;
block->size = size; block->size = size;
block->data = BUF_MEM_new(); block->data = BUF_MEM_new();
BUF_MEM_grow(block->data, size); BUF_MEM_grow(block->data, size);
@ -61,30 +61,33 @@ static void freeBlock(BlockList *el) {
} }
static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER;
static BlockList *gMemPool = NULL; static BlockList *gMemPool = nullptr;
MemBlock MemoryPool::allocate(int size) { MemBlock MemoryPool::allocate(int size) {
pthread_mutex_lock(&gMPoolMutex); pthread_mutex_lock(&gMPoolMutex);
BlockList *parent = NULL; BlockList *parent = nullptr;
BlockList *block = gMemPool; BlockList *block = gMemPool;
// check if we already have a large enough block available.. // check if we already have a large enough block available..
while (block != NULL && block->size < size) { while (block != nullptr && block->size < size) {
parent = block; parent = block;
block = block->next; block = block->next;
} }
// unlink block from list // unlink block from list
if (block) { if (block != nullptr) {
if (!parent) if (parent == nullptr) {
gMemPool = block->next; gMemPool = block->next;
else } else {
parent->next = block->next; parent->next = block->next;
}
} }
pthread_mutex_unlock(&gMPoolMutex); pthread_mutex_unlock(&gMPoolMutex);
if (!block) block = allocBlock(size); if (block == nullptr) {
block->next = NULL; block = allocBlock(size);
}
block->next = nullptr;
MemBlock result; MemBlock result;
result.data = BLOCKDATA(block); result.data = BLOCKDATA(block);
@ -98,7 +101,7 @@ MemBlock MemoryPool::allocate(int size) {
void MemoryPool::release(const MemBlock &mb) { void MemoryPool::release(const MemBlock &mb) {
pthread_mutex_lock(&gMPoolMutex); pthread_mutex_lock(&gMPoolMutex);
BlockList *block = (BlockList *)mb.internalData; auto *block = (BlockList *)mb.internalData;
// just to be sure there's nothing important left in buffers.. // just to be sure there's nothing important left in buffers..
VALGRIND_MAKE_MEM_UNDEFINED(block->data->data, block->size); VALGRIND_MAKE_MEM_UNDEFINED(block->data->data, block->size);
@ -115,11 +118,11 @@ void MemoryPool::destroyAll() {
pthread_mutex_lock(&gMPoolMutex); pthread_mutex_lock(&gMPoolMutex);
BlockList *block = gMemPool; BlockList *block = gMemPool;
gMemPool = NULL; gMemPool = nullptr;
pthread_mutex_unlock(&gMPoolMutex); pthread_mutex_unlock(&gMPoolMutex);
while (block != NULL) { while (block != nullptr) {
BlockList *next = block->next; BlockList *next = block->next;
freeBlock(block); freeBlock(block);

View File

@ -20,7 +20,7 @@
#include "NameIO.h" #include "NameIO.h"
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <cstring> #include <cstring>
// for static build. Need to reference the modules which are registered at // for static build. Need to reference the modules which are registered at
// run-time, to ensure that the linker doesn't optimize them away. // run-time, to ensure that the linker doesn't optimize them away.
@ -55,14 +55,14 @@ struct NameIOAlg {
Interface iface; Interface iface;
}; };
typedef multimap<string, NameIOAlg> NameIOMap_t; using NameIOMap_t = multimap<string, NameIOAlg>;
static NameIOMap_t *gNameIOMap = 0; static NameIOMap_t *gNameIOMap = nullptr;
list<NameIO::Algorithm> NameIO::GetAlgorithmList(bool includeHidden) { list<NameIO::Algorithm> NameIO::GetAlgorithmList(bool includeHidden) {
AddSymbolReferences(); AddSymbolReferences();
list<Algorithm> result; list<Algorithm> result;
if (gNameIOMap) { if (gNameIOMap != nullptr) {
NameIOMap_t::const_iterator it; NameIOMap_t::const_iterator it;
NameIOMap_t::const_iterator end = gNameIOMap->end(); NameIOMap_t::const_iterator end = gNameIOMap->end();
for (it = gNameIOMap->begin(); it != end; ++it) { for (it = gNameIOMap->begin(); it != end; ++it) {
@ -83,7 +83,9 @@ list<NameIO::Algorithm> NameIO::GetAlgorithmList(bool includeHidden) {
bool NameIO::Register(const char *name, const char *description, bool NameIO::Register(const char *name, const char *description,
const Interface &iface, Constructor constructor, const Interface &iface, Constructor constructor,
bool hidden) { bool hidden) {
if (!gNameIOMap) gNameIOMap = new NameIOMap_t; if (gNameIOMap == nullptr) {
gNameIOMap = new NameIOMap_t;
}
NameIOAlg alg; NameIOAlg alg;
alg.hidden = hidden; alg.hidden = hidden;
@ -98,7 +100,7 @@ std::shared_ptr<NameIO> NameIO::New(const string &name,
const std::shared_ptr<Cipher> &cipher, const std::shared_ptr<Cipher> &cipher,
const CipherKey &key) { const CipherKey &key) {
std::shared_ptr<NameIO> result; std::shared_ptr<NameIO> result;
if (gNameIOMap) { if (gNameIOMap != nullptr) {
NameIOMap_t::const_iterator it = gNameIOMap->find(name); NameIOMap_t::const_iterator it = gNameIOMap->find(name);
if (it != gNameIOMap->end()) { if (it != gNameIOMap->end()) {
Constructor fn = it->second.constructor; Constructor fn = it->second.constructor;
@ -111,7 +113,7 @@ std::shared_ptr<NameIO> NameIO::New(const Interface &iface,
const std::shared_ptr<Cipher> &cipher, const std::shared_ptr<Cipher> &cipher,
const CipherKey &key) { const CipherKey &key) {
std::shared_ptr<NameIO> result; std::shared_ptr<NameIO> result;
if (gNameIOMap) { if (gNameIOMap != nullptr) {
NameIOMap_t::const_iterator it; NameIOMap_t::const_iterator it;
NameIOMap_t::const_iterator end = gNameIOMap->end(); NameIOMap_t::const_iterator end = gNameIOMap->end();
for (it = gNameIOMap->begin(); it != end; ++it) { for (it = gNameIOMap->begin(); it != end; ++it) {
@ -127,7 +129,7 @@ std::shared_ptr<NameIO> NameIO::New(const Interface &iface,
NameIO::NameIO() : chainedNameIV(false), reverseEncryption(false) {} NameIO::NameIO() : chainedNameIV(false), reverseEncryption(false) {}
NameIO::~NameIO() {} NameIO::~NameIO() = default;
void NameIO::setChainedNameIV(bool enable) { chainedNameIV = enable; } void NameIO::setChainedNameIV(bool enable) { chainedNameIV = enable; }
@ -143,15 +145,16 @@ std::string NameIO::recodePath(
uint64_t *iv) const { uint64_t *iv) const {
string output; string output;
while (*path) { while (*path != 0) {
if (*path == '/') { if (*path == '/') {
if (!output.empty()) // don't start the string with '/' if (!output.empty()) { // don't start the string with '/'
output += '/'; output += '/';
}
++path; ++path;
} else { } else {
bool isDotFile = (*path == '.'); bool isDotFile = (*path == '.');
const char *next = strchr(path, '/'); const char *next = strchr(path, '/');
int len = next ? next - path : strlen(path); int len = next != nullptr ? next - path : strlen(path);
// at this point we know that len > 0 // at this point we know that len > 0
if (isDotFile && (path[len - 1] == '.') && (len <= 2)) { if (isDotFile && (path[len - 1] == '.') && (len <= 2)) {
@ -162,7 +165,9 @@ std::string NameIO::recodePath(
// figure out buffer sizes // figure out buffer sizes
int approxLen = (this->*_length)(len); int approxLen = (this->*_length)(len);
if (approxLen <= 0) throw Error("Filename too small to decode"); if (approxLen <= 0) {
throw Error("Filename too small to decode");
}
int bufSize = 0; int bufSize = 0;
BUFFER_INIT_S(codeBuf, 32, (unsigned int)approxLen + 1, bufSize) BUFFER_INIT_S(codeBuf, 32, (unsigned int)approxLen + 1, bufSize)
@ -195,14 +200,18 @@ std::string NameIO::decodePath(const char *cipherPath) const {
std::string NameIO::_encodePath(const char *plaintextPath, uint64_t *iv) const { std::string NameIO::_encodePath(const char *plaintextPath, uint64_t *iv) const {
// if chaining is not enabled, then the iv pointer is not used.. // if chaining is not enabled, then the iv pointer is not used..
if (!chainedNameIV) iv = 0; if (!chainedNameIV) {
iv = nullptr;
}
return recodePath(plaintextPath, &NameIO::maxEncodedNameLen, return recodePath(plaintextPath, &NameIO::maxEncodedNameLen,
&NameIO::encodeName, iv); &NameIO::encodeName, iv);
} }
std::string NameIO::_decodePath(const char *cipherPath, uint64_t *iv) const { std::string NameIO::_decodePath(const char *cipherPath, uint64_t *iv) const {
// if chaining is not enabled, then the iv pointer is not used.. // if chaining is not enabled, then the iv pointer is not used..
if (!chainedNameIV) iv = 0; if (!chainedNameIV) {
iv = nullptr;
}
return recodePath(cipherPath, &NameIO::maxDecodedNameLen, &NameIO::decodeName, return recodePath(cipherPath, &NameIO::maxDecodedNameLen, &NameIO::decodeName,
iv); iv);
} }
@ -217,12 +226,12 @@ std::string NameIO::decodePath(const char *path, uint64_t *iv) const {
int NameIO::encodeName(const char *input, int length, char *output, int NameIO::encodeName(const char *input, int length, char *output,
int bufferLength) const { int bufferLength) const {
return encodeName(input, length, (uint64_t *)0, output, bufferLength); return encodeName(input, length, (uint64_t *)nullptr, output, bufferLength);
} }
int NameIO::decodeName(const char *input, int length, char *output, int NameIO::decodeName(const char *input, int length, char *output,
int bufferLength) const { int bufferLength) const {
return decodeName(input, length, (uint64_t *)0, output, bufferLength); return decodeName(input, length, (uint64_t *)nullptr, output, bufferLength);
} }
std::string NameIO::_encodeName(const char *plaintextName, int length) const { std::string NameIO::_encodeName(const char *plaintextName, int length) const {
@ -232,7 +241,7 @@ std::string NameIO::_encodeName(const char *plaintextName, int length) const {
BUFFER_INIT_S(codeBuf, 32, (unsigned int)approxLen + 1, bufSize) BUFFER_INIT_S(codeBuf, 32, (unsigned int)approxLen + 1, bufSize)
// code the name // code the name
int codedLen = encodeName(plaintextName, length, 0, codeBuf, bufSize); int codedLen = encodeName(plaintextName, length, nullptr, codeBuf, bufSize);
rAssert(codedLen <= approxLen); rAssert(codedLen <= approxLen);
rAssert(codeBuf[codedLen] == '\0'); rAssert(codeBuf[codedLen] == '\0');
@ -251,7 +260,7 @@ std::string NameIO::_decodeName(const char *encodedName, int length) const {
BUFFER_INIT_S(codeBuf, 32, (unsigned int)approxLen + 1, bufSize) BUFFER_INIT_S(codeBuf, 32, (unsigned int)approxLen + 1, bufSize)
// code the name // code the name
int codedLen = decodeName(encodedName, length, 0, codeBuf, bufSize); int codedLen = decodeName(encodedName, length, nullptr, codeBuf, bufSize);
rAssert(codedLen <= approxLen); rAssert(codedLen <= approxLen);
rAssert(codeBuf[codedLen] == '\0'); rAssert(codeBuf[codedLen] == '\0');

View File

@ -37,7 +37,7 @@ class Cipher;
class NameIO { class NameIO {
public: public:
typedef std::shared_ptr<NameIO> (*Constructor)( using Constructor = std::shared_ptr<NameIO> (*)(
const Interface &iface, const std::shared_ptr<Cipher> &cipher, const Interface &iface, const std::shared_ptr<Cipher> &cipher,
const CipherKey &key); const CipherKey &key);
@ -47,7 +47,7 @@ class NameIO {
Interface iface; Interface iface;
}; };
typedef std::list<Algorithm> AlgorithmList; using AlgorithmList = std::list<Algorithm>;
static AlgorithmList GetAlgorithmList(bool includeHidden = false); static AlgorithmList GetAlgorithmList(bool includeHidden = false);
static std::shared_ptr<NameIO> New(const Interface &iface, static std::shared_ptr<NameIO> New(const Interface &iface,
@ -139,7 +139,7 @@ class NameIO {
delete[] Name; \ delete[] Name; \
Name = Name##_Raw; \ Name = Name##_Raw; \
} \ } \
} while (0); } while (false);
} // namespace encfs } // namespace encfs

View File

@ -49,24 +49,24 @@ static bool NullCipher_registered = Cipher::Register(
class NullKey : public AbstractCipherKey { class NullKey : public AbstractCipherKey {
public: public:
NullKey() {} NullKey() = default;
virtual ~NullKey() {} ~NullKey() override = default;
}; };
class NullDestructor { class NullDestructor {
public: public:
NullDestructor() {} NullDestructor() = default;
NullDestructor(const NullDestructor &) {} NullDestructor(const NullDestructor &) = default;
~NullDestructor() {} ~NullDestructor() = default;
NullDestructor &operator=(const NullDestructor &) { return *this; } NullDestructor &operator=(const NullDestructor &) = default;
void operator()(NullKey *&) {} void operator()(NullKey *&) {}
}; };
std::shared_ptr<AbstractCipherKey> gNullKey(new NullKey(), NullDestructor()); std::shared_ptr<AbstractCipherKey> gNullKey(new NullKey(), NullDestructor());
NullCipher::NullCipher(const Interface &iface_) { this->iface = iface_; } NullCipher::NullCipher(const Interface &iface_) { this->iface = iface_; }
NullCipher::~NullCipher() {} NullCipher::~NullCipher() = default;
Interface NullCipher::interface() const { return iface; } Interface NullCipher::interface() const { return iface; }

View File

@ -41,9 +41,9 @@ static Interface NNIOIface("nameio/null", 1, 0, 0);
static bool NullNameIO_registered = static bool NullNameIO_registered =
NameIO::Register("Null", "No encryption of filenames", NNIOIface, NewNNIO); NameIO::Register("Null", "No encryption of filenames", NNIOIface, NewNNIO);
NullNameIO::NullNameIO() {} NullNameIO::NullNameIO() = default;
NullNameIO::~NullNameIO() {} NullNameIO::~NullNameIO() = default;
Interface NullNameIO::interface() const { return NNIOIface; } Interface NullNameIO::interface() const { return NNIOIface; }

View File

@ -21,13 +21,14 @@
#ifdef linux #ifdef linux
#define _XOPEN_SOURCE 500 // pick up pread , pwrite #define _XOPEN_SOURCE 500 // pick up pread , pwrite
#endif #endif
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <cerrno> #include <cerrno>
#include <cinttypes>
#include <cstring> #include <cstring>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <utility>
#include "Error.h" #include "Error.h"
#include "FileIO.h" #include "FileIO.h"
@ -53,8 +54,8 @@ inline void swap(int &x, int &y) {
RawFileIO::RawFileIO() RawFileIO::RawFileIO()
: knownSize(false), fileSize(0), fd(-1), oldfd(-1), canWrite(false) {} : knownSize(false), fileSize(0), fd(-1), oldfd(-1), canWrite(false) {}
RawFileIO::RawFileIO(const std::string &fileName) RawFileIO::RawFileIO(std::string fileName)
: name(fileName), : name(std::move(fileName)),
knownSize(false), knownSize(false),
fileSize(0), fileSize(0),
fd(-1), fd(-1),
@ -68,9 +69,13 @@ RawFileIO::~RawFileIO() {
swap(_fd, fd); swap(_fd, fd);
swap(_oldfd, oldfd); swap(_oldfd, oldfd);
if (_oldfd != -1) close(_oldfd); if (_oldfd != -1) {
close(_oldfd);
}
if (_fd != -1) close(_fd); if (_fd != -1) {
close(_fd);
}
} }
Interface RawFileIO::interface() const { return RawFileIO_iface; } Interface RawFileIO::interface() const { return RawFileIO_iface; }
@ -110,7 +115,7 @@ static int open_readonly_workaround(const char *path, int flags) {
it.. it..
*/ */
int RawFileIO::open(int flags) { int RawFileIO::open(int flags) {
bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY)); bool requestWrite = (((flags & O_RDWR) != 0) || ((flags & O_WRONLY) != 0));
VLOG(1) << "open call, requestWrite = " << requestWrite; VLOG(1) << "open call, requestWrite = " << requestWrite;
int result = 0; int result = 0;
@ -123,7 +128,9 @@ int RawFileIO::open(int flags) {
int finalFlags = requestWrite ? O_RDWR : O_RDONLY; int finalFlags = requestWrite ? O_RDWR : O_RDONLY;
#if defined(O_LARGEFILE) #if defined(O_LARGEFILE)
if (flags & O_LARGEFILE) finalFlags |= O_LARGEFILE; if ((flags & O_LARGEFILE) != 0) {
finalFlags |= O_LARGEFILE;
}
#else #else
#warning O_LARGEFILE not supported #warning O_LARGEFILE not supported
#endif #endif
@ -183,14 +190,12 @@ off_t RawFileIO::getSize() const {
const_cast<RawFileIO *>(this)->fileSize = stbuf.st_size; const_cast<RawFileIO *>(this)->fileSize = stbuf.st_size;
const_cast<RawFileIO *>(this)->knownSize = true; const_cast<RawFileIO *>(this)->knownSize = true;
return fileSize; return fileSize;
} else {
int eno = errno;
RLOG(ERROR) << "getSize on " << name << " failed: " << strerror(eno);
return -eno;
} }
} else { int eno = errno;
return fileSize; RLOG(ERROR) << "getSize on " << name << " failed: " << strerror(eno);
return -eno;
} }
return fileSize;
} }
ssize_t RawFileIO::read(const IORequest &req) const { ssize_t RawFileIO::read(const IORequest &req) const {
@ -209,7 +214,7 @@ ssize_t RawFileIO::read(const IORequest &req) const {
int RawFileIO::write(const IORequest &req) { int RawFileIO::write(const IORequest &req) {
rAssert(fd >= 0); rAssert(fd >= 0);
rAssert(true == canWrite); rAssert(canWrite);
int retrys = 10; int retrys = 10;
void *buf = req.data; void *buf = req.data;
@ -217,7 +222,7 @@ int RawFileIO::write(const IORequest &req) {
off_t offset = req.offset; off_t offset = req.offset;
int eno = 0; int eno = 0;
while (bytes && retrys > 0) { while ((bytes != 0) && retrys > 0) {
errno = 0; errno = 0;
ssize_t writeSize = ::pwrite(fd, buf, bytes, offset); ssize_t writeSize = ::pwrite(fd, buf, bytes, offset);
eno = errno; eno = errno;
@ -243,11 +248,15 @@ int RawFileIO::write(const IORequest &req) {
} else { } else {
if (knownSize) { if (knownSize) {
off_t last = req.offset + req.dataLen; off_t last = req.offset + req.dataLen;
if (last > fileSize) fileSize = last; if (last > fileSize) {
fileSize = last;
}
} }
return 0; //No matter how many bytes we wrote, we of course already know this. return 0; //No matter how many bytes we wrote, we of course already know this.
} }
return true;
} }
int RawFileIO::truncate(off_t size) { int RawFileIO::truncate(off_t size) {
@ -255,8 +264,9 @@ int RawFileIO::truncate(off_t size) {
if (fd >= 0 && canWrite) { if (fd >= 0 && canWrite) {
res = ::ftruncate(fd, size); res = ::ftruncate(fd, size);
} else } else {
res = ::truncate(name.c_str(), size); res = ::truncate(name.c_str(), size);
}
if (res < 0) { if (res < 0) {
int eno = errno; int eno = errno;
@ -271,10 +281,10 @@ int RawFileIO::truncate(off_t size) {
} }
if (fd >= 0 && canWrite) { if (fd >= 0 && canWrite) {
#ifdef FDATASYNC #if defined(HAVE_FDATASYNC)
::fdatasync(fd); ::fdatasync(fd);
#else #else
::fsync(fd); ::fsync(fd);
#endif #endif
} }

View File

@ -32,7 +32,7 @@ namespace encfs {
class RawFileIO : public FileIO { class RawFileIO : public FileIO {
public: public:
RawFileIO(); RawFileIO();
RawFileIO(const std::string &fileName); RawFileIO(std::string fileName);
virtual ~RawFileIO(); virtual ~RawFileIO();
virtual Interface interface() const; virtual Interface interface() const;

View File

@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <cstring> #include <cstring>
#include <openssl/crypto.h> #include <openssl/crypto.h>
#include <openssl/err.h> #include <openssl/err.h>
@ -36,8 +36,8 @@
#include "Interface.h" #include "Interface.h"
#include "Mutex.h" #include "Mutex.h"
#include "Range.h" #include "Range.h"
#include "SSL_Compat.h"
#include "SSL_Cipher.h" #include "SSL_Cipher.h"
#include "SSL_Compat.h"
#include "intl/gettext.h" #include "intl/gettext.h"
using namespace std; using namespace std;
@ -66,46 +66,51 @@ inline int MIN(int a, int b) { return (a < b) ? a : b; }
int BytesToKey(int keyLen, int ivLen, const EVP_MD *md, int BytesToKey(int keyLen, int ivLen, const EVP_MD *md,
const unsigned char *data, int dataLen, unsigned int rounds, const unsigned char *data, int dataLen, unsigned int rounds,
unsigned char *key, unsigned char *iv) { unsigned char *key, unsigned char *iv) {
if (data == NULL || dataLen == 0) if (data == nullptr || dataLen == 0) {
return 0; // OpenSSL returns nkey here, but why? It is a failure.. return 0; // OpenSSL returns nkey here, but why? It is a failure..
}
unsigned char mdBuf[EVP_MAX_MD_SIZE]; unsigned char mdBuf[EVP_MAX_MD_SIZE];
unsigned int mds = 0; unsigned int mds = 0;
int addmd = 0; int addmd = 0;
int nkey = key ? keyLen : 0; int nkey = key != nullptr ? keyLen : 0;
int niv = iv ? ivLen : 0; int niv = iv != nullptr ? ivLen : 0;
EVP_MD_CTX *cx = EVP_MD_CTX_new(); EVP_MD_CTX *cx = EVP_MD_CTX_new();
EVP_MD_CTX_init(cx); EVP_MD_CTX_init(cx);
for (;;) { for (;;) {
EVP_DigestInit_ex(cx, md, NULL); EVP_DigestInit_ex(cx, md, nullptr);
if (addmd++) EVP_DigestUpdate(cx, mdBuf, mds); if ((addmd++) != 0) {
EVP_DigestUpdate(cx, mdBuf, mds);
}
EVP_DigestUpdate(cx, data, dataLen); EVP_DigestUpdate(cx, data, dataLen);
EVP_DigestFinal_ex(cx, mdBuf, &mds); EVP_DigestFinal_ex(cx, mdBuf, &mds);
for (unsigned int i = 1; i < rounds; ++i) { for (unsigned int i = 1; i < rounds; ++i) {
EVP_DigestInit_ex(cx, md, NULL); EVP_DigestInit_ex(cx, md, nullptr);
EVP_DigestUpdate(cx, mdBuf, mds); EVP_DigestUpdate(cx, mdBuf, mds);
EVP_DigestFinal_ex(cx, mdBuf, &mds); EVP_DigestFinal_ex(cx, mdBuf, &mds);
} }
int offset = 0; int offset = 0;
int toCopy = MIN(nkey, mds - offset); int toCopy = MIN(nkey, mds - offset);
if (toCopy) { if (toCopy != 0) {
memcpy(key, mdBuf + offset, toCopy); memcpy(key, mdBuf + offset, toCopy);
key += toCopy; key += toCopy;
nkey -= toCopy; nkey -= toCopy;
offset += toCopy; offset += toCopy;
} }
toCopy = MIN(niv, mds - offset); toCopy = MIN(niv, mds - offset);
if (toCopy) { if (toCopy != 0) {
memcpy(iv, mdBuf + offset, toCopy); memcpy(iv, mdBuf + offset, toCopy);
iv += toCopy; iv += toCopy;
niv -= toCopy; niv -= toCopy;
offset += toCopy; offset += toCopy;
} }
if ((nkey == 0) && (niv == 0)) break; if ((nkey == 0) && (niv == 0)) {
break;
}
} }
EVP_MD_CTX_free(cx); EVP_MD_CTX_free(cx);
OPENSSL_cleanse(mdBuf, sizeof(mdBuf)); OPENSSL_cleanse(mdBuf, sizeof(mdBuf));
@ -125,13 +130,15 @@ int TimedPBKDF2(const char *pass, int passlen, const unsigned char *salt,
timeval start, end; timeval start, end;
for (;;) { for (;;) {
gettimeofday(&start, 0); gettimeofday(&start, nullptr);
int res = int res =
PKCS5_PBKDF2_HMAC_SHA1(pass, passlen, const_cast<unsigned char *>(salt), PKCS5_PBKDF2_HMAC_SHA1(pass, passlen, const_cast<unsigned char *>(salt),
saltlen, iter, keylen, out); saltlen, iter, keylen, out);
if (res != 1) return -1; if (res != 1) {
return -1;
}
gettimeofday(&end, 0); gettimeofday(&end, nullptr);
long delta = time_diff(end, start); long delta = time_diff(end, start);
if (delta < desiredPDFTime / 8) { if (delta < desiredPDFTime / 8) {
@ -139,8 +146,9 @@ int TimedPBKDF2(const char *pass, int passlen, const unsigned char *salt,
} else if (delta < (5 * desiredPDFTime / 6)) { } else if (delta < (5 * desiredPDFTime / 6)) {
// estimate number of iterations to get close to desired time // estimate number of iterations to get close to desired time
iter = (int)((double)iter * (double)desiredPDFTime / (double)delta); iter = (int)((double)iter * (double)desiredPDFTime / (double)delta);
} else } else {
return iter; return iter;
}
} }
} }
@ -153,6 +161,47 @@ int TimedPBKDF2(const char *pass, int passlen, const unsigned char *salt,
// - Version 3:0 adds a new IV mechanism // - Version 3:0 adds a new IV mechanism
static Interface BlowfishInterface("ssl/blowfish", 3, 0, 2); static Interface BlowfishInterface("ssl/blowfish", 3, 0, 2);
static Interface AESInterface("ssl/aes", 3, 0, 2); static Interface AESInterface("ssl/aes", 3, 0, 2);
static Interface CAMELLIAInterface("ssl/camellia",3, 0, 2);
#ifndef OPENSSL_NO_CAMELLIA
static Range CAMELLIAKeyRange(128, 256, 64);
static Range CAMELLIABlockRange(64, 4096, 16);
static std::shared_ptr<Cipher> NewCAMELLIACipher(const Interface &iface, int keyLen) {
if (keyLen <= 0) keyLen = 192;
keyLen = CAMELLIAKeyRange.closest(keyLen);
const EVP_CIPHER *blockCipher = 0;
const EVP_CIPHER *streamCipher = 0;
switch (keyLen) {
case 128:
blockCipher = EVP_camellia_128_cbc();
streamCipher = EVP_camellia_128_cfb();
break;
case 192:
blockCipher = EVP_camellia_192_cbc();
streamCipher = EVP_camellia_192_cfb();
break;
case 256:
default:
blockCipher = EVP_camellia_256_cbc();
streamCipher = EVP_camellia_256_cfb();
break;
}
return std::shared_ptr<Cipher>(new SSL_Cipher(
iface, CAMELLIAInterface, blockCipher, streamCipher, keyLen / 8 ));
}
static bool CAMELLIA_Cipher_registered =
Cipher::Register("CAMELLIA","16 byte block cipher", CAMELLIAInterface, CAMELLIAKeyRange,
CAMELLIABlockRange, NewCAMELLIACipher );
#endif
#ifndef OPENSSL_NO_BF #ifndef OPENSSL_NO_BF
@ -160,7 +209,9 @@ static Range BFKeyRange(128, 256, 32);
static Range BFBlockRange(64, 4096, 8); static Range BFBlockRange(64, 4096, 8);
static std::shared_ptr<Cipher> NewBFCipher(const Interface &iface, int keyLen) { static std::shared_ptr<Cipher> NewBFCipher(const Interface &iface, int keyLen) {
if (keyLen <= 0) keyLen = 160; if (keyLen <= 0) {
keyLen = 160;
}
keyLen = BFKeyRange.closest(keyLen); keyLen = BFKeyRange.closest(keyLen);
@ -185,12 +236,14 @@ static Range AESBlockRange(64, 4096, 16);
static std::shared_ptr<Cipher> NewAESCipher(const Interface &iface, static std::shared_ptr<Cipher> NewAESCipher(const Interface &iface,
int keyLen) { int keyLen) {
if (keyLen <= 0) keyLen = 192; if (keyLen <= 0) {
keyLen = 192;
}
keyLen = AESKeyRange.closest(keyLen); keyLen = AESKeyRange.closest(keyLen);
const EVP_CIPHER *blockCipher = 0; const EVP_CIPHER *blockCipher = nullptr;
const EVP_CIPHER *streamCipher = 0; const EVP_CIPHER *streamCipher = nullptr;
switch (keyLen) { switch (keyLen) {
case 128: case 128:
@ -238,13 +291,13 @@ class SSLKey : public AbstractCipherKey {
HMAC_CTX *mac_ctx; HMAC_CTX *mac_ctx;
SSLKey(int keySize, int ivLength); SSLKey(int keySize, int ivLength);
~SSLKey(); ~SSLKey() override;
}; };
SSLKey::SSLKey(int keySize_, int ivLength_) { SSLKey::SSLKey(int keySize_, int ivLength_) {
this->keySize = keySize_; this->keySize = keySize_;
this->ivLength = ivLength_; this->ivLength = ivLength_;
pthread_mutex_init(&mutex, 0); pthread_mutex_init(&mutex, nullptr);
buffer = (unsigned char *)OPENSSL_malloc(keySize + ivLength); buffer = (unsigned char *)OPENSSL_malloc(keySize + ivLength);
memset(buffer, 0, keySize + ivLength); memset(buffer, 0, keySize + ivLength);
@ -272,7 +325,7 @@ SSLKey::~SSLKey() {
keySize = 0; keySize = 0;
ivLength = 0; ivLength = 0;
buffer = 0; buffer = nullptr;
EVP_CIPHER_CTX_free(block_enc); EVP_CIPHER_CTX_free(block_enc);
EVP_CIPHER_CTX_free(block_dec); EVP_CIPHER_CTX_free(block_dec);
@ -295,10 +348,10 @@ void initKey(const std::shared_ptr<SSLKey> &key, const EVP_CIPHER *_blockCipher,
Lock lock(key->mutex); Lock lock(key->mutex);
// initialize the cipher context once so that we don't have to do it for // initialize the cipher context once so that we don't have to do it for
// every block.. // every block..
EVP_EncryptInit_ex(key->block_enc, _blockCipher, NULL, NULL, NULL); EVP_EncryptInit_ex(key->block_enc, _blockCipher, nullptr, nullptr, nullptr);
EVP_DecryptInit_ex(key->block_dec, _blockCipher, NULL, NULL, NULL); EVP_DecryptInit_ex(key->block_dec, _blockCipher, nullptr, nullptr, nullptr);
EVP_EncryptInit_ex(key->stream_enc, _streamCipher, NULL, NULL, NULL); EVP_EncryptInit_ex(key->stream_enc, _streamCipher, nullptr, nullptr, nullptr);
EVP_DecryptInit_ex(key->stream_dec, _streamCipher, NULL, NULL, NULL); EVP_DecryptInit_ex(key->stream_dec, _streamCipher, nullptr, nullptr, nullptr);
EVP_CIPHER_CTX_set_key_length(key->block_enc, _keySize); EVP_CIPHER_CTX_set_key_length(key->block_enc, _keySize);
EVP_CIPHER_CTX_set_key_length(key->block_dec, _keySize); EVP_CIPHER_CTX_set_key_length(key->block_dec, _keySize);
@ -310,12 +363,12 @@ void initKey(const std::shared_ptr<SSLKey> &key, const EVP_CIPHER *_blockCipher,
EVP_CIPHER_CTX_set_padding(key->stream_enc, 0); EVP_CIPHER_CTX_set_padding(key->stream_enc, 0);
EVP_CIPHER_CTX_set_padding(key->stream_dec, 0); EVP_CIPHER_CTX_set_padding(key->stream_dec, 0);
EVP_EncryptInit_ex(key->block_enc, NULL, NULL, KeyData(key), NULL); EVP_EncryptInit_ex(key->block_enc, nullptr, nullptr, KeyData(key), nullptr);
EVP_DecryptInit_ex(key->block_dec, NULL, NULL, KeyData(key), NULL); EVP_DecryptInit_ex(key->block_dec, nullptr, nullptr, KeyData(key), nullptr);
EVP_EncryptInit_ex(key->stream_enc, NULL, NULL, KeyData(key), NULL); EVP_EncryptInit_ex(key->stream_enc, nullptr, nullptr, KeyData(key), nullptr);
EVP_DecryptInit_ex(key->stream_dec, NULL, NULL, KeyData(key), NULL); EVP_DecryptInit_ex(key->stream_dec, nullptr, nullptr, KeyData(key), nullptr);
HMAC_Init_ex(key->mac_ctx, KeyData(key), _keySize, EVP_sha1(), 0); HMAC_Init_ex(key->mac_ctx, KeyData(key), _keySize, EVP_sha1(), nullptr);
} }
SSL_Cipher::SSL_Cipher(const Interface &iface_, const Interface &realIface_, SSL_Cipher::SSL_Cipher(const Interface &iface_, const Interface &realIface_,
@ -342,7 +395,7 @@ SSL_Cipher::SSL_Cipher(const Interface &iface_, const Interface &realIface_,
} }
} }
SSL_Cipher::~SSL_Cipher() {} SSL_Cipher::~SSL_Cipher() = default;
Interface SSL_Cipher::interface() const { return realIface; } Interface SSL_Cipher::interface() const { return realIface; }
@ -366,8 +419,9 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength,
if (res <= 0) { if (res <= 0) {
RLOG(WARNING) << "openssl error, PBKDF2 failed"; RLOG(WARNING) << "openssl error, PBKDF2 failed";
return CipherKey(); return CipherKey();
} else }
iterationCount = res; iterationCount = res;
} else { } else {
// known iteration length // known iteration length
if (PKCS5_PBKDF2_HMAC_SHA1( if (PKCS5_PBKDF2_HMAC_SHA1(
@ -401,9 +455,8 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) {
} }
} else { } else {
// for backward compatibility with filesystems created with 1:0 // for backward compatibility with filesystems created with 1:0
bytes = EVP_BytesToKey(_blockCipher, EVP_sha1(), NULL, EVP_BytesToKey(_blockCipher, EVP_sha1(), nullptr, (unsigned char *)password,
(unsigned char *)password, passwdLength, 16, passwdLength, 16, KeyData(key), IVData(key));
KeyData(key), IVData(key));
} }
initKey(key, _blockCipher, _streamCipher, _keySize); initKey(key, _blockCipher, _streamCipher, _keySize);
@ -425,8 +478,9 @@ CipherKey SSL_Cipher::newRandomKey() {
int saltLen = 20; int saltLen = 20;
unsigned char saltBuf[saltLen]; unsigned char saltBuf[saltLen];
if (!randomize(tmpBuf, bufLen, true) || !randomize(saltBuf, saltLen, true)) if (!randomize(tmpBuf, bufLen, true) || !randomize(saltBuf, saltLen, true)) {
return CipherKey(); return CipherKey();
}
std::shared_ptr<SSLKey> key(new SSLKey(_keySize, _ivLength)); std::shared_ptr<SSLKey> key(new SSLKey(_keySize, _ivLength));
@ -456,9 +510,9 @@ static uint64_t _checksum_64(SSLKey *key, const unsigned char *data,
unsigned char md[EVP_MAX_MD_SIZE]; unsigned char md[EVP_MAX_MD_SIZE];
unsigned int mdLen = EVP_MAX_MD_SIZE; unsigned int mdLen = EVP_MAX_MD_SIZE;
HMAC_Init_ex(key->mac_ctx, 0, 0, 0, 0); HMAC_Init_ex(key->mac_ctx, nullptr, 0, nullptr, nullptr);
HMAC_Update(key->mac_ctx, data, dataLen); HMAC_Update(key->mac_ctx, data, dataLen);
if (chainedIV) { if (chainedIV != nullptr) {
// toss in the chained IV as well // toss in the chained IV as well
uint64_t tmp = *chainedIV; uint64_t tmp = *chainedIV;
unsigned char h[8]; unsigned char h[8];
@ -476,11 +530,14 @@ static uint64_t _checksum_64(SSLKey *key, const unsigned char *data,
// chop this down to a 64bit value.. // chop this down to a 64bit value..
unsigned char h[8] = {0, 0, 0, 0, 0, 0, 0, 0}; unsigned char h[8] = {0, 0, 0, 0, 0, 0, 0, 0};
for (unsigned int i = 0; i < (mdLen - 1); ++i) for (unsigned int i = 0; i < (mdLen - 1); ++i) {
h[i % 8] ^= (unsigned char)(md[i]); h[i % 8] ^= (unsigned char)(md[i]);
}
uint64_t value = (uint64_t)h[0]; auto value = (uint64_t)h[0];
for (int i = 1; i < 8; ++i) value = (value << 8) | (uint64_t)h[i]; for (int i = 1; i < 8; ++i) {
value = (value << 8) | (uint64_t)h[i];
}
return value; return value;
} }
@ -505,9 +562,8 @@ bool SSL_Cipher::randomize(unsigned char *buf, int len,
} }
return false; return false;
} else {
return true;
} }
return true;
} }
uint64_t SSL_Cipher::MAC_64(const unsigned char *data, int len, uint64_t SSL_Cipher::MAC_64(const unsigned char *data, int len,
@ -515,7 +571,9 @@ uint64_t SSL_Cipher::MAC_64(const unsigned char *data, int len,
std::shared_ptr<SSLKey> mk = dynamic_pointer_cast<SSLKey>(key); std::shared_ptr<SSLKey> mk = dynamic_pointer_cast<SSLKey>(key);
uint64_t tmp = _checksum_64(mk.get(), data, len, chainedIV); uint64_t tmp = _checksum_64(mk.get(), data, len, chainedIV);
if (chainedIV) *chainedIV = tmp; if (chainedIV != nullptr) {
*chainedIV = tmp;
}
return tmp; return tmp;
} }
@ -529,8 +587,9 @@ CipherKey SSL_Cipher::readKey(const unsigned char *data,
// First N bytes are checksum bytes. // First N bytes are checksum bytes.
unsigned int checksum = 0; unsigned int checksum = 0;
for (int i = 0; i < KEY_CHECKSUM_BYTES; ++i) for (int i = 0; i < KEY_CHECKSUM_BYTES; ++i) {
checksum = (checksum << 8) | (unsigned int)data[i]; checksum = (checksum << 8) | (unsigned int)data[i];
}
memcpy(tmpBuf, data + KEY_CHECKSUM_BYTES, _keySize + _ivLength); memcpy(tmpBuf, data + KEY_CHECKSUM_BYTES, _keySize + _ivLength);
streamDecode(tmpBuf, _keySize + _ivLength, checksum, masterKey); streamDecode(tmpBuf, _keySize + _ivLength, checksum, masterKey);
@ -591,10 +650,7 @@ bool SSL_Cipher::compareKey(const CipherKey &A, const CipherKey &B) const {
rAssert(key1->keySize == _keySize); rAssert(key1->keySize == _keySize);
rAssert(key2->keySize == _keySize); rAssert(key2->keySize == _keySize);
if (memcmp(key1->buffer, key2->buffer, _keySize + _ivLength) != 0) return memcmp(key1->buffer, key2->buffer, _keySize + _ivLength) == 0;
return false;
else
return true;
} }
int SSL_Cipher::encodedKeySize() const { int SSL_Cipher::encodedKeySize() const {
@ -637,7 +693,7 @@ void SSL_Cipher::setIVec(unsigned char *ivec, uint64_t seed,
} }
// combine ivec and seed with HMAC // combine ivec and seed with HMAC
HMAC_Init_ex(key->mac_ctx, 0, 0, 0, 0); HMAC_Init_ex(key->mac_ctx, nullptr, 0, nullptr, nullptr);
HMAC_Update(key->mac_ctx, ivec, _ivLength); HMAC_Update(key->mac_ctx, ivec, _ivLength);
HMAC_Update(key->mac_ctx, md, 8); HMAC_Update(key->mac_ctx, md, 8);
HMAC_Final(key->mac_ctx, md, &mdLen); HMAC_Final(key->mac_ctx, md, &mdLen);
@ -694,10 +750,12 @@ static void flipBytes(unsigned char *buf, int size) {
unsigned char revBuf[64]; unsigned char revBuf[64];
int bytesLeft = size; int bytesLeft = size;
while (bytesLeft) { while (bytesLeft != 0) {
int toFlip = MIN(sizeof(revBuf), bytesLeft); int toFlip = MIN(sizeof(revBuf), bytesLeft);
for (int i = 0; i < toFlip; ++i) revBuf[i] = buf[toFlip - (i + 1)]; for (int i = 0; i < toFlip; ++i) {
revBuf[i] = buf[toFlip - (i + 1)];
}
memcpy(buf, revBuf, toFlip); memcpy(buf, revBuf, toFlip);
bytesLeft -= toFlip; bytesLeft -= toFlip;
@ -707,11 +765,15 @@ static void flipBytes(unsigned char *buf, int size) {
} }
static void shuffleBytes(unsigned char *buf, int size) { static void shuffleBytes(unsigned char *buf, int size) {
for (int i = 0; i < size - 1; ++i) buf[i + 1] ^= buf[i]; for (int i = 0; i < size - 1; ++i) {
buf[i + 1] ^= buf[i];
}
} }
static void unshuffleBytes(unsigned char *buf, int size) { static void unshuffleBytes(unsigned char *buf, int size) {
for (int i = size - 1; i; --i) buf[i] ^= buf[i - 1]; for (int i = size - 1; i != 0; --i) {
buf[i] ^= buf[i - 1];
}
} }
/** Partial blocks are encoded with a stream cipher. We make multiple passes on /** Partial blocks are encoded with a stream cipher. We make multiple passes on
@ -732,7 +794,7 @@ bool SSL_Cipher::streamEncode(unsigned char *buf, int size, uint64_t iv64,
shuffleBytes(buf, size); shuffleBytes(buf, size);
setIVec(ivec, iv64, key); setIVec(ivec, iv64, key);
EVP_EncryptInit_ex(key->stream_enc, NULL, NULL, NULL, ivec); EVP_EncryptInit_ex(key->stream_enc, nullptr, nullptr, nullptr, ivec);
EVP_EncryptUpdate(key->stream_enc, buf, &dstLen, buf, size); EVP_EncryptUpdate(key->stream_enc, buf, &dstLen, buf, size);
EVP_EncryptFinal_ex(key->stream_enc, buf + dstLen, &tmpLen); EVP_EncryptFinal_ex(key->stream_enc, buf + dstLen, &tmpLen);
@ -740,7 +802,7 @@ bool SSL_Cipher::streamEncode(unsigned char *buf, int size, uint64_t iv64,
shuffleBytes(buf, size); shuffleBytes(buf, size);
setIVec(ivec, iv64 + 1, key); setIVec(ivec, iv64 + 1, key);
EVP_EncryptInit_ex(key->stream_enc, NULL, NULL, NULL, ivec); EVP_EncryptInit_ex(key->stream_enc, nullptr, nullptr, nullptr, ivec);
EVP_EncryptUpdate(key->stream_enc, buf, &dstLen, buf, size); EVP_EncryptUpdate(key->stream_enc, buf, &dstLen, buf, size);
EVP_EncryptFinal_ex(key->stream_enc, buf + dstLen, &tmpLen); EVP_EncryptFinal_ex(key->stream_enc, buf + dstLen, &tmpLen);
@ -767,7 +829,7 @@ bool SSL_Cipher::streamDecode(unsigned char *buf, int size, uint64_t iv64,
int dstLen = 0, tmpLen = 0; int dstLen = 0, tmpLen = 0;
setIVec(ivec, iv64 + 1, key); setIVec(ivec, iv64 + 1, key);
EVP_DecryptInit_ex(key->stream_dec, NULL, NULL, NULL, ivec); EVP_DecryptInit_ex(key->stream_dec, nullptr, nullptr, nullptr, ivec);
EVP_DecryptUpdate(key->stream_dec, buf, &dstLen, buf, size); EVP_DecryptUpdate(key->stream_dec, buf, &dstLen, buf, size);
EVP_DecryptFinal_ex(key->stream_dec, buf + dstLen, &tmpLen); EVP_DecryptFinal_ex(key->stream_dec, buf + dstLen, &tmpLen);
@ -775,7 +837,7 @@ bool SSL_Cipher::streamDecode(unsigned char *buf, int size, uint64_t iv64,
flipBytes(buf, size); flipBytes(buf, size);
setIVec(ivec, iv64, key); setIVec(ivec, iv64, key);
EVP_DecryptInit_ex(key->stream_dec, NULL, NULL, NULL, ivec); EVP_DecryptInit_ex(key->stream_dec, nullptr, nullptr, nullptr, ivec);
EVP_DecryptUpdate(key->stream_dec, buf, &dstLen, buf, size); EVP_DecryptUpdate(key->stream_dec, buf, &dstLen, buf, size);
EVP_DecryptFinal_ex(key->stream_dec, buf + dstLen, &tmpLen); EVP_DecryptFinal_ex(key->stream_dec, buf + dstLen, &tmpLen);
@ -812,7 +874,7 @@ bool SSL_Cipher::blockEncode(unsigned char *buf, int size, uint64_t iv64,
int dstLen = 0, tmpLen = 0; int dstLen = 0, tmpLen = 0;
setIVec(ivec, iv64, key); setIVec(ivec, iv64, key);
EVP_EncryptInit_ex(key->block_enc, NULL, NULL, NULL, ivec); EVP_EncryptInit_ex(key->block_enc, nullptr, nullptr, nullptr, ivec);
EVP_EncryptUpdate(key->block_enc, buf, &dstLen, buf, size); EVP_EncryptUpdate(key->block_enc, buf, &dstLen, buf, size);
EVP_EncryptFinal_ex(key->block_enc, buf + dstLen, &tmpLen); EVP_EncryptFinal_ex(key->block_enc, buf + dstLen, &tmpLen);
dstLen += tmpLen; dstLen += tmpLen;
@ -847,7 +909,7 @@ bool SSL_Cipher::blockDecode(unsigned char *buf, int size, uint64_t iv64,
int dstLen = 0, tmpLen = 0; int dstLen = 0, tmpLen = 0;
setIVec(ivec, iv64, key); setIVec(ivec, iv64, key);
EVP_DecryptInit_ex(key->block_dec, NULL, NULL, NULL, ivec); EVP_DecryptInit_ex(key->block_dec, nullptr, nullptr, nullptr, ivec);
EVP_DecryptUpdate(key->block_dec, buf, &dstLen, buf, size); EVP_DecryptUpdate(key->block_dec, buf, &dstLen, buf, size);
EVP_DecryptFinal_ex(key->block_dec, buf + dstLen, &tmpLen); EVP_DecryptFinal_ex(key->block_dec, buf + dstLen, &tmpLen);
dstLen += tmpLen; dstLen += tmpLen;

View File

@ -31,7 +31,7 @@
#ifndef EVP_CIPHER #ifndef EVP_CIPHER
struct evp_cipher_st; struct evp_cipher_st;
typedef struct evp_cipher_st EVP_CIPHER; using EVP_CIPHER = struct evp_cipher_st;
#endif #endif
namespace encfs { namespace encfs {

View File

@ -30,8 +30,7 @@
#define HMAC_CTX_reset HMAC_CTX_cleanup #define HMAC_CTX_reset HMAC_CTX_cleanup
// Missing methods (based on 1.1.0 versions) // Missing methods (based on 1.1.0 versions)
HMAC_CTX *HMAC_CTX_new(void) HMAC_CTX *HMAC_CTX_new(void) {
{
HMAC_CTX *ctx = (HMAC_CTX *)OPENSSL_malloc(sizeof(HMAC_CTX)); HMAC_CTX *ctx = (HMAC_CTX *)OPENSSL_malloc(sizeof(HMAC_CTX));
if (ctx != NULL) { if (ctx != NULL) {
memset(ctx, 0, sizeof(HMAC_CTX)); memset(ctx, 0, sizeof(HMAC_CTX));
@ -40,8 +39,7 @@ HMAC_CTX *HMAC_CTX_new(void)
return ctx; return ctx;
} }
void HMAC_CTX_free(HMAC_CTX *ctx) void HMAC_CTX_free(HMAC_CTX *ctx) {
{
if (ctx != NULL) { if (ctx != NULL) {
HMAC_CTX_cleanup(ctx); HMAC_CTX_cleanup(ctx);
OPENSSL_free(ctx); OPENSSL_free(ctx);

View File

@ -20,8 +20,9 @@
#include "StreamNameIO.h" #include "StreamNameIO.h"
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <cstring> #include <cstring>
#include <utility>
#include "Cipher.h" #include "Cipher.h"
#include "CipherKey.h" #include "CipherKey.h"
@ -72,11 +73,12 @@ Interface StreamNameIO::CurrentInterface() {
} }
StreamNameIO::StreamNameIO(const Interface &iface, StreamNameIO::StreamNameIO(const Interface &iface,
const std::shared_ptr<Cipher> &cipher, std::shared_ptr<Cipher> cipher, CipherKey key)
const CipherKey &key) : _interface(iface.current()),
: _interface(iface.current()), _cipher(cipher), _key(key) {} _cipher(std::move(cipher)),
_key(std::move(key)) {}
StreamNameIO::~StreamNameIO() {} StreamNameIO::~StreamNameIO() = default;
Interface StreamNameIO::interface() const { return CurrentInterface(); } Interface StreamNameIO::interface() const { return CurrentInterface(); }
@ -94,7 +96,9 @@ int StreamNameIO::encodeName(const char *plaintextName, int length,
uint64_t *iv, char *encodedName, uint64_t *iv, char *encodedName,
int bufferLength) const { int bufferLength) const {
uint64_t tmpIV = 0; uint64_t tmpIV = 0;
if (iv && _interface >= 2) tmpIV = *iv; if ((iv != nullptr) && _interface >= 2) {
tmpIV = *iv;
}
unsigned int mac = unsigned int mac =
_cipher->MAC_16((const unsigned char *)plaintextName, length, _key, iv); _cipher->MAC_16((const unsigned char *)plaintextName, length, _key, iv);
@ -135,7 +139,9 @@ int StreamNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
int decodedStreamLen = decLen256 - 2; int decodedStreamLen = decLen256 - 2;
rAssert(decodedStreamLen <= bufferLength); rAssert(decodedStreamLen <= bufferLength);
if (decodedStreamLen <= 0) throw Error("Filename too small to decode"); if (decodedStreamLen <= 0) {
throw Error("Filename too small to decode");
}
BUFFER_INIT(tmpBuf, 32, (unsigned int)length); BUFFER_INIT(tmpBuf, 32, (unsigned int)length);
@ -153,7 +159,9 @@ int StreamNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
((unsigned int)((unsigned char)tmpBuf[1])); ((unsigned int)((unsigned char)tmpBuf[1]));
// version 2 adds support for IV chaining.. // version 2 adds support for IV chaining..
if (iv && _interface >= 2) tmpIV = *iv; if ((iv != nullptr) && _interface >= 2) {
tmpIV = *iv;
}
memcpy(plaintextName, tmpBuf + 2, decodedStreamLen); memcpy(plaintextName, tmpBuf + 2, decodedStreamLen);
} else { } else {

View File

@ -36,8 +36,8 @@ class StreamNameIO : public NameIO {
public: public:
static Interface CurrentInterface(); static Interface CurrentInterface();
StreamNameIO(const Interface &iface, const std::shared_ptr<Cipher> &cipher, StreamNameIO(const Interface &iface, std::shared_ptr<Cipher> cipher,
const CipherKey &key); CipherKey key);
virtual ~StreamNameIO(); virtual ~StreamNameIO();
virtual Interface interface() const; virtual Interface interface() const;

View File

@ -22,7 +22,9 @@
#include <algorithm> // for remove_if #include <algorithm> // for remove_if
#include <cstring> // for NULL #include <cstring> // for NULL
#include <fstream> // for ifstream
#include <memory> // for shared_ptr #include <memory> // for shared_ptr
#include <sstream> // for ostringstream
#include <tinyxml2.h> // for XMLElement, XMLNode, XMLDocument (ptr only) #include <tinyxml2.h> // for XMLElement, XMLNode, XMLDocument (ptr only)
@ -32,7 +34,7 @@
namespace encfs { namespace encfs {
XmlValue::~XmlValue() {} XmlValue::~XmlValue() = default;
XmlValuePtr XmlValue::operator[](const char *path) const { return find(path); } XmlValuePtr XmlValue::operator[](const char *path) const { return find(path); }
@ -44,7 +46,9 @@ XmlValuePtr XmlValue::find(const char *path) const {
bool XmlValue::read(const char *path, std::string *out) const { bool XmlValue::read(const char *path, std::string *out) const {
XmlValuePtr value = find(path); XmlValuePtr value = find(path);
if (!value) return false; if (!value) {
return false;
}
*out = value->text(); *out = value->text();
return true; return true;
@ -52,7 +56,9 @@ bool XmlValue::read(const char *path, std::string *out) const {
bool XmlValue::read(const char *path, int *out) const { bool XmlValue::read(const char *path, int *out) const {
XmlValuePtr value = find(path); XmlValuePtr value = find(path);
if (!value) return false; if (!value) {
return false;
}
*out = atoi(value->text().c_str()); *out = atoi(value->text().c_str());
return true; return true;
@ -60,7 +66,9 @@ bool XmlValue::read(const char *path, int *out) const {
bool XmlValue::read(const char *path, long *out) const { bool XmlValue::read(const char *path, long *out) const {
XmlValuePtr value = find(path); XmlValuePtr value = find(path);
if (!value) return false; if (!value) {
return false;
}
*out = atol(value->text().c_str()); *out = atol(value->text().c_str());
return true; return true;
@ -68,7 +76,9 @@ bool XmlValue::read(const char *path, long *out) const {
bool XmlValue::read(const char *path, double *out) const { bool XmlValue::read(const char *path, double *out) const {
XmlValuePtr value = find(path); XmlValuePtr value = find(path);
if (!value) return false; if (!value) {
return false;
}
*out = atof(value->text().c_str()); *out = atof(value->text().c_str());
return true; return true;
@ -76,16 +86,20 @@ bool XmlValue::read(const char *path, double *out) const {
bool XmlValue::read(const char *path, bool *out) const { bool XmlValue::read(const char *path, bool *out) const {
XmlValuePtr value = find(path); XmlValuePtr value = find(path);
if (!value) return false; if (!value) {
return false;
}
*out = atoi(value->text().c_str()); *out = (atoi(value->text().c_str()) != 0);
return true; return true;
} }
bool XmlValue::readB64(const char *path, unsigned char *data, bool XmlValue::readB64(const char *path, unsigned char *data,
int length) const { int length) const {
XmlValuePtr value = find(path); XmlValuePtr value = find(path);
if (!value) return false; if (!value) {
return false;
}
std::string s = value->text(); std::string s = value->text();
s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end()); s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
@ -99,7 +113,7 @@ bool XmlValue::readB64(const char *path, unsigned char *data,
return false; return false;
} }
if (!B64StandardDecode(data, (unsigned char *)s.data(), s.size())) { if (!B64StandardDecode(data, (unsigned char *)s.data(), s.size())) {
RLOG(ERROR) << "B64 decode failure on \"" << s << "\""; RLOG(ERROR) << R"(B64 decode failure on ")" << s << R"(")";
return false; return false;
} }
@ -108,7 +122,9 @@ bool XmlValue::readB64(const char *path, unsigned char *data,
bool XmlValue::read(const char *path, Interface *out) const { bool XmlValue::read(const char *path, Interface *out) const {
XmlValuePtr node = find(path); XmlValuePtr node = find(path);
if (!node) return false; if (!node) {
return false;
}
bool ok = node->read("name", &out->name()) && bool ok = node->read("name", &out->name()) &&
node->read("major", &out->current()) && node->read("major", &out->current()) &&
@ -119,12 +135,16 @@ bool XmlValue::read(const char *path, Interface *out) const {
std::string safeValueForNode(const tinyxml2::XMLElement *element) { std::string safeValueForNode(const tinyxml2::XMLElement *element) {
std::string value; std::string value;
if (element == NULL) return value; if (element == nullptr) {
return value;
}
const tinyxml2::XMLNode *child = element->FirstChild(); const tinyxml2::XMLNode *child = element->FirstChild();
if (child) { if (child != nullptr) {
const tinyxml2::XMLText *childText = child->ToText(); const tinyxml2::XMLText *childText = child->ToText();
if (childText) value = childText->Value(); if (childText != nullptr) {
value = childText->Value();
}
} }
return value; return value;
@ -137,22 +157,21 @@ class XmlNode : virtual public XmlValue {
XmlNode(const tinyxml2::XMLElement *element_) XmlNode(const tinyxml2::XMLElement *element_)
: XmlValue(safeValueForNode(element_)), element(element_) {} : XmlValue(safeValueForNode(element_)), element(element_) {}
virtual ~XmlNode() {} ~XmlNode() override = default;
virtual XmlValuePtr find(const char *name) const { XmlValuePtr find(const char *name) const override {
if (name[0] == '@') { if (name[0] == '@') {
const char *value = element->Attribute(name + 1); const char *value = element->Attribute(name + 1);
if (value) if (value != nullptr) {
return XmlValuePtr(new XmlValue(value)); return std::make_shared<encfs::XmlValue>(value);
else }
return XmlValuePtr(); return XmlValuePtr();
} else {
const tinyxml2::XMLElement *el = element->FirstChildElement(name);
if (el)
return XmlValuePtr(new XmlNode(el));
else
return XmlValuePtr();
} }
const tinyxml2::XMLElement *el = element->FirstChildElement(name);
if (el != nullptr) {
return XmlValuePtr(new XmlNode(el));
}
return XmlValuePtr();
} }
}; };
@ -162,26 +181,33 @@ struct XmlReader::XmlReaderData {
XmlReader::XmlReader() : pd(new XmlReaderData()) {} XmlReader::XmlReader() : pd(new XmlReaderData()) {}
XmlReader::~XmlReader() {} XmlReader::~XmlReader() = default;
bool XmlReader::load(const char *fileName) { bool XmlReader::load(const char *fileName) {
pd->doc.reset(new tinyxml2::XMLDocument()); pd->doc.reset(new tinyxml2::XMLDocument());
auto err = pd->doc->LoadFile(fileName); std::ifstream in(fileName);
if (!in) {
return false;
}
std::ostringstream fileContent;
fileContent << in.rdbuf();
auto err = pd->doc->Parse(fileContent.str().c_str());
return err == tinyxml2::XML_SUCCESS; return err == tinyxml2::XML_SUCCESS;
} }
XmlValuePtr XmlReader::operator[](const char *name) const { XmlValuePtr XmlReader::operator[](const char *name) const {
tinyxml2::XMLNode *node = pd->doc->FirstChildElement(name); tinyxml2::XMLNode *node = pd->doc->FirstChildElement(name);
if (node == NULL) { if (node == nullptr) {
RLOG(ERROR) << "Xml node " << name << " not found"; RLOG(ERROR) << "Xml node " << name << " not found";
return XmlValuePtr(new XmlValue()); return std::make_shared<encfs::XmlValue>();
} }
tinyxml2::XMLElement *element = node->ToElement(); tinyxml2::XMLElement *element = node->ToElement();
if (element == NULL) { if (element == nullptr) {
RLOG(ERROR) << "Xml node " << name << " not element"; RLOG(ERROR) << "Xml node " << name << " not element";
return XmlValuePtr(new XmlValue()); return std::make_shared<encfs::XmlValue>();
} }
return XmlValuePtr(new XmlNode(element)); return XmlValuePtr(new XmlNode(element));

View File

@ -29,7 +29,7 @@
namespace encfs { namespace encfs {
class XmlValue; class XmlValue;
typedef std::shared_ptr<XmlValue> XmlValuePtr; using XmlValuePtr = std::shared_ptr<XmlValue>;
class XmlValue { class XmlValue {
std::string value; std::string value;

View File

@ -27,10 +27,10 @@
/* Specification. */ /* Specification. */
#include "autosprintf.h" #include "autosprintf.h"
#include <stdarg.h> // for va_list #include <cstdarg> // for va_list
#include <stdio.h> // for NULL, vasprintf #include <cstdio> // for NULL, vasprintf
#include <stdlib.h> // for free #include <cstdlib> // for free
#include <string.h> // for strdup #include <cstring> // for strdup
namespace gnu { namespace gnu {
@ -38,13 +38,15 @@ namespace gnu {
autosprintf::autosprintf(const char *format, ...) { autosprintf::autosprintf(const char *format, ...) {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
if (vasprintf(&str, format, args) < 0) str = NULL; if (vasprintf(&str, format, args) < 0) {
str = nullptr;
}
va_end(args); va_end(args);
} }
/* Copy constructor. Necessary because the destructor is nontrivial. */ /* Copy constructor. Necessary because the destructor is nontrivial. */
autosprintf::autosprintf(const autosprintf &src) { autosprintf::autosprintf(const autosprintf &src) {
str = (src.str != NULL ? strdup(src.str) : NULL); str = (src.str != nullptr ? strdup(src.str) : nullptr);
} }
/* Destructor: frees the temporarily allocated string. */ /* Destructor: frees the temporarily allocated string. */
@ -52,15 +54,15 @@ autosprintf::~autosprintf() { free(str); }
/* Conversion to string. */ /* Conversion to string. */
autosprintf::operator char *() const { autosprintf::operator char *() const {
if (str != NULL) { if (str != nullptr) {
size_t length = strlen(str) + 1; size_t length = strlen(str) + 1;
char *copy = new char[length]; auto *copy = new char[length];
memcpy(copy, str, length); memcpy(copy, str, length);
return copy; return copy;
} else }
return NULL; return nullptr;
} }
autosprintf::operator std::string() const { autosprintf::operator std::string() const {
return std::string(str ? str : "(error in autosprintf)"); return std::string(str != nullptr ? str : "(error in autosprintf)");
}
} }
} // namespace gnu

View File

@ -20,7 +20,7 @@
#include "base64.h" #include "base64.h"
#include <ctype.h> // for toupper #include <cctype> // for toupper
#include "Error.h" #include "Error.h"
@ -52,7 +52,9 @@ void changeBase2(unsigned char *src, int srcLen, int src2Pow,
} }
// now, we could have a partial value left in the work buffer.. // now, we could have a partial value left in the work buffer..
if (workBits && ((dst - origDst) < dstLen)) *dst++ = work & mask; if ((workBits != 0) && ((dst - origDst) < dstLen)) {
*dst++ = work & mask;
}
} }
/* /*
@ -67,11 +69,13 @@ static void changeBase2Inline(unsigned char *src, int srcLen, int src2Pow,
unsigned long work, int workBits, unsigned long work, int workBits,
unsigned char *outLoc) { unsigned char *outLoc) {
const int mask = (1 << dst2Pow) - 1; const int mask = (1 << dst2Pow) - 1;
if (!outLoc) outLoc = src; if (outLoc == nullptr) {
outLoc = src;
}
// copy the new bits onto the high bits of the stream. // copy the new bits onto the high bits of the stream.
// The bits that fall off the low end are the output bits. // The bits that fall off the low end are the output bits.
while (srcLen && workBits < dst2Pow) { while ((srcLen != 0) && workBits < dst2Pow) {
work |= ((unsigned long)(*src++)) << workBits; work |= ((unsigned long)(*src++)) << workBits;
workBits += src2Pow; workBits += src2Pow;
--srcLen; --srcLen;
@ -82,7 +86,7 @@ static void changeBase2Inline(unsigned char *src, int srcLen, int src2Pow,
work >>= dst2Pow; work >>= dst2Pow;
workBits -= dst2Pow; workBits -= dst2Pow;
if (srcLen) { if (srcLen != 0) {
// more input left, so recurse // more input left, so recurse
changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte, changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte,
work, workBits, outLoc + 1); work, workBits, outLoc + 1);
@ -105,7 +109,7 @@ static void changeBase2Inline(unsigned char *src, int srcLen, int src2Pow,
void changeBase2Inline(unsigned char *src, int srcLen, int src2Pow, int dst2Pow, void changeBase2Inline(unsigned char *src, int srcLen, int src2Pow, int dst2Pow,
bool outputPartialLastByte) { bool outputPartialLastByte) {
changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte, 0, 0, changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte, 0, 0,
0); nullptr);
} }
// character set for ascii b64: // character set for ascii b64:
@ -119,12 +123,14 @@ void B64ToAscii(unsigned char *in, int length) {
for (int offset = 0; offset < length; ++offset) { for (int offset = 0; offset < length; ++offset) {
int ch = in[offset]; int ch = in[offset];
if (ch > 11) { if (ch > 11) {
if (ch > 37) if (ch > 37) {
ch += 'a' - 38; ch += 'a' - 38;
else } else {
ch += 'A' - 12; ch += 'A' - 12;
} else }
} else {
ch = B642AsciiTable[ch]; ch = B642AsciiTable[ch];
}
in[offset] = ch; in[offset] = ch;
} }
@ -139,16 +145,17 @@ void AsciiToB64(unsigned char *in, int length) {
} }
void AsciiToB64(unsigned char *out, const unsigned char *in, int length) { void AsciiToB64(unsigned char *out, const unsigned char *in, int length) {
while (length--) { while ((length--) != 0) {
unsigned char ch = *in++; unsigned char ch = *in++;
if (ch >= 'A') { if (ch >= 'A') {
if (ch >= 'a') if (ch >= 'a') {
ch += 38 - 'a'; ch += 38 - 'a';
else } else {
ch += 12 - 'A'; ch += 12 - 'A';
} else }
} else {
ch = Ascii2B64Table[ch] - '0'; ch = Ascii2B64Table[ch] - '0';
}
*out++ = ch; *out++ = ch;
} }
} }
@ -156,10 +163,11 @@ void AsciiToB64(unsigned char *out, const unsigned char *in, int length) {
void B32ToAscii(unsigned char *buf, int len) { void B32ToAscii(unsigned char *buf, int len) {
for (int offset = 0; offset < len; ++offset) { for (int offset = 0; offset < len; ++offset) {
int ch = buf[offset]; int ch = buf[offset];
if (ch >= 0 && ch < 26) if (ch >= 0 && ch < 26) {
ch += 'A'; ch += 'A';
else } else {
ch += '2' - 26; ch += '2' - 26;
}
buf[offset] = ch; buf[offset] = ch;
} }
@ -170,14 +178,14 @@ void AsciiToB32(unsigned char *in, int length) {
} }
void AsciiToB32(unsigned char *out, const unsigned char *in, int length) { void AsciiToB32(unsigned char *out, const unsigned char *in, int length) {
while (length--) { while ((length--) != 0) {
unsigned char ch = *in++; unsigned char ch = *in++;
int lch = toupper(ch); int lch = toupper(ch);
if (lch >= 'A') if (lch >= 'A') {
lch -= 'A'; lch -= 'A';
else } else {
lch += 26 - '2'; lch += 26 - '2';
}
*out++ = (unsigned char)lch; *out++ = (unsigned char)lch;
} }
} }
@ -221,7 +229,7 @@ bool B64StandardDecode(unsigned char *out, const unsigned char *in, int inLen) {
buf = buf << 6 | c; buf = buf << 6 | c;
/* If the buffer is full, split it into bytes */ /* If the buffer is full, split it into bytes */
if (buf & 0x1000000) { if ((buf & 0x1000000) != 0u) {
*out++ = buf >> 16; *out++ = buf >> 16;
*out++ = buf >> 8; *out++ = buf >> 8;
*out++ = buf; *out++ = buf;
@ -230,10 +238,10 @@ bool B64StandardDecode(unsigned char *out, const unsigned char *in, int inLen) {
} }
} }
if (buf & 0x40000) { if ((buf & 0x40000) != 0u) {
*out++ = buf >> 10; *out++ = buf >> 10;
*out++ = buf >> 2; *out++ = buf >> 2;
} else if (buf & 0x1000) { } else if ((buf & 0x1000) != 0u) {
*out++ = buf >> 4; *out++ = buf >> 4;
} }
@ -248,7 +256,7 @@ std::string B64StandardEncode(std::vector<unsigned char> inputBuffer) {
std::string encodedString; std::string encodedString;
encodedString.reserve(B256ToB64Bytes(inputBuffer.size())); encodedString.reserve(B256ToB64Bytes(inputBuffer.size()));
long temp; long temp;
std::vector<unsigned char>::iterator cursor = inputBuffer.begin(); auto cursor = inputBuffer.begin();
for (size_t idx = 0; idx < inputBuffer.size() / 3; idx++) { for (size_t idx = 0; idx < inputBuffer.size() / 3; idx++) {
temp = (*cursor++) << 16; // Convert to big endian temp = (*cursor++) << 16; // Convert to big endian
temp += (*cursor++) << 8; temp += (*cursor++) << 8;

View File

@ -18,17 +18,17 @@
#include "encfs.h" #include "encfs.h"
#include <cerrno> #include <cerrno>
#include <cinttypes>
#include <cstddef> #include <cstddef>
#include <cstdint>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <ctime>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h>
#include <memory> #include <memory>
#include <stdint.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include <utime.h> #include <utime.h>
#ifdef linux #ifdef linux
@ -41,7 +41,7 @@
#include <attr/xattr.h> #include <attr/xattr.h>
#endif #endif
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <functional> #include <functional>
#include <string> #include <string>
#include <vector> #include <vector>
@ -76,7 +76,9 @@ static EncFS_Context *context() {
* if the argument is NULL. * if the argument is NULL.
*/ */
static bool isReadOnly(EncFS_Context *ctx) { static bool isReadOnly(EncFS_Context *ctx) {
if (ctx == NULL) ctx = (EncFS_Context *)fuse_get_context()->private_data; if (ctx == nullptr) {
ctx = (EncFS_Context *)fuse_get_context()->private_data;
}
return ctx->opts->readOnly; return ctx->opts->readOnly;
} }
@ -89,7 +91,9 @@ static int withCipherPath(const char *opName, const char *path,
int res = -EIO; int res = -EIO;
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if (!FSRoot) return res; if (!FSRoot) {
return res;
}
try { try {
string cyName = FSRoot->cipherPath(path); string cyName = FSRoot->cipherPath(path);
@ -111,6 +115,27 @@ static int withCipherPath(const char *opName, const char *path,
return res; return res;
} }
static void checkCanary(std::shared_ptr<FileNode> fnode) {
if (fnode->canary == CANARY_OK) {
return;
}
if (fnode->canary == CANARY_RELEASED) {
// "fnode" may have been released after it was retrieved by
// lookupFuseFh. This is not an error. std::shared_ptr will release
// the memory only when all operations on the FileNode have been
// completed.
return;
}
if (fnode->canary == CANARY_DESTROYED) {
RLOG(ERROR)
<< "canary=CANARY_DESTROYED. FileNode accessed after it was destroyed.";
} else {
RLOG(ERROR) << "canary=0x" << std::hex << fnode->canary
<< ". Memory corruption?";
}
throw Error("dead canary");
}
// helper function -- apply a functor to a node // helper function -- apply a functor to a node
static int withFileNode(const char *opName, const char *path, static int withFileNode(const char *opName, const char *path,
struct fuse_file_info *fi, struct fuse_file_info *fi,
@ -119,12 +144,15 @@ static int withFileNode(const char *opName, const char *path,
int res = -EIO; int res = -EIO;
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if (!FSRoot) return res; if (!FSRoot) {
return res;
}
try { try {
auto do_op = [&FSRoot, opName, &op](FileNode *fnode) { auto do_op = [&FSRoot, opName, &op](std::shared_ptr<FileNode> fnode) {
rAssert(fnode != nullptr); rAssert(fnode != nullptr);
checkCanary(fnode);
VLOG(1) << "op: " << opName << " : " << fnode->cipherName(); VLOG(1) << "op: " << opName << " : " << fnode->cipherName();
// check that we're not recursing into the mount point itself // check that we're not recursing into the mount point itself
@ -133,13 +161,19 @@ static int withFileNode(const char *opName, const char *path,
<< fnode->cipherName() << "'"; << fnode->cipherName() << "'";
return -EIO; return -EIO;
} }
return op(fnode); return op(fnode.get());
}; };
if (fi != nullptr && fi->fh != 0) if (fi != nullptr && fi->fh != 0) {
res = do_op(reinterpret_cast<FileNode *>(fi->fh)); auto node = ctx->lookupFuseFh(fi->fh);
else if (node == nullptr) {
res = do_op(FSRoot->lookupNode(path, opName).get()); auto msg = "fh=" + std::to_string(fi->fh) + " not found in fuseFhMap";
throw Error(msg.c_str());
}
res = do_op(node);
} else {
res = do_op(FSRoot->lookupNode(path, opName));
}
if (res < 0) { if (res < 0) {
RLOG(DEBUG) << "op: " << opName << " error: " << strerror(-res); RLOG(DEBUG) << "op: " << opName << " error: " << strerror(-res);
@ -188,7 +222,7 @@ int _do_getattr(FileNode *fnode, struct stat *stbuf) {
} }
int encfs_getattr(const char *path, struct stat *stbuf) { int encfs_getattr(const char *path, struct stat *stbuf) {
return withFileNode("getattr", path, NULL, bind(_do_getattr, _1, stbuf)); return withFileNode("getattr", path, nullptr, bind(_do_getattr, _1, stbuf));
} }
int encfs_fgetattr(const char *path, struct stat *stbuf, int encfs_fgetattr(const char *path, struct stat *stbuf,
@ -202,7 +236,9 @@ int encfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
int res = ESUCCESS; int res = ESUCCESS;
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if (!FSRoot) return res; if (!FSRoot) {
return res;
}
try { try {
@ -224,7 +260,9 @@ int encfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
#if defined(fuse_fill_dir_flags) #if defined(fuse_fill_dir_flags)
if (filler(buf, name.c_str(), &st, 0, 0)) break; if (filler(buf, name.c_str(), &st, 0, 0)) break;
#else #else
if (filler(buf, name.c_str(), &st, 0)) break; if (filler(buf, name.c_str(), &st, 0) != 0) {
break;
}
#endif #endif
name = dt.nextPlaintextName(&fileType, &inode); name = dt.nextPlaintextName(&fileType, &inode);
@ -243,11 +281,15 @@ int encfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
int encfs_mknod(const char *path, mode_t mode, dev_t rdev) { int encfs_mknod(const char *path, mode_t mode, dev_t rdev) {
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
if (isReadOnly(ctx)) return -EROFS; if (isReadOnly(ctx)) {
return -EROFS;
}
int res = -EIO; int res = -EIO;
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if (!FSRoot) return res; if (!FSRoot) {
return res;
}
try { try {
std::shared_ptr<FileNode> fnode = FSRoot->lookupNode(path, "mknod"); std::shared_ptr<FileNode> fnode = FSRoot->lookupNode(path, "mknod");
@ -272,8 +314,9 @@ int encfs_mknod(const char *path, mode_t mode, dev_t rdev) {
FSRoot->lookupNode(parent.c_str(), "mknod"); FSRoot->lookupNode(parent.c_str(), "mknod");
struct stat st; struct stat st;
if (dnode->getAttr(&st) == 0) if (dnode->getAttr(&st) == 0) {
res = fnode->mknod(mode, rdev, uid, st.st_gid); res = fnode->mknod(mode, rdev, uid, st.st_gid);
}
} }
} catch (encfs::Error &err) { } catch (encfs::Error &err) {
RLOG(ERROR) << "error caught in mknod: " << err.what(); RLOG(ERROR) << "error caught in mknod: " << err.what();
@ -285,11 +328,15 @@ int encfs_mkdir(const char *path, mode_t mode) {
fuse_context *fctx = fuse_get_context(); fuse_context *fctx = fuse_get_context();
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
if (isReadOnly(ctx)) return -EROFS; if (isReadOnly(ctx)) {
return -EROFS;
}
int res = -EIO; int res = -EIO;
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if (!FSRoot) return res; if (!FSRoot) {
return res;
}
try { try {
uid_t uid = 0; uid_t uid = 0;
@ -307,8 +354,9 @@ int encfs_mkdir(const char *path, mode_t mode) {
FSRoot->lookupNode(parent.c_str(), "mkdir"); FSRoot->lookupNode(parent.c_str(), "mkdir");
struct stat st; struct stat st;
if (dnode->getAttr(&st) == 0) if (dnode->getAttr(&st) == 0) {
res = FSRoot->mkdir(path, mode, uid, st.st_gid); res = FSRoot->mkdir(path, mode, uid, st.st_gid);
}
} }
} catch (encfs::Error &err) { } catch (encfs::Error &err) {
RLOG(ERROR) << "error caught in mkdir: " << err.what(); RLOG(ERROR) << "error caught in mkdir: " << err.what();
@ -319,11 +367,15 @@ int encfs_mkdir(const char *path, mode_t mode) {
int encfs_unlink(const char *path) { int encfs_unlink(const char *path) {
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
if (isReadOnly(ctx)) return -EROFS; if (isReadOnly(ctx)) {
return -EROFS;
}
int res = -EIO; int res = -EIO;
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if (!FSRoot) return res; if (!FSRoot) {
return res;
}
try { try {
// let DirNode handle it atomically so that it can handle race // let DirNode handle it atomically so that it can handle race
@ -340,7 +392,9 @@ int _do_rmdir(EncFS_Context *, const string &cipherPath) {
} }
int encfs_rmdir(const char *path) { int encfs_rmdir(const char *path) {
if (isReadOnly(NULL)) return -EROFS; if (isReadOnly(nullptr)) {
return -EROFS;
}
return withCipherPath("rmdir", path, bind(_do_rmdir, _1, _2)); return withCipherPath("rmdir", path, bind(_do_rmdir, _1, _2));
} }
@ -348,11 +402,15 @@ int _do_readlink(EncFS_Context *ctx, const string &cyName, char *buf,
size_t size) { size_t size) {
int res = ESUCCESS; int res = ESUCCESS;
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if (!FSRoot) return res; if (!FSRoot) {
return res;
}
res = ::readlink(cyName.c_str(), buf, size - 1); res = ::readlink(cyName.c_str(), buf, size - 1);
if (res == -1) return -errno; if (res == -1) {
return -errno;
}
buf[res] = '\0'; // ensure null termination buf[res] = '\0'; // ensure null termination
string decodedName; string decodedName;
@ -363,10 +421,9 @@ int _do_readlink(EncFS_Context *ctx, const string &cyName, char *buf,
buf[size - 1] = '\0'; buf[size - 1] = '\0';
return ESUCCESS; return ESUCCESS;
} else {
RLOG(WARNING) << "Error decoding link";
return -1;
} }
RLOG(WARNING) << "Error decoding link";
return -1;
} }
int encfs_readlink(const char *path, char *buf, size_t size) { int encfs_readlink(const char *path, char *buf, size_t size) {
@ -380,11 +437,15 @@ int encfs_readlink(const char *path, char *buf, size_t size) {
int encfs_symlink(const char *to, const char *from) { int encfs_symlink(const char *to, const char *from) {
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
if (isReadOnly(ctx)) return -EROFS; if (isReadOnly(ctx)) {
return -EROFS;
}
int res = -EIO; int res = -EIO;
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if (!FSRoot) return res; if (!FSRoot) {
return res;
}
try { try {
string fromCName = FSRoot->cipherPath(from); string fromCName = FSRoot->cipherPath(from);
@ -403,13 +464,18 @@ int encfs_symlink(const char *to, const char *from) {
oldgid = setfsgid(context->gid); oldgid = setfsgid(context->gid);
} }
res = ::symlink(toCName.c_str(), fromCName.c_str()); res = ::symlink(toCName.c_str(), fromCName.c_str());
if (olduid >= 0) setfsuid(olduid); if (olduid >= 0) {
if (oldgid >= 0) setfsgid(oldgid); setfsuid(olduid);
}
if (oldgid >= 0) {
setfsgid(oldgid);
}
if (res == -1) if (res == -1) {
res = -errno; res = -errno;
else } else {
res = ESUCCESS; res = ESUCCESS;
}
} catch (encfs::Error &err) { } catch (encfs::Error &err) {
RLOG(ERROR) << "error caught in symlink: " << err.what(); RLOG(ERROR) << "error caught in symlink: " << err.what();
} }
@ -419,11 +485,15 @@ int encfs_symlink(const char *to, const char *from) {
int encfs_link(const char *from, const char *to) { int encfs_link(const char *from, const char *to) {
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
if (isReadOnly(ctx)) return -EROFS; if (isReadOnly(ctx)) {
return -EROFS;
}
int res = -EIO; int res = -EIO;
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if (!FSRoot) return res; if (!FSRoot) {
return res;
}
try { try {
res = FSRoot->link(from, to); res = FSRoot->link(from, to);
@ -436,11 +506,15 @@ int encfs_link(const char *from, const char *to) {
int encfs_rename(const char *from, const char *to) { int encfs_rename(const char *from, const char *to) {
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
if (isReadOnly(ctx)) return -EROFS; if (isReadOnly(ctx)) {
return -EROFS;
}
int res = -EIO; int res = -EIO;
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if (!FSRoot) return res; if (!FSRoot) {
return res;
}
try { try {
res = FSRoot->rename(from, to); res = FSRoot->rename(from, to);
@ -455,7 +529,9 @@ int _do_chmod(EncFS_Context *, const string &cipherPath, mode_t mode) {
} }
int encfs_chmod(const char *path, mode_t mode) { int encfs_chmod(const char *path, mode_t mode) {
if (isReadOnly(NULL)) return -EROFS; if (isReadOnly(nullptr)) {
return -EROFS;
}
return withCipherPath("chmod", path, bind(_do_chmod, _1, _2, mode)); return withCipherPath("chmod", path, bind(_do_chmod, _1, _2, mode));
} }
@ -465,19 +541,25 @@ int _do_chown(EncFS_Context *, const string &cyName, uid_t u, gid_t g) {
} }
int encfs_chown(const char *path, uid_t uid, gid_t gid) { int encfs_chown(const char *path, uid_t uid, gid_t gid) {
if (isReadOnly(NULL)) return -EROFS; if (isReadOnly(nullptr)) {
return -EROFS;
}
return withCipherPath("chown", path, bind(_do_chown, _1, _2, uid, gid)); return withCipherPath("chown", path, bind(_do_chown, _1, _2, uid, gid));
} }
int _do_truncate(FileNode *fnode, off_t size) { return fnode->truncate(size); } int _do_truncate(FileNode *fnode, off_t size) { return fnode->truncate(size); }
int encfs_truncate(const char *path, off_t size) { int encfs_truncate(const char *path, off_t size) {
if (isReadOnly(NULL)) return -EROFS; if (isReadOnly(nullptr)) {
return withFileNode("truncate", path, NULL, bind(_do_truncate, _1, size)); return -EROFS;
}
return withFileNode("truncate", path, nullptr, bind(_do_truncate, _1, size));
} }
int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) { int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) {
if (isReadOnly(NULL)) return -EROFS; if (isReadOnly(nullptr)) {
return -EROFS;
}
return withFileNode("ftruncate", path, fi, bind(_do_truncate, _1, size)); return withFileNode("ftruncate", path, fi, bind(_do_truncate, _1, size));
} }
@ -487,7 +569,9 @@ int _do_utime(EncFS_Context *, const string &cyName, struct utimbuf *buf) {
} }
int encfs_utime(const char *path, struct utimbuf *buf) { int encfs_utime(const char *path, struct utimbuf *buf) {
if (isReadOnly(NULL)) return -EROFS; if (isReadOnly(nullptr)) {
return -EROFS;
}
return withCipherPath("utime", path, bind(_do_utime, _1, _2, buf)); return withCipherPath("utime", path, bind(_do_utime, _1, _2, buf));
} }
@ -508,19 +592,25 @@ int _do_utimens(EncFS_Context *, const string &cyName,
} }
int encfs_utimens(const char *path, const struct timespec ts[2]) { int encfs_utimens(const char *path, const struct timespec ts[2]) {
if (isReadOnly(NULL)) return -EROFS; if (isReadOnly(nullptr)) {
return -EROFS;
}
return withCipherPath("utimens", path, bind(_do_utimens, _1, _2, ts)); return withCipherPath("utimens", path, bind(_do_utimens, _1, _2, ts));
} }
int encfs_open(const char *path, struct fuse_file_info *file) { int encfs_open(const char *path, struct fuse_file_info *file) {
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
if (isReadOnly(ctx) && (file->flags & O_WRONLY || file->flags & O_RDWR)) if (isReadOnly(ctx) &&
(((file->flags & O_WRONLY) != 0) || ((file->flags & O_RDWR) != 0))) {
return -EROFS; return -EROFS;
}
int res = -EIO; int res = -EIO;
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if (!FSRoot) return res; if (!FSRoot) {
return res;
}
try { try {
std::shared_ptr<FileNode> fnode = std::shared_ptr<FileNode> fnode =
@ -531,8 +621,8 @@ int encfs_open(const char *path, struct fuse_file_info *file) {
<< file->flags; << file->flags;
if (res >= 0) { if (res >= 0) {
file->fh = ctx->putNode(path, fnode);
reinterpret_cast<uintptr_t>(ctx->putNode(path, std::move(fnode))); file->fh = fnode->fuseFh;
res = ESUCCESS; res = ESUCCESS;
} }
} }
@ -545,7 +635,7 @@ int encfs_open(const char *path, struct fuse_file_info *file) {
int encfs_create(const char *path, mode_t mode, struct fuse_file_info *file) { int encfs_create(const char *path, mode_t mode, struct fuse_file_info *file) {
int res = encfs_mknod(path, mode, 0); int res = encfs_mknod(path, mode, 0);
if (res) { if (res != 0) {
return res; return res;
} }
@ -587,7 +677,8 @@ int encfs_release(const char *path, struct fuse_file_info *finfo) {
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
try { try {
ctx->eraseNode(path, reinterpret_cast<FileNode *>(finfo->fh)); auto fnode = ctx->lookupFuseFh(finfo->fh);
ctx->eraseNode(path, fnode);
return ESUCCESS; return ESUCCESS;
} catch (encfs::Error &err) { } catch (encfs::Error &err) {
RLOG(ERROR) << "error caught in release: " << err.what(); RLOG(ERROR) << "error caught in release: " << err.what();
@ -610,21 +701,25 @@ int _do_fsync(FileNode *fnode, int dataSync) {
} }
int encfs_fsync(const char *path, int dataSync, struct fuse_file_info *file) { int encfs_fsync(const char *path, int dataSync, struct fuse_file_info *file) {
if (isReadOnly(NULL)) return -EROFS; if (isReadOnly(nullptr)) {
return -EROFS;
}
return withFileNode("fsync", path, file, bind(_do_fsync, _1, dataSync)); return withFileNode("fsync", path, file, bind(_do_fsync, _1, dataSync));
} }
int _do_write(FileNode *fnode, unsigned char *ptr, size_t size, off_t offset) { int _do_write(FileNode *fnode, unsigned char *ptr, size_t size, off_t offset) {
int res = fnode->write(offset, ptr, size); int res = fnode->write(offset, ptr, size);
if (res < 0) if (res < 0) {
return res; return res;
else }
return size; return size;
} }
int encfs_write(const char *path, const char *buf, size_t size, off_t offset, int encfs_write(const char *path, const char *buf, size_t size, off_t offset,
struct fuse_file_info *file) { struct fuse_file_info *file) {
if (isReadOnly(NULL)) return -EROFS; if (isReadOnly(nullptr)) {
return -EROFS;
}
return withFileNode("write", path, file, return withFileNode("write", path, file,
bind(_do_write, _1, (unsigned char *)buf, size, offset)); bind(_do_write, _1, (unsigned char *)buf, size, offset));
} }
@ -636,16 +731,18 @@ int encfs_statfs(const char *path, struct statvfs *st) {
int res = -EIO; int res = -EIO;
try { try {
(void)path; // path should always be '/' for now.. (void)path; // path should always be '/' for now..
rAssert(st != NULL); rAssert(st != nullptr);
string cyName = ctx->rootCipherDir; string cyName = ctx->rootCipherDir;
VLOG(1) << "doing statfs of " << cyName; VLOG(1) << "doing statfs of " << cyName;
res = statvfs(cyName.c_str(), st); res = statvfs(cyName.c_str(), st);
if (!res) { if (res == 0) {
// adjust maximum name length.. // adjust maximum name length..
st->f_namemax = 6 * (st->f_namemax - 2) / 8; // approx.. st->f_namemax = 6 * (st->f_namemax - 2) / 8; // approx..
} }
if (res == -1) res = -errno; if (res == -1) {
res = -errno;
}
} catch (encfs::Error &err) { } catch (encfs::Error &err) {
RLOG(ERROR) << "error caught in statfs: " << err.what(); RLOG(ERROR) << "error caught in statfs: " << err.what();
} }
@ -657,7 +754,7 @@ int encfs_statfs(const char *path, struct statvfs *st) {
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int _do_setxattr(EncFS_Context *, const string &cyName, const char *name, int _do_setxattr(EncFS_Context *, const string &cyName, const char *name,
const char *value, size_t size, uint32_t pos) { const char *value, size_t size, uint32_t pos) {
int options = 0; int options = XATTR_NOFOLLOW;
return ::setxattr(cyName.c_str(), name, value, size, pos, options); return ::setxattr(cyName.c_str(), name, value, size, pos, options);
} }
int encfs_setxattr(const char *path, const char *name, const char *value, int encfs_setxattr(const char *path, const char *name, const char *value,
@ -670,11 +767,13 @@ int encfs_setxattr(const char *path, const char *name, const char *value,
#else #else
int _do_setxattr(EncFS_Context *, const string &cyName, const char *name, int _do_setxattr(EncFS_Context *, const string &cyName, const char *name,
const char *value, size_t size, int flags) { const char *value, size_t size, int flags) {
return ::setxattr(cyName.c_str(), name, value, size, flags); return ::lsetxattr(cyName.c_str(), name, value, size, flags);
} }
int encfs_setxattr(const char *path, const char *name, const char *value, int encfs_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags) { size_t size, int flags) {
if (isReadOnly(NULL)) return -EROFS; if (isReadOnly(nullptr)) {
return -EROFS;
}
return withCipherPath("setxattr", path, return withCipherPath("setxattr", path,
bind(_do_setxattr, _1, _2, name, value, size, flags)); bind(_do_setxattr, _1, _2, name, value, size, flags));
} }
@ -683,7 +782,7 @@ int encfs_setxattr(const char *path, const char *name, const char *value,
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int _do_getxattr(EncFS_Context *, const string &cyName, const char *name, int _do_getxattr(EncFS_Context *, const string &cyName, const char *name,
void *value, size_t size, uint32_t pos) { void *value, size_t size, uint32_t pos) {
int options = 0; int options = XATTR_NOFOLLOW;
return ::getxattr(cyName.c_str(), name, value, size, pos, options); return ::getxattr(cyName.c_str(), name, value, size, pos, options);
} }
int encfs_getxattr(const char *path, const char *name, char *value, size_t size, int encfs_getxattr(const char *path, const char *name, char *value, size_t size,
@ -695,7 +794,7 @@ int encfs_getxattr(const char *path, const char *name, char *value, size_t size,
#else #else
int _do_getxattr(EncFS_Context *, const string &cyName, const char *name, int _do_getxattr(EncFS_Context *, const string &cyName, const char *name,
void *value, size_t size) { void *value, size_t size) {
return ::getxattr(cyName.c_str(), name, value, size); return ::lgetxattr(cyName.c_str(), name, value, size);
} }
int encfs_getxattr(const char *path, const char *name, char *value, int encfs_getxattr(const char *path, const char *name, char *value,
size_t size) { size_t size) {
@ -708,10 +807,10 @@ int encfs_getxattr(const char *path, const char *name, char *value,
int _do_listxattr(EncFS_Context *, const string &cyName, char *list, int _do_listxattr(EncFS_Context *, const string &cyName, char *list,
size_t size) { size_t size) {
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int options = 0; int options = XATTR_NOFOLLOW;
int res = ::listxattr(cyName.c_str(), list, size, options); int res = ::listxattr(cyName.c_str(), list, size, options);
#else #else
int res = ::listxattr(cyName.c_str(), list, size); int res = ::llistxattr(cyName.c_str(), list, size);
#endif #endif
return (res == -1) ? -errno : res; return (res == -1) ? -errno : res;
} }
@ -723,16 +822,18 @@ int encfs_listxattr(const char *path, char *list, size_t size) {
int _do_removexattr(EncFS_Context *, const string &cyName, const char *name) { int _do_removexattr(EncFS_Context *, const string &cyName, const char *name) {
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int options = 0; int options = XATTR_NOFOLLOW;
int res = ::removexattr(cyName.c_str(), name, options); int res = ::removexattr(cyName.c_str(), name, options);
#else #else
int res = ::removexattr(cyName.c_str(), name); int res = ::lremovexattr(cyName.c_str(), name);
#endif #endif
return (res == -1) ? -errno : res; return (res == -1) ? -errno : res;
} }
int encfs_removexattr(const char *path, const char *name) { int encfs_removexattr(const char *path, const char *name) {
if (isReadOnly(NULL)) return -EROFS; if (isReadOnly(nullptr)) {
return -EROFS;
}
return withCipherPath("removexattr", path, return withCipherPath("removexattr", path,
bind(_do_removexattr, _1, _2, name)); bind(_do_removexattr, _1, _2, name));

View File

@ -21,7 +21,7 @@
#ifndef _encfs_incl_ #ifndef _encfs_incl_
#define _encfs_incl_ #define _encfs_incl_
#include "internal/easylogging++.h" #include "easylogging++.h"
#include <fuse.h> #include <fuse.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>

View File

@ -16,12 +16,13 @@ encfs - mounts or creates an encrypted virtual filesystem
=head1 SYNOPSIS =head1 SYNOPSIS
B<encfs> [B<--version>] [B<-s>] [B<-f>] [B<-v>|B<--verbose>] B<encfs> [B<--version>] [B<-v>|B<--verbose>] [B<-t>|B<--syslogtag>]
[B<-i MINUTES>|B<--idle=MINUTES>] [B<--extpass=program>] [B<-s>] [B<-f>] [B<--annotate>] [B<--standard>] [B<--paranoia>]
[B<-S>|B<--stdinpass>] [B<--anykey>] [B<--forcedecode>] [B<--reverse>] [B<--extpass=program>] [B<-S>|B<--stdinpass>]
[B<-d>|B<--fuse-debug>] [B<--public>] [B<--no-default-flags>] [B<--anykey>] [B<--forcedecode>] [B<-require-macs>]
[B<--ondemand>] [B<--delaymount>] [B<--reverse>] [B<--standard>] [B<-i MINUTES>|B<--idle=MINUTES>] [B<-m>|B<--ondemand>] [B<--delaymount>]
[B<-o FUSE_OPTION>] [B<--public>] [B<--nocache>] [B<--no-default-flags>]
[B<-o FUSE_OPTION>] [B<-d>|B<--fuse-debug>] [B<-H>|B<--fuse-help>]
I<rootdir> I<mountPoint> I<rootdir> I<mountPoint>
[B<--> [I<Fuse Mount Options>]] [B<--> [I<Fuse Mount Options>]]
@ -42,13 +43,29 @@ may be an increasing number of choices.
=over 4 =over 4
=item B<-i>, B<--idle=MINUTES> =item B<--version>
Enable automatic unmount of the filesystem after a period of inactivity. The Shows B<EncFS> version. Using B<--verbose> before B<--version> may display
period is specified in minutes, so the shortest timeout period that can be additional information.
requested is one minute. B<EncFS> will not automatically unmount if there are
files open within the filesystem, even if they are open in read-only mode. =item B<-v>, B<--verbose>
However simply having files open does not count as activity.
Causes B<EncFS> to enable logging of various debug channels within B<EncFS>.
Normally these logging messages are disabled and have no effect. It is
recommended that you run in foreground (B<-f>) mode when running with verbose
enabled.
=item B<-t>, B<--syslogtag>
This option allows to set the syslog tag which will be used when messages are
logged via syslog. By default the syslog tag is set to B<encfs>.
=item B<-s>
The B<-s> (I<single threaded>) option causes B<EncFS> to run in single threaded
mode. By default, B<EncFS> runs in multi-threaded mode. This option is used
during B<EncFS> development in order to simplify debugging and allow it to run
under memory checking tools.
=item B<-f> =item B<-f>
@ -59,76 +76,22 @@ foreground and any warning/debug log messages will be displayed on standard
error. In the default (background) mode, all log messages are logged via error. In the default (background) mode, all log messages are logged via
syslog. syslog.
=item B<-v>, B<--verbose> =item B<--annotate>
Causes B<EncFS> to enable logging of various debug channels within B<EncFS>. Print annotation lines to stderr during configuration.
Normally these logging messages are disabled and have no effect. It is
recommended that you run in foreground (B<-f>) mode when running with verbose
enabled.
=item B<-s> =item B<--standard>
The B<-s> (I<single threaded>) option causes B<EncFS> to run in single threaded If creating a new filesystem, this automatically selects standard configuration
mode. By default, B<EncFS> runs in multi-threaded mode. This option is used options, to help with automatic filesystem creation. This is the set of
during B<EncFS> development in order to simplify debugging and allow it to run options that should be used unless you know what you're doing and have read the
under memory checking tools. documentation.
=item B<-d>, B<--fuse-debug> When not creating a filesystem, this flag does nothing.
Enables debugging within the B<FUSE> library. This should only be used if you =item B<--paranoia>
suspect a problem within B<FUSE> itself (not B<EncFS>), as it generates a lot
of low-level data and is not likely to be very helpful in general problem
tracking. Try I<verbose> mode (B<-v>) first, which gives a higher level view
of what is happening within B<EncFS>.
=item B<--forcedecode> Same as B<--standard>, but for B<paranoia> mode.
This option only has an effect on filesystems which use MAC block headers. By
default, if a block is decoded and the stored MAC doesn't match what is
calculated, then an IO error is returned to the application and the block is
not returned. However, by specifying B<--forcedecode>, only an error will be
logged and the data will still be returned to the application. This may be
useful for attempting to read corrupted files.
=item B<--public>
Attempt to make encfs behave as a typical multi-user filesystem. By default,
all FUSE based filesystems are visible only to the user who mounted them. No
other users (including root) can view the filesystem contents. The B<--public>
option does two things. It adds the FUSE flags "allow_other" and
"default_permission" when mounting the filesystem, which tells FUSE to allow
other users to access the filesystem, and to use the ownership permissions
provided by the filesystem. Secondly, the B<--public> flag changes how encfs's
node creation functions work - as they will try and set ownership of new nodes
based on the caller identification.
B<Warning>: In order for this to work, encfs must be run as root -- otherwise
it will not have the ability to change ownership of files. I recommend that
you instead investigate if the fuse allow_other option can be used to do what
you want before considering the use of B<--public>.
=item B<--ondemand>
Mount the filesystem on-demand. This currently only makes sense in combination
with B<--idle> and B<--extpass> options. When the filesystem becomes idle,
instead of exiting, B<EncFS> stops allowing access to the filesystem by
internally dropping its reference to it. If someone attempts to access the
filesystem again, the extpass program is used to prompt the user for the
password. If this succeeds, then the filesystem becomes available again.
=item B<--delaymount>
Do not mount the filesystem when encfs starts; instead, delay mounting until
first use. This option only makes sense with B<--ondemand>.
=item B<--require-macs>
If creating a new filesystem, this forces block authentication code headers to
be enabled. When mounting an existing filesystem, this causes encfs to exit
if block authentication code headers are not enabled.
This can be used to improve security in case the ciphertext is vulnerable to
tampering, by preventing an attacker from disabling MACs in the config file.
=item B<--reverse> =item B<--reverse>
@ -154,58 +117,6 @@ Now /tmp/plain-view contains the same data as /home/me
Note that B<--reverse> mode only works with limited configuration options, so Note that B<--reverse> mode only works with limited configuration options, so
many settings may be disabled when used. many settings may be disabled when used.
=item B<--nocache>
Disable the kernel's cache of file attributes.
Setting this option makes EncFS pass "attr_timeout=0" and "entry_timeout=0" to
FUSE. This makes sure that modifications to the backing files that occour
outside EncFS show up immediately in the EncFS mount. The main use case
for "--nocache" is reverse mode.
=item B<--standard>
If creating a new filesystem, this automatically selects standard configuration
options, to help with automatic filesystem creation. This is the set of
options that should be used unless you know what you're doing and have read the
documentation.
When not creating a filesystem, this flag does nothing.
=item B<-o FUSE_ARG>
Pass through B<FUSE> args to the underlying library. This makes it easy to
pass FUSE options when mounting B<EncFS> via mount (and /etc/fstab). Eg:
mount encfs#/home/me-crypt /home/me -t fuse -o kernel_cache
Note that encfs arguments cannot be set this way. If you need to set encfs
arguments, create a wrapper, such as encfs-reverse;
#!/bin/sh
encfs --reverse "$@"
Then mount using the script path
mount encfs-reverse#/home/me /home/me-crypt -t fuse
=item B<-->
The B<--> option tells B<EncFS> to send any remaining arguments directly to
B<FUSE>. In turn, B<FUSE> passes the arguments to B<fusermount>. See
the B<fusermount> help page for information on available commands.
=item B<--no-default-flags>
B<Encfs> adds the FUSE flags "use_ino" and "default_permissions" by default, as
of version 1.2.2, because that improves compatibility with some programs. If
for some reason you need to disable one or both of these flags, use the option
B<--no-default-flags>.
The following command lines produce the same result:
encfs raw crypt
encfs --no-default-flags raw crypt -- -o use_ino,default_permissions
=item B<--extpass=program> =item B<--extpass=program>
Specify an external program to use for getting the user password. When the Specify an external program to use for getting the user password. When the
@ -247,6 +158,118 @@ which will not remain the same if the primary password is changed.
B<Warning>: Use this option at your own risk. B<Warning>: Use this option at your own risk.
=item B<--forcedecode>
This option only has an effect on filesystems which use MAC block headers. By
default, if a block is decoded and the stored MAC doesn't match what is
calculated, then an IO error is returned to the application and the block is
not returned. However, by specifying B<--forcedecode>, only an error will be
logged and the data will still be returned to the application. This may be
useful for attempting to read corrupted files.
=item B<--require-macs>
If creating a new filesystem, this forces block authentication code headers to
be enabled. When mounting an existing filesystem, this causes encfs to exit
if block authentication code headers are not enabled.
This can be used to improve security in case the ciphertext is vulnerable to
tampering, by preventing an attacker from disabling MACs in the config file.
=item B<-i>, B<--idle=MINUTES>
Enable automatic unmount of the filesystem after a period of inactivity. The
period is specified in minutes, so the shortest timeout period that can be
requested is one minute. B<EncFS> will not automatically unmount if there are
files open within the filesystem, even if they are open in read-only mode.
However simply having files open does not count as activity.
=item B<-m>, B<--ondemand>
Mount the filesystem on-demand. This currently only makes sense in combination
with B<--idle> and B<--extpass> options. When the filesystem becomes idle,
instead of exiting, B<EncFS> stops allowing access to the filesystem by
internally dropping its reference to it. If someone attempts to access the
filesystem again, the extpass program is used to prompt the user for the
password. If this succeeds, then the filesystem becomes available again.
=item B<--delaymount>
Do not mount the filesystem when encfs starts; instead, delay mounting until
first use. This option only makes sense with B<--ondemand>.
=item B<--public>
Attempt to make encfs behave as a typical multi-user filesystem. By default,
all FUSE based filesystems are visible only to the user who mounted them. No
other users (including root) can view the filesystem contents. The B<--public>
option does two things. It adds the FUSE flags "allow_other" and
"default_permission" when mounting the filesystem, which tells FUSE to allow
other users to access the filesystem, and to use the ownership permissions
provided by the filesystem. Secondly, the B<--public> flag changes how encfs's
node creation functions work - as they will try and set ownership of new nodes
based on the caller identification.
B<Warning>: In order for this to work, encfs must be run as root -- otherwise
it will not have the ability to change ownership of files. I recommend that
you instead investigate if the fuse allow_other option can be used to do what
you want before considering the use of B<--public>.
=item B<--nocache>
Disable the kernel's cache of file attributes.
Setting this option makes EncFS pass "attr_timeout=0" and "entry_timeout=0" to
FUSE. This makes sure that modifications to the backing files that occour
outside EncFS show up immediately in the EncFS mount. The main use case
for "--nocache" is reverse mode.
=item B<--no-default-flags>
B<Encfs> adds the FUSE flags "use_ino" and "default_permissions" by default, as
of version 1.2.2, because that improves compatibility with some programs. If
for some reason you need to disable one or both of these flags, use the option
B<--no-default-flags>.
The following command lines produce the same result:
encfs raw crypt
encfs --no-default-flags raw crypt -- -o use_ino,default_permissions
=item B<-o FUSE_ARG>
Pass through B<FUSE> args to the underlying library. This makes it easy to
pass FUSE options when mounting B<EncFS> via mount (and /etc/fstab). Eg:
mount encfs#/home/me-crypt /home/me -t fuse -o kernel_cache
Note that encfs arguments cannot be set this way. If you need to set encfs
arguments, create a wrapper, such as encfs-reverse;
#!/bin/sh
encfs --reverse "$@"
Then mount using the script path
mount encfs-reverse#/home/me /home/me-crypt -t fuse
=item B<-d>, B<--fuse-debug>
Enables debugging within the B<FUSE> library. This should only be used if you
suspect a problem within B<FUSE> itself (not B<EncFS>), as it generates a lot
of low-level data and is not likely to be very helpful in general problem
tracking. Try I<verbose> mode (B<-v>) first, which gives a higher level view
of what is happening within B<EncFS>.
=item B<-H>, B<--fuse-help>
Shows B<FUSE> help.
=item B<-->
The B<--> option tells B<EncFS> to send any remaining arguments directly to
B<FUSE>. In turn, B<FUSE> passes the arguments to B<fusermount>. See
the B<fusermount> help page for information on available commands.
=back =back
=head1 ENVIRONMENT VARIABLES =head1 ENVIRONMENT VARIABLES

View File

@ -53,8 +53,6 @@ using namespace std;
using gnu::autosprintf; using gnu::autosprintf;
using namespace encfs; using namespace encfs;
INITIALIZE_EASYLOGGINGPP
static int showInfo(int argc, char **argv); static int showInfo(int argc, char **argv);
static int showVersion(int argc, char **argv); static int showVersion(int argc, char **argv);
static int chpasswd(int argc, char **argv); static int chpasswd(int argc, char **argv);

View File

@ -6,16 +6,17 @@
# Contributed by David Rosenstrauch. # Contributed by David Rosenstrauch.
canonicalize() { canonicalize() {
cd "$1" cd "$1" || return
pwd pwd
} }
if [ -z "$1" -o "$1" = "-h" ]; then case $1 in "" | -h | --help)
echo Usage: encfssh encrypted_directory [unencrypted-directory [-p]] echo "Usage: encfssh encrypted_directory [unencrypted-directory [-p]]"
echo " -p mount the unencrypted directory as public" echo " -p mount the unencrypted directory as public"
exit 1 exit 1
fi ;;
esac
enc_dir=$1 enc_dir=$1
unenc_dir_given=false unenc_dir_given=false
@ -28,42 +29,65 @@ if [ ! -z "$2" ]; then
mount_public=true mount_public=true
fi fi
done done
[ -d "$unenc_dir" ] || mkdir $unenc_dir [ -d "$unenc_dir" ] || mkdir -- "$unenc_dir"
else else
unenc_dir=$(mktemp -d .XXXXXXXX) unenc_dir=$(mktemp -d .XXXXXXXX)
fi fi
if [ ! -d "$enc_dir" ]; then if [ ! -d "$enc_dir" ]; then
mkdir $enc_dir mkdir -- "$enc_dir"
fi fi
enc_dir=$(canonicalize "$enc_dir") enc_dir=$(canonicalize "$enc_dir")
unenc_dir=$(canonicalize "$unenc_dir") unenc_dir=$(canonicalize "$unenc_dir")
options="" options=
if $unenc_dir_given; then if [ "$unenc_dir_given" = "true" ]; then
if $mount_public; then if [ "$mount_public" = "true" ]; then
options="-- -o allow_other" options="-- -o allow_other"
fi fi
fi fi
# Attach the directory and change into it # Attach the directory and change into it
if encfs $enc_dir $unenc_dir $options; then :; else
## options can only have one of two values (empty, or "-- -o allow_other"), so
## this unquoted expansion is safe; disabling relevant shellcheck warning.
## See code review feedback requesting this attached to
## https://github.com/vgough/encfs/pull/258/files/09b9fc5efb7c2694976baffe7dd21172fd182027
## ...and that warning's explanation at https://github.com/koalaman/shellcheck/wiki/SC2086
# shellcheck disable=SC2086
if encfs "$enc_dir" "$unenc_dir" $options; then :; else
echo "encfs failed" echo "encfs failed"
rmdir $unenc_dir rmdir -- "$unenc_dir"
exit 1 exit 1
fi fi
if ! $unenc_dir_given; then if ! [ "$unenc_dir_given" = "true" ]; then
chmod 700 $unenc_dir chmod 700 "$unenc_dir"
fi fi
echo "Directory is $unenc_dir" echo "Directory is $unenc_dir" >&2
orig_dir=$(pwd) cd "$unenc_dir" || exit
cd $unenc_dir
# Fall back to umount if fusermount is not available (e.g., on OS X) # Fall back to umount if fusermount is not available (e.g., on OS X)
FUSE_UMOUNT="$(which 2>/dev/null fusermount)" fuse_umount() {
FUSE_UMOUNT="${FUSE_UMOUNT:+fusermount -u}" if command -v fusermount >/dev/null 2>&1; then
FUSE_UMOUNT="${FUSE_UMOUNT:-umount}" fusermount -u "$@"
else
umount "$@" # MacOS case
fi
}
# Set the shell up # Honor the SHELL environment variable to select a shell to run
exec /bin/sh -c "$SHELL ; cd $orig_dir ; $FUSE_UMOUNT $unenc_dir ; if ! $unenc_dir_given; then rmdir $unenc_dir; fi" "$SHELL"; retval=$?
# ensure that this shell isn't itself holding the mounted directory open
# ...but avoid terminating on failure, *or* causing a shellcheck warning for
# failing to check exit status from cd.
cd / ||:
# if unmount fails, skip rmdir, always use exit status of failure
fuse_umount "$unenc_dir" || exit
if ! [ "$unenc_dir_given" = true ]; then
rmdir -- "$unenc_dir"
fi
exit "$retval"

View File

@ -18,18 +18,18 @@
#include <cerrno> #include <cerrno>
#include <cstdio> #include <cstdio>
#include <cstdlib>
#include <cstring> #include <cstring>
#include <ctime>
#include <exception> #include <exception>
#include <getopt.h> #include <getopt.h>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <pthread.h> #include <pthread.h>
#include <sstream> #include <sstream>
#include <stdlib.h>
#include <string> #include <string>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include "Context.h" #include "Context.h"
@ -43,11 +43,6 @@
#include "i18n.h" #include "i18n.h"
#include "openssl.h" #include "openssl.h"
// Fuse version >= 26 requires another argument to fuse_unmount, which we
// don't have. So use the backward compatible call instead..
extern "C" void fuse_unmount_compat22(const char *mountpoint);
#define fuse_unmount fuse_unmount_compat22
/* Arbitrary identifiers for long options that do /* Arbitrary identifiers for long options that do
* not have a short version */ * not have a short version */
#define LONG_OPT_ANNOTATE 513 #define LONG_OPT_ANNOTATE 513
@ -58,8 +53,6 @@ using namespace std;
using namespace encfs; using namespace encfs;
using gnu::autosprintf; using gnu::autosprintf;
INITIALIZE_EASYLOGGINGPP
namespace encfs { namespace encfs {
class DirNode; class DirNode;
@ -80,6 +73,7 @@ struct EncFS_Args {
int idleTimeout; // 0 == idle time in minutes to trigger unmount int idleTimeout; // 0 == idle time in minutes to trigger unmount
const char *fuseArgv[MaxFuseArgs]; const char *fuseArgv[MaxFuseArgs];
int fuseArgc; int fuseArgc;
std::string syslogTag; // syslog tag to use when logging using syslog
std::shared_ptr<EncFS_Opts> opts; std::shared_ptr<EncFS_Opts> opts;
@ -91,17 +85,36 @@ struct EncFS_Args {
ostringstream ss; ostringstream ss;
ss << (isDaemon ? "(daemon) " : "(fg) "); ss << (isDaemon ? "(daemon) " : "(fg) ");
ss << (isThreaded ? "(threaded) " : "(UP) "); ss << (isThreaded ? "(threaded) " : "(UP) ");
if (idleTimeout > 0) ss << "(timeout " << idleTimeout << ") "; if (idleTimeout > 0) {
if (opts->checkKey) ss << "(keyCheck) "; ss << "(timeout " << idleTimeout << ") ";
if (opts->forceDecode) ss << "(forceDecode) "; }
if (opts->ownerCreate) ss << "(ownerCreate) "; if (opts->checkKey) {
if (opts->useStdin) ss << "(useStdin) "; ss << "(keyCheck) ";
if (opts->annotate) ss << "(annotate) "; }
if (opts->reverseEncryption) ss << "(reverseEncryption) "; if (opts->forceDecode) {
if (opts->mountOnDemand) ss << "(mountOnDemand) "; ss << "(forceDecode) ";
if (opts->delayMount) ss << "(delayMount) "; }
for (int i = 0; i < fuseArgc; ++i) ss << fuseArgv[i] << ' '; if (opts->ownerCreate) {
ss << "(ownerCreate) ";
}
if (opts->useStdin) {
ss << "(useStdin) ";
}
if (opts->annotate) {
ss << "(annotate) ";
}
if (opts->reverseEncryption) {
ss << "(reverseEncryption) ";
}
if (opts->mountOnDemand) {
ss << "(mountOnDemand) ";
}
if (opts->delayMount) {
ss << "(delayMount) ";
}
for (int i = 0; i < fuseArgc; ++i) {
ss << fuseArgv[i] << ' ';
}
return ss.str(); return ss.str();
} }
@ -167,18 +180,21 @@ static void FuseUsage() {
int argc = 2; int argc = 2;
const char *argv[] = {"...", "-h"}; const char *argv[] = {"...", "-h"};
fuse_main(argc, const_cast<char **>(argv), (fuse_operations *)NULL, NULL); fuse_main(argc, const_cast<char **>(argv), (fuse_operations *)nullptr,
nullptr);
} }
#define PUSHARG(ARG) \ #define PUSHARG(ARG) \
do { \ do { \
rAssert(out->fuseArgc < MaxFuseArgs); \ rAssert(out->fuseArgc < MaxFuseArgs); \
out->fuseArgv[out->fuseArgc++] = (ARG); \ out->fuseArgv[out->fuseArgc++] = (ARG); \
} while (0) } while (false)
static string slashTerminate(const string &src) { static string slashTerminate(const string &src) {
string result = src; string result = src;
if (result[result.length() - 1] != '/') result.append("/"); if (result[result.length() - 1] != '/') {
result.append("/");
}
return result; return result;
} }
@ -190,6 +206,7 @@ static bool processArgs(int argc, char *argv[],
out->isVerbose = false; out->isVerbose = false;
out->idleTimeout = 0; out->idleTimeout = 0;
out->fuseArgc = 0; out->fuseArgc = 0;
out->syslogTag = "encfs";
out->opts->idleTracking = false; out->opts->idleTracking = false;
out->opts->checkKey = true; out->opts->checkKey = true;
out->opts->forceDecode = false; out->opts->forceDecode = false;
@ -207,36 +224,37 @@ static bool processArgs(int argc, char *argv[],
// leave a space for mount point, as FUSE expects the mount point before // leave a space for mount point, as FUSE expects the mount point before
// any flags // any flags
out->fuseArgv[1] = NULL; out->fuseArgv[1] = nullptr;
++out->fuseArgc; ++out->fuseArgc;
// TODO: can flags be internationalized? // TODO: can flags be internationalized?
static struct option long_options[] = { static struct option long_options[] = {
{"fuse-debug", 0, 0, 'd'}, // Fuse debug mode {"fuse-debug", 0, nullptr, 'd'}, // Fuse debug mode
{"forcedecode", 0, 0, 'D'}, // force decode {"forcedecode", 0, nullptr, 'D'}, // force decode
// {"foreground", 0, 0, 'f'}, // foreground mode (no daemon) // {"foreground", 0, 0, 'f'}, // foreground mode (no daemon)
{"fuse-help", 0, 0, 'H'}, // fuse_mount usage {"fuse-help", 0, nullptr, 'H'}, // fuse_mount usage
{"idle", 1, 0, 'i'}, // idle timeout {"idle", 1, nullptr, 'i'}, // idle timeout
{"anykey", 0, 0, 'k'}, // skip key checks {"anykey", 0, nullptr, 'k'}, // skip key checks
{"no-default-flags", 0, 0, 'N'}, // don't use default fuse flags {"no-default-flags", 0, nullptr, 'N'}, // don't use default fuse flags
{"ondemand", 0, 0, 'm'}, // mount on-demand {"ondemand", 0, nullptr, 'm'}, // mount on-demand
{"delaymount", 0, 0, 'M'}, // delay initial mount until use {"delaymount", 0, nullptr, 'M'}, // delay initial mount until use
{"public", 0, 0, 'P'}, // public mode {"public", 0, nullptr, 'P'}, // public mode
{"extpass", 1, 0, 'p'}, // external password program {"extpass", 1, nullptr, 'p'}, // external password program
// {"single-thread", 0, 0, 's'}, // single-threaded mode // {"single-thread", 0, 0, 's'}, // single-threaded mode
{"stdinpass", 0, 0, 'S'}, // read password from stdin {"stdinpass", 0, nullptr, 'S'}, // read password from stdin
{"annotate", 0, 0, {"syslogtag", 1, nullptr, 't'}, // syslog tag
LONG_OPT_ANNOTATE}, // Print annotation lines to stderr {"annotate", 0, nullptr,
{"nocache", 0, 0, LONG_OPT_NOCACHE}, // disable caching LONG_OPT_ANNOTATE}, // Print annotation lines to stderr
{"verbose", 0, 0, 'v'}, // verbose mode {"nocache", 0, nullptr, LONG_OPT_NOCACHE}, // disable caching
{"version", 0, 0, 'V'}, // version {"verbose", 0, nullptr, 'v'}, // verbose mode
{"reverse", 0, 0, 'r'}, // reverse encryption {"version", 0, nullptr, 'V'}, // version
{"standard", 0, 0, '1'}, // standard configuration {"reverse", 0, nullptr, 'r'}, // reverse encryption
{"paranoia", 0, 0, '2'}, // standard configuration {"standard", 0, nullptr, '1'}, // standard configuration
{"require-macs", 0, 0, LONG_OPT_REQUIRE_MAC}, // require MACs {"paranoia", 0, nullptr, '2'}, // standard configuration
{0, 0, 0, 0}}; {"require-macs", 0, nullptr, LONG_OPT_REQUIRE_MAC}, // require MACs
{nullptr, 0, nullptr, 0}};
while (1) { while (true) {
int option_index = 0; int option_index = 0;
// 's' : single-threaded mode // 's' : single-threaded mode
@ -247,10 +265,13 @@ static bool processArgs(int argc, char *argv[],
// 'm' : mount-on-demand // 'm' : mount-on-demand
// 'S' : password from stdin // 'S' : password from stdin
// 'o' : arguments meant for fuse // 'o' : arguments meant for fuse
// 't' : syslog tag
int res = int res =
getopt_long(argc, argv, "HsSfvdmi:o:", long_options, &option_index); getopt_long(argc, argv, "HsSfvdmi:o:t:", long_options, &option_index);
if (res == -1) break; if (res == -1) {
break;
}
switch (res) { switch (res) {
case '1': case '1':
@ -265,6 +286,9 @@ static bool processArgs(int argc, char *argv[],
case 'S': case 'S':
out->opts->useStdin = true; out->opts->useStdin = true;
break; break;
case 't':
out->syslogTag = optarg;
break;
case LONG_OPT_ANNOTATE: case LONG_OPT_ANNOTATE:
out->opts->annotate = true; out->opts->annotate = true;
break; break;
@ -283,7 +307,7 @@ static bool processArgs(int argc, char *argv[],
PUSHARG("-d"); PUSHARG("-d");
break; break;
case 'i': case 'i':
out->idleTimeout = strtol(optarg, (char **)NULL, 10); out->idleTimeout = strtol(optarg, (char **)nullptr, 10);
out->opts->idleTracking = true; out->opts->idleTracking = true;
break; break;
case 'k': case 'k':
@ -342,9 +366,9 @@ static bool processArgs(int argc, char *argv[],
out->opts->passwordProgram.assign(optarg); out->opts->passwordProgram.assign(optarg);
break; break;
case 'P': case 'P':
if (geteuid() != 0) if (geteuid() != 0) {
RLOG(WARNING) << "option '--public' ignored for non-root user"; RLOG(WARNING) << "option '--public' ignored for non-root user";
else { } else {
out->opts->ownerCreate = true; out->opts->ownerCreate = true;
// add 'allow_other' option // add 'allow_other' option
// add 'default_permissions' option (default) // add 'default_permissions' option (default)
@ -355,6 +379,12 @@ static bool processArgs(int argc, char *argv[],
case 'V': case 'V':
// xgroup(usage) // xgroup(usage)
cerr << autosprintf(_("encfs version %s"), VERSION) << endl; cerr << autosprintf(_("encfs version %s"), VERSION) << endl;
#if defined(HAVE_XATTR)
// "--verbose" has to be passed before "--version" for this to work.
if (out->isVerbose) {
cerr << "Compiled with : HAVE_XATTR" << endl;
}
#endif
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
break; break;
case 'H': case 'H':
@ -373,7 +403,9 @@ static bool processArgs(int argc, char *argv[],
} }
} }
if (!out->isThreaded) PUSHARG("-s"); if (!out->isThreaded) {
PUSHARG("-s");
}
// we should have at least 2 arguments left over - the source directory and // we should have at least 2 arguments left over - the source directory and
// the mount point. // the mount point.
@ -486,15 +518,10 @@ static bool processArgs(int argc, char *argv[],
static void *idleMonitor(void *); static void *idleMonitor(void *);
void *encfs_init(fuse_conn_info *conn) { void *encfs_init(fuse_conn_info *conn) {
EncFS_Context *ctx = (EncFS_Context *)fuse_get_context()->private_data; auto *ctx = (EncFS_Context *)fuse_get_context()->private_data;
// set fuse connection options // set fuse connection options
conn->async_read = true; conn->async_read = 1u;
if (ctx->args->isDaemon) {
// Switch to using syslog.
encfs::rlogAction = el::base::DispatchAction::SysLog;
}
// if an idle timeout is specified, then setup a thread to monitor the // if an idle timeout is specified, then setup a thread to monitor the
// filesystem. // filesystem.
@ -502,7 +529,8 @@ void *encfs_init(fuse_conn_info *conn) {
VLOG(1) << "starting idle monitoring thread"; VLOG(1) << "starting idle monitoring thread";
ctx->running = true; ctx->running = true;
int res = pthread_create(&ctx->monitorThread, 0, idleMonitor, (void *)ctx); int res =
pthread_create(&ctx->monitorThread, nullptr, idleMonitor, (void *)ctx);
if (res != 0) { if (res != 0) {
int eno = errno; int eno = errno;
RLOG(ERROR) << "error starting idle monitor thread, " RLOG(ERROR) << "error starting idle monitor thread, "
@ -532,19 +560,17 @@ int main(int argc, char *argv[]) {
// anything that comes from the user should be considered tainted until // anything that comes from the user should be considered tainted until
// we've processed it and only allowed through what we support. // we've processed it and only allowed through what we support.
std::shared_ptr<EncFS_Args> encfsArgs(new EncFS_Args); std::shared_ptr<EncFS_Args> encfsArgs(new EncFS_Args);
for (int i = 0; i < MaxFuseArgs; ++i) for (int i = 0; i < MaxFuseArgs; ++i) {
encfsArgs->fuseArgv[i] = NULL; // libfuse expects null args.. encfsArgs->fuseArgv[i] = nullptr; // libfuse expects null args..
}
if (argc == 1 || !processArgs(argc, argv, encfsArgs)) { if (argc == 1 || !processArgs(argc, argv, encfsArgs)) {
usage(argv[0]); usage(argv[0]);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (encfsArgs->isVerbose) { encfs::initLogging(encfsArgs->isVerbose, encfsArgs->isDaemon);
el::Loggers::setVerboseLevel(1); ELPP_INITIALIZE_SYSLOG(encfsArgs->syslogTag.c_str(), LOG_PID, LOG_USER);
}
encfs::initLogging(encfsArgs->isVerbose);
VLOG(1) << "Root directory: " << encfsArgs->opts->rootDir; VLOG(1) << "Root directory: " << encfsArgs->opts->rootDir;
VLOG(1) << "Fuse arguments: " << encfsArgs->toString(); VLOG(1) << "Fuse arguments: " << encfsArgs->toString();
@ -600,7 +626,7 @@ int main(int argc, char *argv[]) {
// context is not a smart pointer because it will live for the life of // context is not a smart pointer because it will live for the life of
// the filesystem. // the filesystem.
auto ctx = std::shared_ptr<EncFS_Context>(new EncFS_Context); auto ctx = std::make_shared<EncFS_Context>();
ctx->publicFilesystem = encfsArgs->opts->ownerCreate; ctx->publicFilesystem = encfsArgs->opts->ownerCreate;
RootPtr rootInfo = initFS(ctx.get(), encfsArgs->opts); RootPtr rootInfo = initFS(ctx.get(), encfsArgs->opts);
@ -617,7 +643,7 @@ int main(int argc, char *argv[]) {
ctx->args = encfsArgs; ctx->args = encfsArgs;
ctx->opts = encfsArgs->opts; ctx->opts = encfsArgs->opts;
if (encfsArgs->isThreaded == false && encfsArgs->idleTimeout > 0) { if (!encfsArgs->isThreaded && encfsArgs->idleTimeout > 0) {
// xgroup(usage) // xgroup(usage)
cerr << _("Note: requested single-threaded mode, but an idle\n" cerr << _("Note: requested single-threaded mode, but an idle\n"
"timeout was specified. The filesystem will operate\n" "timeout was specified. The filesystem will operate\n"
@ -639,7 +665,9 @@ int main(int argc, char *argv[]) {
try { try {
time_t startTime, endTime; time_t startTime, endTime;
if (encfsArgs->opts->annotate) cerr << "$STATUS$ fuse_main_start" << endl; if (encfsArgs->opts->annotate) {
cerr << "$STATUS$ fuse_main_start" << endl;
}
// FIXME: workaround for fuse_main returning an error on normal // FIXME: workaround for fuse_main returning an error on normal
// exit. Only print information if fuse_main returned // exit. Only print information if fuse_main returned
@ -653,9 +681,13 @@ int main(int argc, char *argv[]) {
time(&endTime); time(&endTime);
if (encfsArgs->opts->annotate) cerr << "$STATUS$ fuse_main_end" << endl; if (encfsArgs->opts->annotate) {
cerr << "$STATUS$ fuse_main_end" << endl;
}
if (res == 0) returnCode = EXIT_SUCCESS; if (res == 0) {
returnCode = EXIT_SUCCESS;
}
if (res != 0 && encfsArgs->isDaemon && (oldStderr >= 0) && if (res != 0 && encfsArgs->isDaemon && (oldStderr >= 0) &&
(endTime - startTime <= 1)) { (endTime - startTime <= 1)) {
@ -684,7 +716,7 @@ int main(int argc, char *argv[]) {
pthread_cond_signal(&ctx->wakeupCond); pthread_cond_signal(&ctx->wakeupCond);
pthread_mutex_unlock(&ctx->wakeupMutex); pthread_mutex_unlock(&ctx->wakeupMutex);
VLOG(1) << "joining with idle monitoring thread"; VLOG(1) << "joining with idle monitoring thread";
pthread_join(ctx->monitorThread, 0); pthread_join(ctx->monitorThread, nullptr);
VLOG(1) << "join done"; VLOG(1) << "join done";
} }
} }
@ -710,34 +742,45 @@ const int ActivityCheckInterval = 10;
static bool unmountFS(EncFS_Context *ctx); static bool unmountFS(EncFS_Context *ctx);
static void *idleMonitor(void *_arg) { static void *idleMonitor(void *_arg) {
EncFS_Context *ctx = (EncFS_Context *)_arg; auto *ctx = (EncFS_Context *)_arg;
std::shared_ptr<EncFS_Args> arg = ctx->args; std::shared_ptr<EncFS_Args> arg = ctx->args;
const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval; const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval;
int idleCycles = -1; int idleCycles = -1;
bool unmountres = false;
// We will notify when FS will be unmounted, so notify that it has just been
// mounted
RLOG(INFO) << "Filesystem mounted: " << arg->opts->mountPoint;
pthread_mutex_lock(&ctx->wakeupMutex); pthread_mutex_lock(&ctx->wakeupMutex);
while (ctx->running) { while (ctx->running) {
int usage = ctx->getAndResetUsageCounter(); int usage, openCount;
ctx->getAndResetUsageCounter(&usage, &openCount);
if (usage == 0 && ctx->isMounted()) if (usage == 0 && ctx->isMounted()) {
++idleCycles; ++idleCycles;
else } else {
if (idleCycles >= timeoutCycles) {
RLOG(INFO) << "Filesystem no longer inactive: "
<< arg->opts->mountPoint;
}
idleCycles = 0; idleCycles = 0;
}
if (idleCycles >= timeoutCycles) { if (idleCycles >= timeoutCycles) {
int openCount = ctx->openFileCount();
if (openCount == 0) { if (openCount == 0) {
if (unmountFS(ctx)) { unmountres = unmountFS(ctx);
if (unmountres) {
// wait for main thread to wake us up // wait for main thread to wake us up
pthread_cond_wait(&ctx->wakeupCond, &ctx->wakeupMutex); pthread_cond_wait(&ctx->wakeupCond, &ctx->wakeupMutex);
break; break;
} }
} else { } else {
RLOG(WARNING) << "Filesystem " << arg->opts->mountPoint RLOG(WARNING) << "Filesystem inactive, but " << openCount
<< " inactivity detected, but still " << openCount << " files opened: " << arg->opts->mountPoint;
<< " opened files";
} }
} }
@ -745,7 +788,7 @@ static void *idleMonitor(void *_arg) {
<< timeoutCycles; << timeoutCycles;
struct timeval currentTime; struct timeval currentTime;
gettimeofday(&currentTime, 0); gettimeofday(&currentTime, nullptr);
struct timespec wakeupTime; struct timespec wakeupTime;
wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval; wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval;
wakeupTime.tv_nsec = currentTime.tv_usec * 1000; wakeupTime.tv_nsec = currentTime.tv_usec * 1000;
@ -754,9 +797,15 @@ static void *idleMonitor(void *_arg) {
pthread_mutex_unlock(&ctx->wakeupMutex); pthread_mutex_unlock(&ctx->wakeupMutex);
// If we are here FS has been unmounted, so if we did not unmount ourselves
// (manual, kill...), notify
if (!unmountres) {
RLOG(INFO) << "Filesystem unmounted: " << arg->opts->mountPoint;
}
VLOG(1) << "Idle monitoring thread exiting"; VLOG(1) << "Idle monitoring thread exiting";
return 0; return nullptr;
} }
static bool unmountFS(EncFS_Context *ctx) { static bool unmountFS(EncFS_Context *ctx) {
@ -767,11 +816,14 @@ static bool unmountFS(EncFS_Context *ctx) {
ctx->setRoot(std::shared_ptr<DirNode>()); ctx->setRoot(std::shared_ptr<DirNode>());
return false; return false;
} else {
// Time to unmount!
RLOG(WARNING) << "Unmounting filesystem due to inactivity: "
<< arg->opts->mountPoint;
fuse_unmount(arg->opts->mountPoint.c_str());
return true;
} }
// Time to unmount!
#if FUSE_USE_VERSION < 30
fuse_unmount(arg->opts->mountPoint.c_str(), nullptr);
#else
fuse_unmount(fuse_get_context()->fuse);
#endif
// fuse_unmount succeeds and returns void
RLOG(INFO) << "Filesystem inactive, unmounted: " << arg->opts->mountPoint;
return true;
} }

View File

@ -31,8 +31,6 @@
using namespace std; using namespace std;
using namespace encfs; using namespace encfs;
INITIALIZE_EASYLOGGINGPP
void genKey(const std::shared_ptr<Cipher> &cipher) { void genKey(const std::shared_ptr<Cipher> &cipher) {
CipherKey key = cipher->newRandomKey(); CipherKey key = cipher->newRandomKey();

View File

@ -20,9 +20,9 @@
#include "openssl.h" #include "openssl.h"
#include <cstdlib>
#include <openssl/crypto.h> #include <openssl/crypto.h>
#include <pthread.h> #include <pthread.h>
#include <stdlib.h>
#define NO_DES #define NO_DES
#include <openssl/rand.h> #include <openssl/rand.h>
@ -37,20 +37,21 @@ namespace encfs {
unsigned long pthreads_thread_id() { return (unsigned long)pthread_self(); } unsigned long pthreads_thread_id() { return (unsigned long)pthread_self(); }
static pthread_mutex_t *crypto_locks = NULL; static pthread_mutex_t *crypto_locks = nullptr;
void pthreads_locking_callback(int mode, int n, const char *caller_file, void pthreads_locking_callback(int mode, int n, const char *caller_file,
int caller_line) { int caller_line) {
(void)caller_file; (void)caller_file;
(void)caller_line; (void)caller_line;
if (!crypto_locks) { if (crypto_locks == nullptr) {
VLOG(1) << "Allocating " << CRYPTO_num_locks() << " locks for OpenSSL"; VLOG(1) << "Allocating " << CRYPTO_num_locks() << " locks for OpenSSL";
crypto_locks = new pthread_mutex_t[CRYPTO_num_locks()]; crypto_locks = new pthread_mutex_t[CRYPTO_num_locks()];
for (int i = 0; i < CRYPTO_num_locks(); ++i) for (int i = 0; i < CRYPTO_num_locks(); ++i) {
pthread_mutex_init(crypto_locks + i, 0); pthread_mutex_init(crypto_locks + i, nullptr);
}
} }
if (mode & CRYPTO_LOCK) { if ((mode & CRYPTO_LOCK) != 0) {
pthread_mutex_lock(crypto_locks + n); pthread_mutex_lock(crypto_locks + n);
} else { } else {
pthread_mutex_unlock(crypto_locks + n); pthread_mutex_unlock(crypto_locks + n);
@ -58,11 +59,12 @@ void pthreads_locking_callback(int mode, int n, const char *caller_file,
} }
void pthreads_locking_cleanup() { void pthreads_locking_cleanup() {
if (crypto_locks) { if (crypto_locks != nullptr) {
for (int i = 0; i < CRYPTO_num_locks(); ++i) for (int i = 0; i < CRYPTO_num_locks(); ++i) {
pthread_mutex_destroy(crypto_locks + i); pthread_mutex_destroy(crypto_locks + i);
}
delete[] crypto_locks; delete[] crypto_locks;
crypto_locks = NULL; crypto_locks = nullptr;
} }
} }
@ -95,7 +97,9 @@ void openssl_shutdown(bool threaded) {
ENGINE_cleanup(); ENGINE_cleanup();
#endif #endif
if (threaded) pthreads_locking_cleanup(); if (threaded) {
pthreads_locking_cleanup();
}
} }
} // namespace encfs } // namespace encfs

View File

@ -76,7 +76,7 @@ char *readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) {
/* I suppose we could alloc on demand in this case (XXX). */ /* I suppose we could alloc on demand in this case (XXX). */
if (bufsiz == 0) { if (bufsiz == 0) {
errno = EINVAL; errno = EINVAL;
return (NULL); return (nullptr);
} }
restart: restart:
@ -85,9 +85,9 @@ restart:
* stdin and write to stderr unless a tty is required. * stdin and write to stderr unless a tty is required.
*/ */
if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) { if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) {
if (flags & RPP_REQUIRE_TTY) { if ((flags & RPP_REQUIRE_TTY) != 0) {
errno = ENOTTY; errno = ENOTTY;
return (NULL); return (nullptr);
} }
input = STDIN_FILENO; input = STDIN_FILENO;
output = STDERR_FILENO; output = STDERR_FILENO;
@ -112,7 +112,9 @@ restart:
/* Turn off echo if possible. */ /* Turn off echo if possible. */
if (tcgetattr(input, &oterm) == 0) { if (tcgetattr(input, &oterm) == 0) {
memcpy(&term, &oterm, sizeof(term)); memcpy(&term, &oterm, sizeof(term));
if (!(flags & RPP_ECHO_ON)) term.c_lflag &= ~(ECHO | ECHONL); if ((flags & RPP_ECHO_ON) == 0) {
term.c_lflag &= ~(ECHO | ECHONL);
}
#ifdef VSTATUS #ifdef VSTATUS
if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
term.c_cc[VSTATUS] = _POSIX_VDISABLE; term.c_cc[VSTATUS] = _POSIX_VDISABLE;
@ -127,35 +129,46 @@ restart:
end = buf + bufsiz - 1; end = buf + bufsiz - 1;
for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) { for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) {
if (p < end) { if (p < end) {
if ((flags & RPP_SEVENBIT)) ch &= 0x7f; if ((flags & RPP_SEVENBIT) != 0) {
if (isalpha(ch)) { ch &= 0x7f;
if ((flags & RPP_FORCELOWER)) ch = tolower(ch); }
if ((flags & RPP_FORCEUPPER)) ch = toupper(ch); if (isalpha(ch) != 0) {
if ((flags & RPP_FORCELOWER) != 0) {
ch = tolower(ch);
}
if ((flags & RPP_FORCEUPPER) != 0) {
ch = toupper(ch);
}
} }
*p++ = ch; *p++ = ch;
} }
} }
*p = '\0'; *p = '\0';
save_errno = errno; save_errno = errno;
if (!(term.c_lflag & ECHO)) (void)write(output, "\n", 1); if ((term.c_lflag & ECHO) == 0u) {
(void)write(output, "\n", 1);
}
/* Restore old terminal settings and signals. */ /* Restore old terminal settings and signals. */
if (memcmp(&term, &oterm, sizeof(term)) != 0) if (memcmp(&term, &oterm, sizeof(term)) != 0) {
(void)tcsetattr(input, _T_FLUSH, &oterm); (void)tcsetattr(input, _T_FLUSH, &oterm);
(void)sigaction(SIGINT, &saveint, NULL); }
(void)sigaction(SIGHUP, &savehup, NULL); (void)sigaction(SIGINT, &saveint, nullptr);
(void)sigaction(SIGQUIT, &savequit, NULL); (void)sigaction(SIGHUP, &savehup, nullptr);
(void)sigaction(SIGTERM, &saveterm, NULL); (void)sigaction(SIGQUIT, &savequit, nullptr);
(void)sigaction(SIGTSTP, &savetstp, NULL); (void)sigaction(SIGTERM, &saveterm, nullptr);
(void)sigaction(SIGTTIN, &savettin, NULL); (void)sigaction(SIGTSTP, &savetstp, nullptr);
(void)sigaction(SIGTTOU, &savettou, NULL); (void)sigaction(SIGTTIN, &savettin, nullptr);
if (input != STDIN_FILENO) (void)close(input); (void)sigaction(SIGTTOU, &savettou, nullptr);
if (input != STDIN_FILENO) {
(void)close(input);
}
/* /*
* If we were interrupted by a signal, resend it to ourselves * If we were interrupted by a signal, resend it to ourselves
* now that we have restored the signal handlers. * now that we have restored the signal handlers.
*/ */
if (signo) { if (signo != 0) {
kill(getpid(), signo); kill(getpid(), signo);
switch (signo) { switch (signo) {
case SIGTSTP: case SIGTSTP:
@ -167,7 +180,7 @@ restart:
} }
errno = save_errno; errno = save_errno;
return (nr == -1 ? NULL : buf); return (nr == -1 ? nullptr : buf);
} }
#endif /* HAVE_READPASSPHRASE */ #endif /* HAVE_READPASSPHRASE */

View File

@ -38,7 +38,7 @@
#include "NameIO.h" #include "NameIO.h"
#include "Range.h" #include "Range.h"
#include "StreamNameIO.h" #include "StreamNameIO.h"
#include "internal/easylogging++.h" #include "easylogging++.h"
#define NO_DES #define NO_DES
#include <openssl/ssl.h> #include <openssl/ssl.h>
@ -49,8 +49,6 @@
using namespace std; using namespace std;
using namespace encfs; using namespace encfs;
INITIALIZE_EASYLOGGINGPP
const int FSBlockSize = 256; const int FSBlockSize = 256;
static int checkErrorPropogation(const std::shared_ptr<Cipher> &cipher, static int checkErrorPropogation(const std::shared_ptr<Cipher> &cipher,
@ -175,11 +173,12 @@ bool runTests(const std::shared_ptr<Cipher> &cipher, bool verbose) {
cfg.assignKeyData(keyBuf, encodedKeySize); cfg.assignKeyData(keyBuf, encodedKeySize);
// save config // save config
//Creation of a temporary file should be more platform independent. On c++17 we could use std::filesystem. // Creation of a temporary file should be more platform independent. On
// c++17 we could use std::filesystem.
string name = "/tmp/encfstestXXXXXX"; string name = "/tmp/encfstestXXXXXX";
int tmpFd = mkstemp(&name[0]); int tmpFd = mkstemp(&name[0]);
rAssert(-1 != tmpFd); rAssert(-1 != tmpFd);
//mkstemp opens the temporary file, but we only need its name -> close it // mkstemp opens the temporary file, but we only need its name -> close it
rAssert(0 == close(tmpFd)); rAssert(0 == close(tmpFd));
{ {
auto ok = writeV6Config(name.c_str(), &cfg); auto ok = writeV6Config(name.c_str(), &cfg);
@ -192,9 +191,9 @@ bool runTests(const std::shared_ptr<Cipher> &cipher, bool verbose) {
auto ok = readV6Config(name.c_str(), &cfg2, nullptr); auto ok = readV6Config(name.c_str(), &cfg2, nullptr);
rAssert(ok == true); rAssert(ok == true);
} }
//delete the temporary file where we stored the config // delete the temporary file where we stored the config
rAssert(0 == unlink(name.c_str())); rAssert(0 == unlink(name.c_str()));
// check.. // check..
rAssert(cfg.cipherIface.implements(cfg2.cipherIface)); rAssert(cfg.cipherIface.implements(cfg2.cipherIface));
rAssert(cfg.keySize == cfg2.keySize); rAssert(cfg.keySize == cfg2.keySize);

File diff suppressed because it is too large Load Diff

View File

@ -1,79 +0,0 @@
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
cmake_policy(VERSION 2.6)
project(tinyxml2)
include(GNUInstallDirs)
#enable_testing()
#CMAKE_BUILD_TOOL
################################
# set lib version here
set(GENERIC_LIB_VERSION "3.0.0")
set(GENERIC_LIB_SOVERSION "3")
################################
# Add common source
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/.")
################################
# Add custom target to copy all data
set(TARGET_DATA_COPY DATA_COPY)
if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
add_custom_target(
${TARGET_DATA_COPY}
COMMAND ${CMAKE_COMMAND} -E echo "In source build")
else(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
make_directory(${CMAKE_CURRENT_BINARY_DIR}/resources/)
add_custom_target(
${TARGET_DATA_COPY}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/resources/dream.xml ${CMAKE_CURRENT_BINARY_DIR}/resources/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/resources/empty.xml ${CMAKE_CURRENT_BINARY_DIR}/resources/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/resources/utf8test.xml ${CMAKE_CURRENT_BINARY_DIR}/resources/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/resources/utf8testverify.xml ${CMAKE_CURRENT_BINARY_DIR}/resources/)
endif(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
################################
# Add definitions
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif(MSVC)
################################
# Add targets
option(BUILD_SHARED_LIBS "build shared or static libraries" OFF)
add_library(tinyxml2 tinyxml2.cpp tinyxml2.h)
set_target_properties(tinyxml2 PROPERTIES
COMPILE_DEFINITIONS "TINYXML2_EXPORT"
VERSION "${GENERIC_LIB_VERSION}"
SOVERSION "${GENERIC_LIB_SOVERSION}")
add_executable(xmltest xmltest.cpp)
add_dependencies(xmltest tinyxml2)
add_dependencies(xmltest ${TARGET_DATA_COPY})
target_link_libraries(xmltest tinyxml2)
#install(TARGETS tinyxml2
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
# LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
# ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
#install(FILES tinyxml2.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
#foreach(p LIB INCLUDE)
# set(var CMAKE_INSTALL_${p}DIR)
# if(NOT IS_ABSOLUTE "${${var}}")
# set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")
# endif()
#endforeach()
#configure_file(tinyxml2.pc.in tinyxml2.pc @ONLY)
#install(FILES ${CMAKE_CURRENT_BINARY_DIR}/tinyxml2.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
#add_test(xmltest ${SAMPLE_NAME} COMMAND $<TARGET_FILE:${SAMPLE_NAME}>)

View File

@ -1,6 +0,0 @@
all: xmltest
xmltest: xmltest.cpp tinyxml2.cpp tinyxml2.h
test: clean xmltest
./xmltest
clean:
rm -f *.o xmltest

View File

@ -455,8 +455,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "الإعدادات المحملة غير متوافقة مع --reverse\n" msgstr "الإعدادات المحملة غير متوافقة مع --reverse\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "الدليل \"%s\" غير موجود. هل ينبغي إنشاؤه؟ (y، n) " msgstr "الدليل \"%s\" غير موجود. هل ينبغي إنشاؤه؟ (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -419,8 +419,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Дырэкторыя \"%s\" не існуе.Ці трэба яе стварыць? (y,n) " msgstr "Дырэкторыя \"%s\" не існуе.Ці трэба яе стварыць? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -446,8 +446,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Директорията \"%s\" не съществува. Да бъде ли създадена? (д,н) " msgstr "Директорията \"%s\" не съществува. Да бъде ли създадена? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -418,7 +418,7 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "" msgstr ""
msgid "" msgid ""

View File

@ -450,9 +450,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "" msgstr ""
"El directori \"%s\" no existeix. Desitges crear el nou directori? (y,n) " "El directori \"%s\" no existeix. Desitges crear el nou directori? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -450,8 +450,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Adresář \"%s\" neexistuje, má být vytvořen? (\"y\"-ano, \"n\"-ne) " msgstr "Adresář \"%s\" neexistuje, má být vytvořen? (\"y\"-ano, \"N\"-ne) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -451,8 +451,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Mappen \"%s\" eksisterer ikke. Skal den oprettes? (y, n) " msgstr "Mappen \"%s\" eksisterer ikke. Skal den oprettes? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -517,8 +517,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n" msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Das Verzeichnis »%s« existiert nicht. Soll es angelegt werden? (y,n) " msgstr "Das Verzeichnis »%s« existiert nicht. Soll es angelegt werden? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -486,9 +486,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n" msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "" msgstr ""
"Das Verzeichnis \"%s\" existiert nicht. Soll es angelegt werden? (j,n) " "Das Verzeichnis \"%s\" existiert nicht. Soll es angelegt werden? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -489,9 +489,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n" msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "" msgstr ""
"Das Verzeichnis \"%s\" existiert nicht. Soll es erstellt werden? (j,n) " "Das Verzeichnis \"%s\" existiert nicht. Soll es erstellt werden? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -490,9 +490,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n" msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "" msgstr ""
"Das Verzeichnis \"%s\" existiert nicht. Soll es angelegt werden? (y,n) " "Das Verzeichnis \"%s\" existiert nicht. Soll es angelegt werden? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -443,8 +443,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Ο φάκελος \"%s\" δεν υπάρχει. Να τον δημιουργήσω? (y/n) " msgstr "Ο φάκελος \"%s\" δεν υπάρχει. Να τον δημιουργήσω? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -153,7 +153,7 @@ msgid "Incorrect number of arguments for command \"%s\""
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "" msgstr ""
msgid "Unable to create directory: " msgid "Unable to create directory: "

View File

@ -423,8 +423,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "La dosierujo \"%s\" ne ekzistas. Ĉu ĝi estu kreota? " msgstr "La dosierujo \"%s\" ne ekzistas. Ĉu ĝi estu kreota? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -512,8 +512,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "La configuración cargada no es compatible con --reverse\n" msgstr "La configuración cargada no es compatible con --reverse\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "El directorio \"%s\" no existe. ¿Debería ser creado? (S,N) " msgstr "El directorio \"%s\" no existe. ¿Debería ser creado? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -468,8 +468,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "El directorio \"%s\" no existe. ¿Deberia ser creado? (s,n) " msgstr "El directorio \"%s\" no existe. ¿Deberia ser creado? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -420,7 +420,7 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "" msgstr ""
msgid "" msgid ""

View File

@ -415,7 +415,7 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "" msgstr ""
msgid "" msgid ""

View File

@ -482,8 +482,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Hakemistoa \"%s\" ei ole olemassa. Luodaanko se? (y,n) " msgstr "Hakemistoa \"%s\" ei ole olemassa. Luodaanko se? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -493,8 +493,8 @@ msgstr ""
"La configuration chargée n'est pas compatible avec l'option --reverse\n" "La configuration chargée n'est pas compatible avec l'option --reverse\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Le répertoire \"%s\" n'existe pas. Doit-il être créé ? (y/n) " msgstr "Le répertoire \"%s\" n'existe pas. Doit-il être créé ? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -482,8 +482,8 @@ msgstr ""
"La configuration chargée n'est pas compatible avec l'option --reverse\n" "La configuration chargée n'est pas compatible avec l'option --reverse\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Le répertoire \"%s\" n'existe pas. Faut-il le créer ? (y/n) " msgstr "Le répertoire \"%s\" n'existe pas. Faut-il le créer ? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -484,8 +484,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "A configuración cargada non é compatíbel con --reverse\n" msgstr "A configuración cargada non é compatíbel con --reverse\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "O directorio \"%s\" non existe. Debería crealo? (y,n) " msgstr "O directorio \"%s\" non existe. Debería crealo? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -477,8 +477,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "התצורה שנטענה אינה תואמת ל --reverse\n" msgstr "התצורה שנטענה אינה תואמת ל --reverse\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "התקייה \"%s\" אינה קיימת. האם ליצור אותה? (y,n) " msgstr "התקייה \"%s\" אינה קיימת. האם ליצור אותה? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -415,7 +415,7 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "" msgstr ""
msgid "" msgid ""

View File

@ -485,8 +485,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "A \"%s\" könyvtár nem létezik. Létrehozzam? (y,n) " msgstr "A \"%s\" könyvtár nem létezik. Létrehozzam? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -432,9 +432,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "" msgstr ""
"Tidak ada direktori \"%s\", perlukah membuat direktori tersebut? (ya, tidak) " "Tidak ada direktori \"%s\", perlukah membuat direktori tersebut? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -521,8 +521,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "La configurazione caricata non è compatibile con --reverse\n" msgstr "La configurazione caricata non è compatibile con --reverse\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "La directory \"%s\" non esiste. Deve essere creata? (y/n) " msgstr "La directory \"%s\" non esiste. Deve essere creata? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -452,8 +452,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "ディレクトリ \"%s\" が存在しません。作成しますか? (y,n) " msgstr "ディレクトリ \"%s\" が存在しません。作成しますか? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -420,7 +420,7 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "" msgstr ""
msgid "" msgid ""

View File

@ -475,8 +475,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Mape \"%s\" neeksistē. Vai radīt to? (y,n) " msgstr "Mape \"%s\" neeksistē. Vai radīt to? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -447,8 +447,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "Innstillingene som er lastet er ikke kompatible med --reverse\n" msgstr "Innstillingene som er lastet er ikke kompatible med --reverse\n"
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Katalogen \"%s\" eksisterer ikke. Skal den opprettes? (y,n) " msgstr "Katalogen \"%s\" eksisterer ikke. Skal den opprettes? (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

View File

@ -434,8 +434,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "" msgstr ""
#, c-format #, c-format
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
msgstr "Das Verzeichnis \"%s\" existiert nicht, soll es erstellt werden (y,n) " msgstr "Das Verzeichnis \"%s\" existiert nicht, soll es erstellt werden (y,N) "
msgid "" msgid ""
"The external initialization-vector chaining option has been\n" "The external initialization-vector chaining option has been\n"

Some files were not shown because too many files have changed in this diff Show More