mirror of
https://github.com/vgough/encfs.git
synced 2024-11-21 23:43:26 +01:00
Merge branch 'master' into errno
This commit is contained in:
commit
21d1d3dcfa
18
.travis.yml
18
.travis.yml
@ -1,9 +1,12 @@
|
||||
dist: trusty
|
||||
|
||||
language: cpp
|
||||
|
||||
sudo: false
|
||||
sudo: true
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
branches:
|
||||
only:
|
||||
@ -18,12 +21,11 @@ env:
|
||||
- secure: "KuAAwjiIqkk4vqSX/M3ZZIvQs6edm+tV8IADiklTUYZIFyxu8FgZ6RbDdMD2sef5bNZA1OZhlcbeRtiKff5CfMtvzc607Lg3NUkpi+ShMynWgqS/e0uCMf9ogEJlUiZMxf4juBi7v6DyMl/WV6pAdJmdfHtzcj8GF2mgTfQjkO8="
|
||||
|
||||
before_script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake ..
|
||||
- sudo modprobe fuse
|
||||
- cmake --version
|
||||
|
||||
script:
|
||||
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make && ./checkops ; fi
|
||||
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./build.sh && ./test.sh ; fi
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
@ -39,7 +41,9 @@ addons:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- attr
|
||||
- clang
|
||||
- cmake
|
||||
- fuse
|
||||
- libfuse-dev
|
||||
|
||||
- gettext
|
||||
- cmake3
|
||||
|
103
CMakeLists.txt
103
CMakeLists.txt
@ -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)
|
||||
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)
|
||||
|
||||
set (ENCFS_MAJOR 1)
|
||||
set (ENCFS_MINOR 9)
|
||||
set (ENCFS_PATCH 1)
|
||||
set (ENCFS_PATCH 2)
|
||||
set (ENCFS_VERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}.${ENCFS_PATCH}")
|
||||
set (ENCFS_SOVERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}")
|
||||
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}
|
||||
"${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 (ENABLE_NLS "compile with Native Language Support (using gettext)" ON)
|
||||
option (INSTALL_LIBENCFS "install libencfs" OFF)
|
||||
option (LINT "enable lint output" OFF)
|
||||
|
||||
if (NOT DEFINED LIB_INSTALL_DIR)
|
||||
set (LIB_INSTALL_DIR lib)
|
||||
@ -31,10 +36,10 @@ if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.0)
|
||||
else ()
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
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")
|
||||
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()
|
||||
message ("** No CMAKE C++11 check. If the build breaks, you're on your own.")
|
||||
endif()
|
||||
@ -55,6 +60,12 @@ if (APPLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WIN32 OR APPLE)
|
||||
set(DEFAULT_CASE_INSENSITIVE TRUE)
|
||||
else()
|
||||
set(DEFAULT_CASE_INSENSITIVE FALSE)
|
||||
endif()
|
||||
|
||||
# Check for FUSE.
|
||||
find_package (FUSE REQUIRED)
|
||||
include_directories (${FUSE_INCLUDE_DIR})
|
||||
@ -64,17 +75,6 @@ add_definitions (-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26)
|
||||
find_package (OpenSSL REQUIRED)
|
||||
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)
|
||||
|
||||
# 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 (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.
|
||||
# Output error is misleading, so do this test quietly.
|
||||
include (CheckCXXSourceCompiles)
|
||||
set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
|
||||
set (CMAKE_REQUIRED_QUIET True)
|
||||
check_cxx_source_compiles ("#include <sys/types.h>
|
||||
#include <sys/xattr.h>
|
||||
int main() { getxattr(0,0,0,0,0,0); return 1; }
|
||||
" XATTR_ADD_OPT)
|
||||
set (CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
|
||||
|
||||
# Check if we have some standard functions.
|
||||
include (CheckFuncs)
|
||||
check_function_exists_glibc (lchmod HAVE_LCHMOD)
|
||||
check_function_exists_glibc (utimensat HAVE_UTIMENSAT)
|
||||
check_function_exists_glibc (fdatasync HAVE_FDATASYNC)
|
||||
|
||||
set (CMAKE_THREAD_PREFER_PTHREAD)
|
||||
find_package (Threads REQUIRED)
|
||||
@ -139,6 +139,40 @@ if (ENABLE_NLS)
|
||||
add_definitions(-DLOCALEDIR="${CMAKE_INSTALL_PREFIX}/share/locale")
|
||||
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
|
||||
encfs/autosprintf.cpp
|
||||
encfs/base64.cpp
|
||||
@ -177,6 +211,7 @@ target_link_libraries(encfs
|
||||
${FUSE_LIBRARIES}
|
||||
${OPENSSL_LIBRARIES}
|
||||
${TINYXML_LIBRARIES}
|
||||
${EASYLOGGING_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${Intl_LIBRARIES}
|
||||
)
|
||||
@ -203,6 +238,11 @@ target_link_libraries (encfs-bin encfs)
|
||||
set_target_properties (encfs-bin PROPERTIES OUTPUT_NAME "encfs")
|
||||
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)
|
||||
target_link_libraries (encfsctl encfs)
|
||||
install (TARGETS encfsctl DESTINATION bin)
|
||||
@ -213,13 +253,18 @@ target_link_libraries (makekey encfs)
|
||||
add_executable (checkops encfs/test.cpp)
|
||||
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.
|
||||
file (GLOB_RECURSE all_headers ${CMAKE_CURRENT_LIST_DIR}/*.h)
|
||||
add_custom_target (all_placeholder SOURCES ${all_headers})
|
||||
|
||||
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
|
||||
COMMAND ${POD2MAN} -u --section=1 --release=${ENCFS_VERSION} --center=${ENCFS_NAME}
|
||||
${CMAKE_CURRENT_LIST_DIR}/encfs/encfs.pod encfs.1)
|
||||
@ -229,20 +274,8 @@ if (POD2MAN)
|
||||
${CMAKE_CURRENT_LIST_DIR}/encfs/encfsctl.pod encfsctl.1)
|
||||
|
||||
install (FILES ${CMAKE_BINARY_DIR}/encfs.1 ${CMAKE_BINARY_DIR}/encfsctl.1
|
||||
DESTINATION share/man/man1)
|
||||
DESTINATION ${MAN_DESTINATION})
|
||||
endif (POD2MAN)
|
||||
|
||||
# Tests
|
||||
enable_testing()
|
||||
add_test (NAME checkops
|
||||
COMMAND checkops)
|
||||
add_custom_target(tests COMMAND ${CMAKE_CURRENT_LIST_DIR}/test.sh)
|
||||
|
||||
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)
|
||||
|
11
ChangeLog
11
ChangeLog
@ -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
|
||||
==================
|
||||
===================
|
||||
* add filehandle null check
|
||||
* bump version to 1.9.1
|
||||
* prevent crash in elpp when verbose logging is enabled
|
||||
|
@ -46,7 +46,7 @@ EncFS depends on a number of libraries:
|
||||
* tinyxml2 : for reading and writing XML configuration files
|
||||
* gettext : 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
|
||||
|
||||
Compiling on Debian and Ubuntu
|
||||
|
12
build.sh
12
build.sh
@ -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
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
else
|
||||
cd build
|
||||
cd ..
|
||||
fi
|
||||
|
||||
make
|
||||
make -j2 -C build
|
||||
|
||||
|
@ -2,4 +2,4 @@ set -x
|
||||
set -e
|
||||
mkdir 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 ..
|
||||
|
@ -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
|
@ -10,5 +10,5 @@ dependencies:
|
||||
test:
|
||||
override:
|
||||
- bash ./ci/config.sh
|
||||
- cd build && make && make test && make install
|
||||
- cd build && make && ./checkops && make install
|
||||
- /tmp/encfs/bin/encfsctl --version
|
||||
|
@ -13,8 +13,8 @@ if (APPLE)
|
||||
set (FUSE_NAMES libosxfuse.dylib fuse)
|
||||
set (FUSE_SUFFIXES osxfuse fuse)
|
||||
else (APPLE)
|
||||
set (FUSE_NAMES fuse)
|
||||
set (FUSE_SUFFIXES fuse)
|
||||
set (FUSE_NAMES fuse refuse)
|
||||
set (FUSE_SUFFIXES fuse refuse)
|
||||
endif (APPLE)
|
||||
|
||||
# find includes
|
||||
|
59
cmake/FindIntl.cmake
Normal file
59
cmake/FindIntl.cmake
Normal 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()
|
@ -3,8 +3,14 @@
|
||||
#cmakedefine HAVE_ATTR_XATTR_H
|
||||
#cmakedefine HAVE_SYS_XATTR_H
|
||||
#cmakedefine XATTR_ADD_OPT
|
||||
#cmakedefine XATTR_LLIST
|
||||
|
||||
#cmakedefine HAVE_LCHMOD
|
||||
#cmakedefine HAVE_FDATASYNC
|
||||
|
||||
#cmakedefine HAVE_DIRENT_D_TYPE
|
||||
|
||||
#cmakedefine DEFAULT_CASE_INSENSITIVE
|
||||
|
||||
/* TODO: add other thread library support. */
|
||||
#cmakedefine CMAKE_USE_PTHREADS_INIT
|
||||
|
2
devmode
2
devmode
@ -1,5 +1,5 @@
|
||||
# Script which sets up the CMake build for Debug mode.
|
||||
# After running, chdir to the build subdir ane run "make"
|
||||
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" $@
|
||||
|
@ -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.
|
||||
* For reverse encryption, the cache must not be used at all, because
|
||||
* the lower file may have changed behind our back. */
|
||||
if ((_noCache == false) && (req.offset == _cache.offset) &&
|
||||
(_cache.dataLen != 0)) {
|
||||
if ((!_noCache) && (req.offset == _cache.offset) && (_cache.dataLen != 0)) {
|
||||
// satisfy request from cache
|
||||
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);
|
||||
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) {
|
||||
@ -101,7 +104,9 @@ int BlockFileIO::cacheWriteOneBlock(const IORequest &req) {
|
||||
_cache.offset = req.offset;
|
||||
_cache.dataLen = req.dataLen;
|
||||
int res = writeOneBlock(req);
|
||||
if (res < 0) clearCache(_cache, _blockSize);
|
||||
if (res < 0) {
|
||||
clearCache(_cache, _blockSize);
|
||||
}
|
||||
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
|
||||
// readOneBlock().
|
||||
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
|
||||
// individually
|
||||
MemBlock mb; // in case we need to allocate a temporary block..
|
||||
IORequest blockReq; // for requests we may need to make
|
||||
blockReq.dataLen = _blockSize;
|
||||
blockReq.data = NULL;
|
||||
// if the request is larger then a block, then request each block
|
||||
// individually
|
||||
MemBlock mb; // in case we need to allocate a temporary block..
|
||||
IORequest blockReq; // for requests we may need to make
|
||||
blockReq.dataLen = _blockSize;
|
||||
blockReq.data = nullptr;
|
||||
|
||||
unsigned char *out = req.data;
|
||||
while (size) {
|
||||
blockReq.offset = blockNum * _blockSize;
|
||||
unsigned char *out = req.data;
|
||||
while (size != 0u) {
|
||||
blockReq.offset = blockNum * _blockSize;
|
||||
|
||||
// if we're reading a full block, then read directly into the
|
||||
// result buffer instead of using a temporary
|
||||
if (partialOffset == 0 && size >= (size_t)_blockSize)
|
||||
blockReq.data = out;
|
||||
else {
|
||||
if (!mb.data) mb = MemoryPool::allocate(_blockSize);
|
||||
blockReq.data = mb.data;
|
||||
// if we're reading a full block, then read directly into the
|
||||
// result buffer instead of using a temporary
|
||||
if (partialOffset == 0 && size >= (size_t)_blockSize) {
|
||||
blockReq.data = out;
|
||||
} else {
|
||||
if (mb.data == nullptr) {
|
||||
mb = MemoryPool::allocate(_blockSize);
|
||||
}
|
||||
|
||||
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;
|
||||
blockReq.data = mb.data;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -184,7 +195,9 @@ int BlockFileIO::write(const IORequest &req) {
|
||||
CHECK(_blockSize != 0);
|
||||
|
||||
off_t fileSize = getSize();
|
||||
if (fileSize < 0) return fileSize;
|
||||
if (fileSize < 0) {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
// where write request begins
|
||||
off_t blockNum = req.offset / _blockSize;
|
||||
@ -195,39 +208,45 @@ int BlockFileIO::write(const IORequest &req) {
|
||||
ssize_t lastBlockSize = fileSize % _blockSize;
|
||||
|
||||
off_t lastNonEmptyBlock = lastFileBlock;
|
||||
if (lastBlockSize == 0) --lastNonEmptyBlock;
|
||||
if (lastBlockSize == 0) {
|
||||
--lastNonEmptyBlock;
|
||||
}
|
||||
|
||||
if (req.offset > fileSize) {
|
||||
// extend file first to fill hole with 0's..
|
||||
const bool forceWrite = false;
|
||||
int res = padFile(fileSize, req.offset, forceWrite);
|
||||
if (res < 0)
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// check against edge cases where we can just let the base class handle the
|
||||
// request as-is..
|
||||
if (partialOffset == 0 && req.dataLen <= _blockSize) {
|
||||
// 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
|
||||
// already there..
|
||||
if (blockNum == lastFileBlock && req.dataLen >= lastBlockSize)
|
||||
if (blockNum == lastFileBlock && req.dataLen >= lastBlockSize) {
|
||||
return cacheWriteOneBlock(req);
|
||||
}
|
||||
}
|
||||
|
||||
// have to merge data with existing block(s)..
|
||||
MemBlock mb;
|
||||
|
||||
IORequest blockReq;
|
||||
blockReq.data = NULL;
|
||||
blockReq.data = nullptr;
|
||||
blockReq.dataLen = _blockSize;
|
||||
|
||||
int res = 0;
|
||||
size_t size = req.dataLen;
|
||||
unsigned char *inPtr = req.data;
|
||||
while (size) {
|
||||
while (size != 0u) {
|
||||
blockReq.offset = blockNum * _blockSize;
|
||||
int toCopy = min((size_t)(_blockSize - partialOffset), size);
|
||||
|
||||
@ -241,7 +260,9 @@ int BlockFileIO::write(const IORequest &req) {
|
||||
} else {
|
||||
// need a temporary buffer, since we have to either merge or pad
|
||||
// the data.
|
||||
if (!mb.data) mb = MemoryPool::allocate(_blockSize);
|
||||
if (mb.data == nullptr) {
|
||||
mb = MemoryPool::allocate(_blockSize);
|
||||
}
|
||||
memset(mb.data, 0, _blockSize);
|
||||
blockReq.data = mb.data;
|
||||
|
||||
@ -257,8 +278,9 @@ int BlockFileIO::write(const IORequest &req) {
|
||||
}
|
||||
|
||||
// extend data if necessary..
|
||||
if (partialOffset + toCopy > blockReq.dataLen)
|
||||
if (partialOffset + toCopy > blockReq.dataLen) {
|
||||
blockReq.dataLen = partialOffset + toCopy;
|
||||
}
|
||||
}
|
||||
// merge in the data to be written..
|
||||
memcpy(blockReq.data + partialOffset, inPtr, toCopy);
|
||||
@ -277,7 +299,9 @@ int BlockFileIO::write(const IORequest &req) {
|
||||
partialOffset = 0;
|
||||
}
|
||||
|
||||
if (mb.data) MemoryPool::release(mb);
|
||||
if (mb.data != nullptr) {
|
||||
MemoryPool::release(mb);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -309,7 +333,7 @@ int BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) {
|
||||
req.dataLen = oldSize % _blockSize;
|
||||
int outSize = newSize % _blockSize; // outSize > req.dataLen
|
||||
|
||||
if (outSize) {
|
||||
if (outSize != 0) {
|
||||
memset(mb.data, 0, outSize);
|
||||
if ((res = cacheReadOneBlock(req)) >= 0) {
|
||||
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;
|
||||
}
|
||||
@ -376,14 +402,17 @@ int BlockFileIO::truncateBase(off_t size, FileIO *base) {
|
||||
// states that it will pad with 0's.
|
||||
// do the truncate so that the underlying filesystem can allocate
|
||||
// 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;
|
||||
if (!(res < 0))
|
||||
if (!(res < 0)) {
|
||||
res = padFile(oldSize, size, forceWrite);
|
||||
}
|
||||
} else if (size == oldSize) {
|
||||
// the easiest case, but least likely....
|
||||
} else if (partialBlock) {
|
||||
} else if (partialBlock != 0) {
|
||||
// partial block after truncate. Need to read in the block being
|
||||
// truncated before the truncate. Then write it back out afterwards,
|
||||
// since the encoding will change..
|
||||
@ -396,23 +425,28 @@ int BlockFileIO::truncateBase(off_t size, FileIO *base) {
|
||||
req.data = mb.data;
|
||||
|
||||
ssize_t rdSz = cacheReadOneBlock(req);
|
||||
if (rdSz < 0)
|
||||
if (rdSz < 0) {
|
||||
res = rdSz;
|
||||
}
|
||||
|
||||
// do the truncate
|
||||
else if (base)
|
||||
else if (base != nullptr) {
|
||||
res = base->truncate(size);
|
||||
}
|
||||
|
||||
// write back out partial block
|
||||
req.dataLen = partialBlock;
|
||||
if (!res)
|
||||
if (!(res < 0)) {
|
||||
res = cacheWriteOneBlock(req);
|
||||
}
|
||||
|
||||
MemoryPool::release(mb);
|
||||
} else {
|
||||
// truncating on a block bounday. No need to re-encode the last
|
||||
// block..
|
||||
if (base) res = base->truncate(size);
|
||||
if (base != nullptr) {
|
||||
res = base->truncate(size);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "Cipher.h"
|
||||
#include "CipherKey.h"
|
||||
@ -29,7 +30,7 @@
|
||||
#include "Interface.h"
|
||||
#include "NameIO.h"
|
||||
#include "base64.h"
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include "intl/gettext.h"
|
||||
|
||||
namespace encfs {
|
||||
@ -38,7 +39,9 @@ static std::shared_ptr<NameIO> NewBlockNameIO(
|
||||
const Interface &iface, const std::shared_ptr<Cipher> &cipher,
|
||||
const CipherKey &key) {
|
||||
int blockSize = 8;
|
||||
if (cipher) blockSize = cipher->cipherBlockSize();
|
||||
if (cipher) {
|
||||
blockSize = cipher->cipherBlockSize();
|
||||
}
|
||||
|
||||
return std::shared_ptr<NameIO>(
|
||||
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 CipherKey &key) {
|
||||
int blockSize = 8;
|
||||
if (cipher) blockSize = cipher->cipherBlockSize();
|
||||
if (cipher) {
|
||||
blockSize = cipher->cipherBlockSize();
|
||||
}
|
||||
|
||||
return std::shared_ptr<NameIO>(
|
||||
new BlockNameIO(iface, cipher, key, blockSize, true));
|
||||
@ -88,26 +93,25 @@ static bool BlockIO32_registered = NameIO::Register(
|
||||
*/
|
||||
Interface BlockNameIO::CurrentInterface(bool caseInsensitive) {
|
||||
// implement major version 4 plus support for two prior versions
|
||||
if (caseInsensitive)
|
||||
if (caseInsensitive) {
|
||||
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,
|
||||
const std::shared_ptr<Cipher> &cipher,
|
||||
const CipherKey &key, int blockSize,
|
||||
BlockNameIO::BlockNameIO(const Interface &iface, std::shared_ptr<Cipher> cipher,
|
||||
CipherKey key, int blockSize,
|
||||
bool caseInsensitiveEncoding)
|
||||
: _interface(iface.current()),
|
||||
_bs(blockSize),
|
||||
_cipher(cipher),
|
||||
_key(key),
|
||||
_cipher(std::move(cipher)),
|
||||
_key(std::move(key)),
|
||||
_caseInsensitive(caseInsensitiveEncoding) {
|
||||
// just to be safe..
|
||||
rAssert(blockSize < 128);
|
||||
}
|
||||
|
||||
BlockNameIO::~BlockNameIO() {}
|
||||
BlockNameIO::~BlockNameIO() = default;
|
||||
|
||||
Interface BlockNameIO::interface() const {
|
||||
return CurrentInterface(_caseInsensitive);
|
||||
@ -118,10 +122,10 @@ int BlockNameIO::maxEncodedNameLen(int plaintextNameLen) const {
|
||||
// the size of too much space rather then too little.
|
||||
int numBlocks = (plaintextNameLen + _bs) / _bs;
|
||||
int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes
|
||||
if (_caseInsensitive)
|
||||
if (_caseInsensitive) {
|
||||
return B256ToB32Bytes(encodedNameLen);
|
||||
else
|
||||
return B256ToB64Bytes(encodedNameLen);
|
||||
}
|
||||
return B256ToB64Bytes(encodedNameLen);
|
||||
}
|
||||
|
||||
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..
|
||||
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);
|
||||
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.
|
||||
uint64_t tmpIV = 0;
|
||||
if (iv && _interface >= 3) tmpIV = *iv;
|
||||
if ((iv != nullptr) && _interface >= 3) {
|
||||
tmpIV = *iv;
|
||||
}
|
||||
|
||||
// include padding in MAC computation
|
||||
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]));
|
||||
|
||||
uint64_t tmpIV = 0;
|
||||
if (iv && _interface >= 3) tmpIV = *iv;
|
||||
if ((iv != nullptr) && _interface >= 3) {
|
||||
tmpIV = *iv;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
ok = _cipher->blockDecode((unsigned char *)tmpBuf + 2, decodedStreamLen,
|
||||
|
@ -41,8 +41,8 @@ class BlockNameIO : public NameIO {
|
||||
public:
|
||||
static Interface CurrentInterface(bool caseInsensitive = false);
|
||||
|
||||
BlockNameIO(const Interface &iface, const std::shared_ptr<Cipher> &cipher,
|
||||
const CipherKey &key, int blockSize,
|
||||
BlockNameIO(const Interface &iface, std::shared_ptr<Cipher> cipher,
|
||||
CipherKey key, int blockSize,
|
||||
bool caseInsensitiveEncoding = false);
|
||||
virtual ~BlockNameIO();
|
||||
|
||||
|
@ -18,10 +18,10 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@ -56,8 +56,8 @@ struct CipherAlg {
|
||||
Range blockSize;
|
||||
};
|
||||
|
||||
typedef multimap<string, CipherAlg> CipherMap_t;
|
||||
static CipherMap_t *gCipherMap = NULL;
|
||||
using CipherMap_t = multimap<string, CipherAlg>;
|
||||
static CipherMap_t *gCipherMap = nullptr;
|
||||
|
||||
std::list<Cipher::CipherAlgorithm> Cipher::GetAlgorithmList(
|
||||
bool includeHidden) {
|
||||
@ -65,7 +65,9 @@ std::list<Cipher::CipherAlgorithm> Cipher::GetAlgorithmList(
|
||||
|
||||
list<CipherAlgorithm> result;
|
||||
|
||||
if (!gCipherMap) return result;
|
||||
if (gCipherMap == nullptr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
CipherMap_t::const_iterator it;
|
||||
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 Range &blockSize, CipherConstructor fn,
|
||||
bool hidden) {
|
||||
if (!gCipherMap) gCipherMap = new CipherMap_t;
|
||||
if (gCipherMap == nullptr) {
|
||||
gCipherMap = new CipherMap_t;
|
||||
}
|
||||
|
||||
CipherAlg ca;
|
||||
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> result;
|
||||
|
||||
if (gCipherMap) {
|
||||
if (gCipherMap != nullptr) {
|
||||
CipherMap_t::const_iterator it = gCipherMap->find(name);
|
||||
if (it != gCipherMap->end()) {
|
||||
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> result;
|
||||
if (gCipherMap) {
|
||||
if (gCipherMap != nullptr) {
|
||||
CipherMap_t::const_iterator it;
|
||||
CipherMap_t::const_iterator mapEnd = gCipherMap->end();
|
||||
|
||||
@ -148,9 +152,9 @@ std::shared_ptr<Cipher> Cipher::New(const Interface &iface, int keyLen) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Cipher::Cipher() {}
|
||||
Cipher::Cipher() = default;
|
||||
|
||||
Cipher::~Cipher() {}
|
||||
Cipher::~Cipher() = default;
|
||||
|
||||
unsigned int Cipher::MAC_32(const unsigned char *src, int len,
|
||||
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,
|
||||
const CipherKey &encodingKey) {
|
||||
int encodedKeySize = this->encodedKeySize();
|
||||
unsigned char *keyBuf = new unsigned char[encodedKeySize];
|
||||
auto *keyBuf = new unsigned char[encodedKeySize];
|
||||
|
||||
// write the key, encoding it with itself.
|
||||
this->writeKey(key, keyBuf, encodingKey);
|
||||
|
||||
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);
|
||||
B64ToAscii(b64Key, b64Len);
|
||||
|
@ -44,8 +44,8 @@ class Cipher {
|
||||
public:
|
||||
// if no key length was indicated when cipher was registered, then keyLen
|
||||
// <= 0 will be used.
|
||||
typedef std::shared_ptr<Cipher> (*CipherConstructor)(const Interface &iface,
|
||||
int keyLenBits);
|
||||
using CipherConstructor = std::shared_ptr<Cipher> (*)(const Interface &iface,
|
||||
int keyLenBits);
|
||||
|
||||
struct CipherAlgorithm {
|
||||
std::string name;
|
||||
@ -55,7 +55,7 @@ class Cipher {
|
||||
Range blockSize;
|
||||
};
|
||||
|
||||
typedef std::list<CipherAlgorithm> AlgorithmList;
|
||||
using AlgorithmList = std::list<CipherAlgorithm>;
|
||||
static AlgorithmList GetAlgorithmList(bool includeHidden = false);
|
||||
|
||||
static std::shared_ptr<Cipher> New(const Interface &iface, int keyLen = -1);
|
||||
|
@ -20,14 +20,15 @@
|
||||
|
||||
#include "CipherFileIO.h"
|
||||
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <cerrno>
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <memory>
|
||||
#include <openssl/sha.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <utility>
|
||||
|
||||
#include "BlockFileIO.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..
|
||||
|
||||
CipherFileIO::CipherFileIO(const std::shared_ptr<FileIO> &_base,
|
||||
CipherFileIO::CipherFileIO(std::shared_ptr<FileIO> _base,
|
||||
const FSConfigPtr &cfg)
|
||||
: BlockFileIO(cfg->config->blockSize, cfg),
|
||||
base(_base),
|
||||
base(std::move(_base)),
|
||||
haveHeader(cfg->config->uniqueIV),
|
||||
externalIV(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";
|
||||
}
|
||||
|
||||
CipherFileIO::~CipherFileIO() {}
|
||||
CipherFileIO::~CipherFileIO() = default;
|
||||
|
||||
Interface CipherFileIO::interface() const { return CipherFileIO_iface; }
|
||||
|
||||
int CipherFileIO::open(int flags) {
|
||||
int res = base->open(flags);
|
||||
|
||||
if (res >= 0) lastFlags = flags;
|
||||
if (res >= 0) {
|
||||
lastFlags = flags;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -109,8 +112,9 @@ bool CipherFileIO::setIV(uint64_t iv) {
|
||||
}
|
||||
}
|
||||
if (fileIV == 0) {
|
||||
if (initHeader() < 0)
|
||||
if (initHeader() < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t oldIV = externalIV;
|
||||
@ -185,14 +189,18 @@ int CipherFileIO::initHeader() {
|
||||
req.data = buf;
|
||||
req.dataLen = 8;
|
||||
ssize_t readSize = base->read(req);
|
||||
if(readSize < 0)
|
||||
if(readSize < 0) {
|
||||
return readSize;
|
||||
}
|
||||
|
||||
if(!cipher->streamDecode(buf, sizeof(buf), externalIV, key))
|
||||
if(!cipher->streamDecode(buf, sizeof(buf), externalIV, key)) {
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
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..
|
||||
} else {
|
||||
@ -206,15 +214,19 @@ int CipherFileIO::initHeader() {
|
||||
}
|
||||
|
||||
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!";
|
||||
}
|
||||
} while (fileIV == 0); // don't accept 0 as an option..
|
||||
|
||||
if (base->isWritable()) {
|
||||
if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key))
|
||||
if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key)) {
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
IORequest req;
|
||||
req.offset = 0;
|
||||
@ -222,8 +234,9 @@ int CipherFileIO::initHeader() {
|
||||
req.dataLen = 8;
|
||||
|
||||
int res = base->write(req);
|
||||
if (res < 0)
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
VLOG(1) << "base not writable, IV not written..";
|
||||
}
|
||||
@ -244,16 +257,18 @@ bool CipherFileIO::writeHeader() {
|
||||
fileIV >>= 8;
|
||||
}
|
||||
|
||||
if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key))
|
||||
if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IORequest req;
|
||||
req.offset = 0;
|
||||
req.data = buf;
|
||||
req.dataLen = 8;
|
||||
|
||||
if (base->write(req) < 0)
|
||||
if (base->write(req) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -331,8 +346,9 @@ ssize_t CipherFileIO::readOneBlock(const IORequest &req) const {
|
||||
if (readSize > 0) {
|
||||
if (haveHeader && fileIV == 0) {
|
||||
int res = const_cast<CipherFileIO *>(this)->initHeader();
|
||||
if (res < 0)
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (readSize != bs) {
|
||||
@ -367,8 +383,9 @@ int CipherFileIO::writeOneBlock(const IORequest &req) {
|
||||
|
||||
if (haveHeader && fileIV == 0) {
|
||||
int res = initHeader();
|
||||
if (res < 0)
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
bool ok;
|
||||
@ -397,43 +414,45 @@ int CipherFileIO::writeOneBlock(const IORequest &req) {
|
||||
bool CipherFileIO::blockWrite(unsigned char *buf, int size,
|
||||
uint64_t _iv64) const {
|
||||
VLOG(1) << "Called blockWrite";
|
||||
if (!fsConfig->reverseEncryption)
|
||||
if (!fsConfig->reverseEncryption) {
|
||||
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,
|
||||
uint64_t _iv64) const {
|
||||
VLOG(1) << "Called streamWrite";
|
||||
if (!fsConfig->reverseEncryption)
|
||||
if (!fsConfig->reverseEncryption) {
|
||||
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,
|
||||
uint64_t _iv64) const {
|
||||
if (fsConfig->reverseEncryption)
|
||||
if (fsConfig->reverseEncryption) {
|
||||
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,
|
||||
uint64_t _iv64) const {
|
||||
if (fsConfig->reverseEncryption)
|
||||
if (fsConfig->reverseEncryption) {
|
||||
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) {
|
||||
@ -453,15 +472,18 @@ int CipherFileIO::truncate(off_t size) {
|
||||
}
|
||||
}
|
||||
int res = initHeader();
|
||||
if (res < 0)
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// can't let BlockFileIO call base->truncate(), since it would be using
|
||||
// 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;
|
||||
}
|
||||
@ -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
|
||||
unsigned char headerBuf[HEADER_SIZE];
|
||||
int res = const_cast<CipherFileIO *>(this)->generateReverseHeader(headerBuf);
|
||||
if (res < 0)
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Copy the request so we can modify it without affecting the caller
|
||||
IORequest req = origReq;
|
||||
@ -502,8 +525,9 @@ ssize_t CipherFileIO::read(const IORequest &origReq) const {
|
||||
* to the data. */
|
||||
if (req.offset < 0) {
|
||||
headerBytes = -req.offset;
|
||||
if (req.dataLen < headerBytes)
|
||||
if (req.dataLen < headerBytes) {
|
||||
headerBytes = req.dataLen; // only up to the number of bytes requested
|
||||
}
|
||||
VLOG(1) << "Adding " << headerBytes << " header bytes";
|
||||
|
||||
// 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);
|
||||
|
||||
// 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.
|
||||
* 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
|
||||
ssize_t readBytes = BlockFileIO::read(req);
|
||||
VLOG(1) << "read " << readBytes << " bytes from backing file";
|
||||
if (readBytes < 0)
|
||||
if (readBytes < 0) {
|
||||
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(); }
|
||||
|
@ -45,7 +45,7 @@ struct IORequest;
|
||||
*/
|
||||
class CipherFileIO : public BlockFileIO {
|
||||
public:
|
||||
CipherFileIO(const std::shared_ptr<FileIO> &base, const FSConfigPtr &cfg);
|
||||
CipherFileIO(std::shared_ptr<FileIO> base, const FSConfigPtr &cfg);
|
||||
virtual ~CipherFileIO();
|
||||
|
||||
virtual Interface interface() const;
|
||||
|
@ -22,8 +22,8 @@
|
||||
|
||||
namespace encfs {
|
||||
|
||||
AbstractCipherKey::AbstractCipherKey() {}
|
||||
AbstractCipherKey::AbstractCipherKey() = default;
|
||||
|
||||
AbstractCipherKey::~AbstractCipherKey() {}
|
||||
AbstractCipherKey::~AbstractCipherKey() = default;
|
||||
|
||||
} // namespace encfs
|
||||
|
@ -31,7 +31,7 @@ class AbstractCipherKey {
|
||||
virtual ~AbstractCipherKey();
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<AbstractCipherKey> CipherKey;
|
||||
using CipherKey = std::shared_ptr<AbstractCipherKey>;
|
||||
|
||||
} // namespace encfs
|
||||
|
||||
|
@ -33,23 +33,27 @@ using namespace std;
|
||||
|
||||
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
|
||||
// into mapped variables.
|
||||
bool ConfigReader::load(const char *fileName) {
|
||||
struct stat stbuf;
|
||||
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 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);
|
||||
close(fd);
|
||||
@ -126,11 +130,11 @@ ConfigVar ConfigReader::toVar() const {
|
||||
|
||||
ConfigVar ConfigReader::operator[](const std::string &varName) const {
|
||||
// read only
|
||||
map<string, ConfigVar>::const_iterator it = vars.find(varName);
|
||||
if (it == vars.end())
|
||||
auto it = vars.find(varName);
|
||||
if (it == vars.end()) {
|
||||
return ConfigVar();
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
ConfigVar &ConfigReader::operator[](const std::string &varName) {
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include "ConfigVar.h"
|
||||
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "Error.h"
|
||||
@ -43,10 +43,10 @@ ConfigVar::ConfigVar(const ConfigVar &src) { pd = src.pd; }
|
||||
ConfigVar::~ConfigVar() { pd.reset(); }
|
||||
|
||||
ConfigVar &ConfigVar::operator=(const ConfigVar &src) {
|
||||
if (src.pd == pd)
|
||||
if (src.pd == pd) {
|
||||
return *this;
|
||||
else
|
||||
pd = src.pd;
|
||||
}
|
||||
pd = src.pd;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -56,7 +56,9 @@ void ConfigVar::resetOffset() { pd->offset = 0; }
|
||||
int ConfigVar::read(unsigned char *buffer_, int bytes) const {
|
||||
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;
|
||||
|
||||
@ -106,13 +108,15 @@ void ConfigVar::writeInt(int val) {
|
||||
// find the starting point - we only need to output starting at the most
|
||||
// significant non-zero digit..
|
||||
int start = 0;
|
||||
while (digit[start] == 0x80) ++start;
|
||||
while (digit[start] == 0x80) {
|
||||
++start;
|
||||
}
|
||||
|
||||
write(digit + start, 5 - start);
|
||||
}
|
||||
|
||||
int ConfigVar::readInt() const {
|
||||
const unsigned char *buf = (const unsigned char *)buffer();
|
||||
const auto *buf = (const unsigned char *)buffer();
|
||||
int bytes = this->size();
|
||||
int offset = at();
|
||||
int value = 0;
|
||||
@ -122,7 +126,7 @@ int ConfigVar::readInt() const {
|
||||
|
||||
do {
|
||||
unsigned char tmp = buf[offset++];
|
||||
highBitSet = tmp & 0x80;
|
||||
highBitSet = ((tmp & 0x80) != 0);
|
||||
|
||||
value = (value << 7) | (int)(tmp & 0x7f);
|
||||
} while (highBitSet && offset < bytes);
|
||||
@ -139,10 +143,10 @@ int ConfigVar::readInt(int defaultValue) const {
|
||||
int bytes = this->size();
|
||||
int offset = at();
|
||||
|
||||
if (offset >= bytes)
|
||||
if (offset >= bytes) {
|
||||
return defaultValue;
|
||||
else
|
||||
return readInt();
|
||||
}
|
||||
return readInt();
|
||||
}
|
||||
|
||||
bool ConfigVar::readBool(bool defaultValue) const {
|
||||
@ -184,7 +188,7 @@ const ConfigVar &operator>>(const ConfigVar &src, std::string &result) {
|
||||
|
||||
unsigned char tmpBuf[32];
|
||||
if (length > (int)sizeof(tmpBuf)) {
|
||||
unsigned char *ptr = new unsigned char[length];
|
||||
auto *ptr = new unsigned char[length];
|
||||
readLen = src.read(ptr, length);
|
||||
result.assign((char *)ptr, length);
|
||||
delete[] ptr;
|
||||
|
@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <utility>
|
||||
|
||||
#include "Context.h"
|
||||
@ -29,11 +29,12 @@
|
||||
namespace encfs {
|
||||
|
||||
EncFS_Context::EncFS_Context() {
|
||||
pthread_cond_init(&wakeupCond, 0);
|
||||
pthread_mutex_init(&wakeupMutex, 0);
|
||||
pthread_mutex_init(&contextMutex, 0);
|
||||
pthread_cond_init(&wakeupCond, nullptr);
|
||||
pthread_mutex_init(&wakeupMutex, nullptr);
|
||||
pthread_mutex_init(&contextMutex, nullptr);
|
||||
|
||||
usageCount = 0;
|
||||
currentFuseFh = 1;
|
||||
}
|
||||
|
||||
EncFS_Context::~EncFS_Context() {
|
||||
@ -69,31 +70,28 @@ void EncFS_Context::setRoot(const std::shared_ptr<DirNode> &r) {
|
||||
Lock lock(contextMutex);
|
||||
|
||||
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);
|
||||
|
||||
int count = usageCount;
|
||||
*usage = usageCount;
|
||||
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) {
|
||||
Lock lock(contextMutex);
|
||||
|
||||
FileMap::iterator it = openFiles.find(std::string(path));
|
||||
auto it = openFiles.find(std::string(path));
|
||||
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
|
||||
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) {
|
||||
Lock lock(contextMutex);
|
||||
|
||||
FileMap::iterator it = openFiles.find(std::string(from));
|
||||
auto it = openFiles.find(std::string(from));
|
||||
if (it != openFiles.end()) {
|
||||
auto val = it->second;
|
||||
openFiles.erase(it);
|
||||
@ -111,26 +109,61 @@ void EncFS_Context::renameNode(const char *from, const char *to) {
|
||||
}
|
||||
}
|
||||
|
||||
FileNode *EncFS_Context::putNode(const char *path,
|
||||
std::shared_ptr<FileNode> &&node) {
|
||||
// putNode stores "node" under key "path" in the "openFiles" map. It
|
||||
// increments the reference count if the key already exists.
|
||||
void EncFS_Context::putNode(const char *path, std::shared_ptr<FileNode> node) {
|
||||
Lock lock(contextMutex);
|
||||
auto &list = openFiles[std::string(path)];
|
||||
list.push_front(std::move(node));
|
||||
return list.front().get();
|
||||
// The length of "list" serves as the reference count.
|
||||
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);
|
||||
|
||||
FileMap::iterator it = openFiles.find(std::string(path));
|
||||
auto it = openFiles.find(std::string(path));
|
||||
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 (it->second.empty()) {
|
||||
// If no reference to "fnode" remains, drop the entry from fuseFhMap
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -21,7 +21,9 @@
|
||||
#ifndef _Context_incl_
|
||||
#define _Context_incl_
|
||||
|
||||
#include <forward_list>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <pthread.h>
|
||||
#include <set>
|
||||
@ -44,12 +46,11 @@ class EncFS_Context {
|
||||
|
||||
std::shared_ptr<FileNode> lookupNode(const char *path);
|
||||
|
||||
int getAndResetUsageCounter();
|
||||
int openFileCount() const;
|
||||
void getAndResetUsageCounter(int *usage, int *openCount);
|
||||
|
||||
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);
|
||||
|
||||
@ -70,6 +71,9 @@ class EncFS_Context {
|
||||
pthread_cond_t wakeupCond;
|
||||
pthread_mutex_t wakeupMutex;
|
||||
|
||||
uint64_t nextFuseFh();
|
||||
std::shared_ptr<FileNode> lookupFuseFh(uint64_t);
|
||||
|
||||
private:
|
||||
/* This placeholder is what is referenced in FUSE context (passed to
|
||||
* callbacks).
|
||||
@ -81,15 +85,17 @@ class EncFS_Context {
|
||||
* us.
|
||||
*/
|
||||
|
||||
typedef std::unordered_map<std::string,
|
||||
std::forward_list<std::shared_ptr<FileNode>>>
|
||||
FileMap;
|
||||
using FileMap =
|
||||
std::unordered_map<std::string, std::list<std::shared_ptr<FileNode>>>;
|
||||
|
||||
mutable pthread_mutex_t contextMutex;
|
||||
FileMap openFiles;
|
||||
|
||||
int usageCount;
|
||||
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);
|
||||
|
@ -35,8 +35,9 @@
|
||||
#include <sys/fsuid.h>
|
||||
#endif
|
||||
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include "Context.h"
|
||||
#include "Error.h"
|
||||
@ -51,20 +52,13 @@ class DirDeleter {
|
||||
void operator()(DIR *d) { ::closedir(d); }
|
||||
};
|
||||
|
||||
DirTraverse::DirTraverse(const std::shared_ptr<DIR> &_dirPtr, uint64_t _iv,
|
||||
const std::shared_ptr<NameIO> &_naming)
|
||||
: dir(_dirPtr), iv(_iv), naming(_naming) {}
|
||||
DirTraverse::DirTraverse(std::shared_ptr<DIR> _dirPtr, uint64_t _iv,
|
||||
std::shared_ptr<NameIO> _naming)
|
||||
: dir(std::move(_dirPtr)), iv(_iv), naming(std::move(_naming)) {}
|
||||
|
||||
DirTraverse::DirTraverse(const DirTraverse &src)
|
||||
: dir(src.dir), iv(src.iv), naming(src.naming) {}
|
||||
DirTraverse::DirTraverse(const DirTraverse &src) = default;
|
||||
|
||||
DirTraverse &DirTraverse::operator=(const DirTraverse &src) {
|
||||
dir = src.dir;
|
||||
iv = src.iv;
|
||||
naming = src.naming;
|
||||
|
||||
return *this;
|
||||
}
|
||||
DirTraverse &DirTraverse::operator=(const DirTraverse &src) = default;
|
||||
|
||||
DirTraverse::~DirTraverse() {
|
||||
dir.reset();
|
||||
@ -76,25 +70,28 @@ static bool _nextName(struct dirent *&de, const std::shared_ptr<DIR> &dir,
|
||||
int *fileType, ino_t *inode) {
|
||||
de = ::readdir(dir.get());
|
||||
|
||||
if (de) {
|
||||
if (fileType) {
|
||||
#if defined(_DIRENT_HAVE_D_TYPE) || defined(__FreeBSD__) || defined(__APPLE__)
|
||||
if (de != nullptr) {
|
||||
if (fileType != nullptr) {
|
||||
#if defined(HAVE_DIRENT_D_TYPE)
|
||||
*fileType = de->d_type;
|
||||
#else
|
||||
#warning "struct dirent.d_type not supported"
|
||||
*fileType = 0;
|
||||
#endif
|
||||
}
|
||||
if (inode) *inode = de->d_ino;
|
||||
if (inode != nullptr) {
|
||||
*inode = de->d_ino;
|
||||
}
|
||||
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) {
|
||||
struct dirent *de = 0;
|
||||
struct dirent *de = nullptr;
|
||||
while (_nextName(de, dir, fileType, inode)) {
|
||||
try {
|
||||
uint64_t localIv = iv;
|
||||
@ -109,9 +106,9 @@ std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) {
|
||||
}
|
||||
|
||||
std::string DirTraverse::nextInvalid() {
|
||||
struct dirent *de = 0;
|
||||
struct dirent *de = nullptr;
|
||||
// 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 {
|
||||
uint64_t localIv = iv;
|
||||
naming->decodePath(de->d_name, &localIv);
|
||||
@ -143,17 +140,16 @@ class RenameOp {
|
||||
list<RenameEl>::const_iterator last;
|
||||
|
||||
public:
|
||||
RenameOp(DirNode *_dn, const std::shared_ptr<list<RenameEl> > &_renameList)
|
||||
: dn(_dn), renameList(_renameList) {
|
||||
RenameOp(DirNode *_dn, std::shared_ptr<list<RenameEl> > _renameList)
|
||||
: dn(_dn), renameList(std::move(_renameList)) {
|
||||
last = renameList->begin();
|
||||
}
|
||||
|
||||
RenameOp(const RenameOp &src)
|
||||
: dn(src.dn), renameList(src.renameList), last(src.last) {}
|
||||
RenameOp(const RenameOp &src) = default;
|
||||
|
||||
~RenameOp();
|
||||
|
||||
operator bool() const { return renameList.get() != nullptr; }
|
||||
operator bool() const { return renameList != nullptr; }
|
||||
|
||||
bool apply();
|
||||
void undo();
|
||||
@ -220,7 +216,7 @@ void RenameOp::undo() {
|
||||
// list has to be processed backwards, otherwise we may rename
|
||||
// directories and directory contents in the wrong order!
|
||||
int undoCount = 0;
|
||||
list<RenameEl>::const_iterator it = last;
|
||||
auto it = last;
|
||||
|
||||
while (it != renameList->begin()) {
|
||||
--it;
|
||||
@ -242,7 +238,7 @@ void RenameOp::undo() {
|
||||
|
||||
DirNode::DirNode(EncFS_Context *_ctx, const string &sourceDir,
|
||||
const FSConfigPtr &_config) {
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
pthread_mutex_init(&mutex, nullptr);
|
||||
|
||||
Lock _lock(mutex);
|
||||
|
||||
@ -253,7 +249,7 @@ DirNode::DirNode(EncFS_Context *_ctx, const string &sourceDir,
|
||||
naming = fsConfig->nameCoding;
|
||||
}
|
||||
|
||||
DirNode::~DirNode() {}
|
||||
DirNode::~DirNode() = default;
|
||||
|
||||
bool DirNode::hasDirectoryNameDependency() const {
|
||||
return naming ? naming->getChainedNameIV() : false;
|
||||
@ -355,23 +351,24 @@ DirTraverse DirNode::openDir(const char *plaintextPath) {
|
||||
string cyName = rootDir + naming->encodePath(plaintextPath);
|
||||
|
||||
DIR *dir = ::opendir(cyName.c_str());
|
||||
if (dir == NULL) {
|
||||
if (dir == nullptr) {
|
||||
int eno = errno;
|
||||
VLOG(1) << "opendir error " << strerror(eno);
|
||||
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,
|
||||
@ -386,16 +383,20 @@ bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP,
|
||||
string sourcePath = rootDir + fromCPart;
|
||||
|
||||
// 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..
|
||||
VLOG(1) << "opendir " << sourcePath;
|
||||
std::shared_ptr<DIR> dir =
|
||||
std::shared_ptr<DIR>(opendir(sourcePath.c_str()), DirDeleter());
|
||||
if (!dir) return false;
|
||||
if (!dir) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct dirent *de = NULL;
|
||||
while ((de = ::readdir(dir.get())) != NULL) {
|
||||
struct dirent *de = nullptr;
|
||||
while ((de = ::readdir(dir.get())) != nullptr) {
|
||||
// decode the name using the oldIV
|
||||
uint64_t localIV = fromIV;
|
||||
string plainName;
|
||||
@ -431,7 +432,7 @@ bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP,
|
||||
ren.newPName = string(toP) + '/' + plainName;
|
||||
|
||||
bool isDir;
|
||||
#if defined(_DIRENT_HAVE_D_TYPE)
|
||||
#if defined(HAVE_DIRENT_D_TYPE)
|
||||
if (de->d_type != DT_UNKNOWN) {
|
||||
isDir = (de->d_type == DT_DIR);
|
||||
} else
|
||||
@ -477,16 +478,17 @@ bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP,
|
||||
will have changed..
|
||||
|
||||
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
|
||||
// Undo everything if we encounter an error!
|
||||
std::shared_ptr<list<RenameEl> > renameList(new list<RenameEl>);
|
||||
if (!genRenameList(*renameList.get(), fromP, toP)) {
|
||||
RLOG(WARNING) << "Error during generation of recursive rename list";
|
||||
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,
|
||||
@ -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
|
||||
int olduid = -1;
|
||||
int oldgid = -1;
|
||||
if (uid != 0) olduid = setfsuid(uid);
|
||||
if (gid != 0) oldgid = setfsgid(gid);
|
||||
if (uid != 0) {
|
||||
olduid = setfsuid(uid);
|
||||
}
|
||||
if (gid != 0) {
|
||||
oldgid = setfsgid(gid);
|
||||
}
|
||||
|
||||
int res = ::mkdir(cyName.c_str(), mode);
|
||||
|
||||
if (olduid >= 0) setfsuid(olduid);
|
||||
if (oldgid >= 0) setfsgid(oldgid);
|
||||
if (olduid >= 0) {
|
||||
setfsuid(olduid);
|
||||
}
|
||||
if (oldgid >= 0) {
|
||||
setfsgid(oldgid);
|
||||
}
|
||||
|
||||
if (res == -1) {
|
||||
int eno = errno;
|
||||
RLOG(WARNING) << "mkdir error on " << cyName << " mode " << mode << ": "
|
||||
<< strerror(eno);
|
||||
res = -eno;
|
||||
} else
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -536,7 +547,9 @@ int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) {
|
||||
renameOp = newRenameOp(fromPlaintext, toPlaintext);
|
||||
|
||||
if (!renameOp || !renameOp->apply()) {
|
||||
if (renameOp) renameOp->undo();
|
||||
if (renameOp) {
|
||||
renameOp->undo();
|
||||
}
|
||||
|
||||
RLOG(WARNING) << "rename aborted";
|
||||
return -EACCES;
|
||||
@ -557,7 +570,9 @@ int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) {
|
||||
res = -errno;
|
||||
renameNode(toPlaintext, fromPlaintext, false);
|
||||
|
||||
if (renameOp) renameOp->undo();
|
||||
if (renameOp) {
|
||||
renameOp->undo();
|
||||
}
|
||||
} else if (preserve_mtime) {
|
||||
struct utimbuf ut;
|
||||
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!";
|
||||
} else {
|
||||
res = ::link(fromCName.c_str(), toCName.c_str());
|
||||
if (res == -1)
|
||||
if (res == -1) {
|
||||
res = -errno;
|
||||
else
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
std::shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to,
|
||||
bool forwardMode) {
|
||||
std::shared_ptr<FileNode> node = findOrCreate(from);
|
||||
@ -621,7 +639,9 @@ std::shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to,
|
||||
<< cname;
|
||||
|
||||
if (node->setName(to, cname.c_str(), newIV, forwardMode)) {
|
||||
if (ctx) ctx->renameNode(from, to);
|
||||
if (ctx != nullptr) {
|
||||
ctx->renameNode(from, to);
|
||||
}
|
||||
} else {
|
||||
// rename error! - put it back
|
||||
RLOG(ERROR) << "renameNode failed";
|
||||
@ -631,18 +651,30 @@ std::shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to,
|
||||
|
||||
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> 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;
|
||||
@ -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
|
||||
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.
|
||||
*/ std::shared_ptr<FileNode> DirNode::openNode(const char *plainName,
|
||||
const char *requestor, int flags,
|
||||
int *result) {
|
||||
"result" is set to -1 on failure, a value >= 0 on success.
|
||||
*/
|
||||
std::shared_ptr<FileNode> DirNode::openNode(const char *plainName,
|
||||
const char *requestor, int flags,
|
||||
int *result) {
|
||||
(void)requestor;
|
||||
rAssert(result != NULL);
|
||||
rAssert(result != nullptr);
|
||||
Lock _lock(mutex);
|
||||
|
||||
std::shared_ptr<FileNode> node = findOrCreate(plainName);
|
||||
|
||||
if (node && (*result = node->open(flags)) >= 0)
|
||||
if (node && (*result = node->open(flags)) >= 0) {
|
||||
return node;
|
||||
else
|
||||
return std::shared_ptr<FileNode>();
|
||||
}
|
||||
return std::shared_ptr<FileNode>();
|
||||
}
|
||||
|
||||
int DirNode::unlink(const char *plaintextName) {
|
||||
@ -680,7 +714,7 @@ int DirNode::unlink(const char *plaintextName) {
|
||||
Lock _lock(mutex);
|
||||
|
||||
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
|
||||
// hide open files for us, then we can't allow an unlink of an open
|
||||
// file..
|
||||
|
@ -48,8 +48,8 @@ struct RenameEl;
|
||||
|
||||
class DirTraverse {
|
||||
public:
|
||||
DirTraverse(const std::shared_ptr<DIR> &dirPtr, uint64_t iv,
|
||||
const std::shared_ptr<NameIO> &naming);
|
||||
DirTraverse(std::shared_ptr<DIR> dirPtr, uint64_t iv,
|
||||
std::shared_ptr<NameIO> naming);
|
||||
DirTraverse(const DirTraverse &src);
|
||||
~DirTraverse();
|
||||
|
||||
|
@ -1,22 +1,34 @@
|
||||
#include "Error.h"
|
||||
|
||||
INITIALIZE_EASYLOGGINGPP
|
||||
|
||||
namespace encfs {
|
||||
|
||||
el::base::DispatchAction rlogAction = el::base::DispatchAction::NormalLog;
|
||||
|
||||
Error::Error(const char *msg) : runtime_error(msg) {}
|
||||
|
||||
void initLogging(bool enable_debug) {
|
||||
el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput);
|
||||
void initLogging(bool enable_debug, bool is_daemon) {
|
||||
|
||||
el::Configurations defaultConf;
|
||||
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");
|
||||
if (!enable_debug) {
|
||||
defaultConf.set(el::Level::Debug, el::ConfigurationType::Enabled, "false");
|
||||
std::string prefix = "%datetime ";
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
// Provides compatibility with RLog's rAssert, which throws an Error exception.
|
||||
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace encfs {
|
||||
@ -21,9 +21,9 @@ class Error : public std::runtime_error {
|
||||
RLOG(ERROR) << "Assert failed: " << 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.
|
||||
// Not thread-safe, so any change must occur outside of threading context.
|
||||
|
@ -130,7 +130,7 @@ struct FSConfig {
|
||||
: forceDecode(false), reverseEncryption(false), idleTracking(false) {}
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<FSConfig> FSConfigPtr;
|
||||
using FSConfigPtr = std::shared_ptr<FSConfig>;
|
||||
|
||||
} // namespace encfs
|
||||
|
||||
|
@ -22,9 +22,9 @@
|
||||
|
||||
namespace encfs {
|
||||
|
||||
FileIO::FileIO() {}
|
||||
FileIO::FileIO() = default;
|
||||
|
||||
FileIO::~FileIO() {}
|
||||
FileIO::~FileIO() = default;
|
||||
|
||||
int FileIO::blockSize() const { return 1; }
|
||||
|
||||
|
@ -18,9 +18,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <cerrno>
|
||||
#include <cinttypes>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
@ -53,29 +53,38 @@ namespace encfs {
|
||||
*/
|
||||
|
||||
FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
|
||||
const char *plaintextName_, const char *cipherName_) {
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
const char *plaintextName_, const char *cipherName_,
|
||||
uint64_t fuseFh) {
|
||||
|
||||
pthread_mutex_init(&mutex, nullptr);
|
||||
|
||||
Lock _lock(mutex);
|
||||
|
||||
this->canary = CANARY_OK;
|
||||
|
||||
this->_pname = plaintextName_;
|
||||
this->_cname = cipherName_;
|
||||
this->parent = parent_;
|
||||
|
||||
this->fsConfig = cfg;
|
||||
|
||||
this->fuseFh = fuseFh;
|
||||
|
||||
// chain RawFileIO & CipherFileIO
|
||||
std::shared_ptr<FileIO> rawIO(new RawFileIO(_cname));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
FileNode::~FileNode() {
|
||||
// FileNode mutex should be locked before the destructor is called
|
||||
// pthread_mutex_lock( &mutex );
|
||||
|
||||
canary = CANARY_DESTROYED;
|
||||
_pname.assign(_pname.length(), '\0');
|
||||
_cname.assign(_cname.length(), '\0');
|
||||
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) {
|
||||
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);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileNode::setName(const char *plaintextName_, const char *cipherName_,
|
||||
uint64_t iv, bool setIVFirst) {
|
||||
// Lock _lock( mutex );
|
||||
if (cipherName_) VLOG(1) << "calling setIV on " << cipherName_;
|
||||
if (cipherName_ != nullptr) {
|
||||
VLOG(1) << "calling setIV on " << cipherName_;
|
||||
}
|
||||
|
||||
if (setIVFirst) {
|
||||
if (fsConfig->config->externalIVChaining && !setIV(io, iv)) return false;
|
||||
if (fsConfig->config->externalIVChaining && !setIV(io, iv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// now change the name..
|
||||
if (plaintextName_) this->_pname = plaintextName_;
|
||||
if (cipherName_) {
|
||||
if (plaintextName_ != nullptr) {
|
||||
this->_pname = plaintextName_;
|
||||
}
|
||||
if (cipherName_ != nullptr) {
|
||||
this->_cname = cipherName_;
|
||||
io->setFileName(cipherName_);
|
||||
}
|
||||
@ -115,8 +130,10 @@ bool FileNode::setName(const char *plaintextName_, const char *cipherName_,
|
||||
std::string oldPName = _pname;
|
||||
std::string oldCName = _cname;
|
||||
|
||||
if (plaintextName_) this->_pname = plaintextName_;
|
||||
if (cipherName_) {
|
||||
if (plaintextName_ != nullptr) {
|
||||
this->_pname = plaintextName_;
|
||||
}
|
||||
if (cipherName_ != nullptr) {
|
||||
this->_cname = 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)) {
|
||||
res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode);
|
||||
if (res >= 0) res = ::close(res);
|
||||
} else if (S_ISFIFO(mode))
|
||||
if (res >= 0) {
|
||||
res = ::close(res);
|
||||
}
|
||||
} else if (S_ISFIFO(mode)) {
|
||||
res = ::mkfifo(_cname.c_str(), mode);
|
||||
else
|
||||
} else {
|
||||
res = ::mknod(_cname.c_str(), mode, rdev);
|
||||
}
|
||||
|
||||
if (res == -1) {
|
||||
int eno = errno;
|
||||
@ -173,8 +193,12 @@ int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) {
|
||||
res = -eno;
|
||||
}
|
||||
|
||||
if (olduid >= 0) setfsuid(olduid);
|
||||
if (oldgid >= 0) setfsgid(oldgid);
|
||||
if (olduid >= 0) {
|
||||
setfsuid(olduid);
|
||||
}
|
||||
if (oldgid >= 0) {
|
||||
setfsgid(oldgid);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -236,21 +260,24 @@ int FileNode::sync(bool datasync) {
|
||||
int fh = io->open(O_RDONLY);
|
||||
if (fh >= 0) {
|
||||
int res = -EIO;
|
||||
#ifdef FDATASYNC
|
||||
if (datasync)
|
||||
#ifdef HAVE_FDATASYNC
|
||||
if (datasync) {
|
||||
res = fdatasync(fh);
|
||||
else
|
||||
} else {
|
||||
res = fsync(fh);
|
||||
}
|
||||
#else
|
||||
(void)datasync;
|
||||
res = fsync(fh);
|
||||
#endif
|
||||
|
||||
if (res == -1) res = -errno;
|
||||
if (res == -1) {
|
||||
res = -errno;
|
||||
}
|
||||
|
||||
return res;
|
||||
} else
|
||||
return fh;
|
||||
}
|
||||
return fh;
|
||||
}
|
||||
|
||||
} // namespace encfs
|
||||
|
@ -21,6 +21,7 @@
|
||||
#ifndef _FileNode_incl_
|
||||
#define _FileNode_incl_
|
||||
|
||||
#include <atomic>
|
||||
#include <inttypes.h>
|
||||
#include <memory>
|
||||
#include <pthread.h>
|
||||
@ -33,6 +34,10 @@
|
||||
#include "FileUtils.h"
|
||||
#include "encfs.h"
|
||||
|
||||
#define CANARY_OK 0x46040975
|
||||
#define CANARY_RELEASED 0x70c5610d
|
||||
#define CANARY_DESTROYED 0x52cdad90
|
||||
|
||||
namespace encfs {
|
||||
|
||||
class Cipher;
|
||||
@ -42,9 +47,16 @@ class FileIO;
|
||||
class FileNode {
|
||||
public:
|
||||
FileNode(DirNode *parent, const FSConfigPtr &cfg, const char *plaintextName,
|
||||
const char *cipherName);
|
||||
const char *cipherName, uint64_t fuseFh);
|
||||
~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 *cipherName() const;
|
||||
|
||||
|
@ -22,9 +22,10 @@
|
||||
#ifdef linux
|
||||
#define _XOPEN_SOURCE 500 // make sure pwrite() is pulled in
|
||||
#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 <cerrno>
|
||||
#include <cstdio>
|
||||
@ -111,54 +112,45 @@ struct ConfigInfo {
|
||||
// backward compatible support for older versions
|
||||
{".encfs5", Config_V5, "ENCFS5_CONFIG", readV5Config, writeV5Config,
|
||||
V5SubVersion, V5SubVersionDefault},
|
||||
{".encfs4", Config_V4, NULL, readV4Config, writeV4Config, 0, 0},
|
||||
{".encfs4", Config_V4, nullptr, readV4Config, writeV4Config, 0, 0},
|
||||
// no longer support earlier versions
|
||||
{".encfs3", Config_V3, NULL, NULL, NULL, 0, 0},
|
||||
{".encfs2", Config_Prehistoric, NULL, NULL, NULL, 0, 0},
|
||||
{".encfs", Config_Prehistoric, NULL, NULL, NULL, 0, 0},
|
||||
{NULL, Config_None, NULL, NULL, NULL, 0, 0}};
|
||||
{".encfs3", Config_V3, nullptr, nullptr, nullptr, 0, 0},
|
||||
{".encfs2", Config_Prehistoric, nullptr, nullptr, nullptr, 0, 0},
|
||||
{".encfs", Config_Prehistoric, nullptr, nullptr, nullptr, 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) {
|
||||
struct stat buf;
|
||||
if (!lstat(fileName, &buf)) {
|
||||
return true;
|
||||
} else {
|
||||
// XXX show perror?
|
||||
return false;
|
||||
}
|
||||
return lstat(fileName, &buf) == 0;
|
||||
}
|
||||
|
||||
bool isDirectory(const char *fileName) {
|
||||
struct stat buf;
|
||||
if (!lstat(fileName, &buf)) {
|
||||
if (lstat(fileName, &buf) == 0) {
|
||||
return S_ISDIR(buf.st_mode);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isAbsolutePath(const char *fileName) {
|
||||
if (fileName && fileName[0] != '\0' && fileName[0] == '/')
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
return (fileName != nullptr) && fileName[0] != '\0' && fileName[0] == '/';
|
||||
}
|
||||
|
||||
const char *lastPathElement(const char *name) {
|
||||
const char *loc = strrchr(name, '/');
|
||||
return loc ? loc + 1 : name;
|
||||
return loc != nullptr ? loc + 1 : name;
|
||||
}
|
||||
|
||||
std::string parentDirectory(const std::string &path) {
|
||||
size_t last = path.find_last_of('/');
|
||||
if (last == string::npos)
|
||||
if (last == string::npos) {
|
||||
return string("");
|
||||
else
|
||||
return path.substr(0, last);
|
||||
}
|
||||
return path.substr(0, last);
|
||||
}
|
||||
|
||||
bool userAllowMkdir(const char *path, mode_t mode) {
|
||||
@ -171,7 +163,7 @@ bool userAllowMkdir(int promptno, const char *path, mode_t mode) {
|
||||
// xgroup(setup)
|
||||
cerr << autosprintf(
|
||||
_("The directory \"%s\" does not exist. Should it be created? "
|
||||
"(y,n) "),
|
||||
"(y,N) "),
|
||||
path);
|
||||
char answer[10];
|
||||
char *res;
|
||||
@ -188,18 +180,17 @@ bool userAllowMkdir(int promptno, const char *path, mode_t mode) {
|
||||
}
|
||||
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);
|
||||
if (result < 0) {
|
||||
perror(_("Unable to create directory: "));
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
} else {
|
||||
// Directory not created, by user request
|
||||
cerr << _("Directory not created.") << "\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// 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,
|
||||
EncFSConfig *config) {
|
||||
if (nm->loadFunc) {
|
||||
if (nm->loadFunc != nullptr) {
|
||||
try {
|
||||
if ((*nm->loadFunc)(path, config, nm)) {
|
||||
config->cfgType = nm->type;
|
||||
@ -233,11 +224,11 @@ ConfigType readConfig_load(ConfigInfo *nm, const char *path,
|
||||
*/
|
||||
ConfigType readConfig(const string &rootDir, EncFSConfig *config) {
|
||||
ConfigInfo *nm = ConfigFileMapping;
|
||||
while (nm->fileName) {
|
||||
while (nm->fileName != nullptr) {
|
||||
// allow environment variable to override default config path
|
||||
if (nm->environmentOverride != NULL) {
|
||||
if (nm->environmentOverride != nullptr) {
|
||||
char *envFile = getenv(nm->environmentOverride);
|
||||
if (envFile != NULL) {
|
||||
if (envFile != nullptr) {
|
||||
if (!fileExists(envFile)) {
|
||||
RLOG(ERROR)
|
||||
<< "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
|
||||
string path = rootDir + nm->fileName;
|
||||
if (fileExists(path.c_str()))
|
||||
if (fileExists(path.c_str())) {
|
||||
return readConfig_load(nm, path.c_str(), config);
|
||||
}
|
||||
|
||||
++nm;
|
||||
}
|
||||
@ -323,7 +315,7 @@ bool readV6Config(const char *configFile, EncFSConfig *cfg, ConfigInfo *info) {
|
||||
|
||||
int encodedSize;
|
||||
config->read("encodedKeySize", &encodedSize);
|
||||
unsigned char *key = new unsigned char[encodedSize];
|
||||
auto *key = new unsigned char[encodedSize];
|
||||
config->readB64("encodedKeyData", key, encodedSize);
|
||||
cfg->assignKeyData(key, encodedSize);
|
||||
delete[] key;
|
||||
@ -331,7 +323,7 @@ bool readV6Config(const char *configFile, EncFSConfig *cfg, ConfigInfo *info) {
|
||||
if (cfg->subVersion >= 20080816) {
|
||||
int saltLen;
|
||||
config->read("saltLen", &saltLen);
|
||||
unsigned char *salt = new unsigned char[saltLen];
|
||||
auto *salt = new unsigned char[saltLen];
|
||||
config->readB64("saltData", salt, saltLen);
|
||||
cfg->assignSaltData(salt, saltLen);
|
||||
delete[] salt;
|
||||
@ -445,13 +437,15 @@ bool saveConfig(ConfigType type, const string &rootDir,
|
||||
bool ok = false;
|
||||
|
||||
ConfigInfo *nm = ConfigFileMapping;
|
||||
while (nm->fileName) {
|
||||
if (nm->type == type && nm->saveFunc) {
|
||||
while (nm->fileName != nullptr) {
|
||||
if (nm->type == type && (nm->saveFunc != nullptr)) {
|
||||
string path = rootDir + nm->fileName;
|
||||
if (nm->environmentOverride != NULL) {
|
||||
if (nm->environmentOverride != nullptr) {
|
||||
// use environment file if specified..
|
||||
const char *envFile = getenv(nm->environmentOverride);
|
||||
if (envFile != NULL) path.assign(envFile);
|
||||
if (envFile != nullptr) {
|
||||
path.assign(envFile);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@ -536,12 +530,12 @@ bool writeV6Config(const char *configFile, const EncFSConfig *cfg) {
|
||||
addEl(doc, config, "nameAlg", cfg->nameIface);
|
||||
addEl(doc, config, "keySize", cfg->keySize);
|
||||
addEl(doc, config, "blockSize", cfg->blockSize);
|
||||
addEl(doc, config, "uniqueIV", cfg->uniqueIV);
|
||||
addEl(doc, config, "chainedNameIV", cfg->chainedNameIV);
|
||||
addEl(doc, config, "externalIVChaining", cfg->externalIVChaining);
|
||||
addEl(doc, config, "uniqueIV", (int)cfg->uniqueIV);
|
||||
addEl(doc, config, "chainedNameIV", (int)cfg->chainedNameIV);
|
||||
addEl(doc, config, "externalIVChaining", (int)cfg->externalIVChaining);
|
||||
addEl(doc, config, "blockMACBytes", cfg->blockMACBytes);
|
||||
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, "encodedKeyData", cfg->keyData);
|
||||
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::const_iterator 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;
|
||||
}
|
||||
}
|
||||
@ -649,7 +644,7 @@ static Cipher::CipherAlgorithm selectCipherAlgorithm() {
|
||||
cout << "\n" << _("Enter the number corresponding to your choice: ");
|
||||
char answer[10];
|
||||
char *res = fgets(answer, sizeof(answer), stdin);
|
||||
int cipherNum = (res == 0 ? 0 : atoi(answer));
|
||||
int cipherNum = (res == nullptr ? 0 : atoi(answer));
|
||||
cout << "\n";
|
||||
|
||||
if (cipherNum < 1 || cipherNum > (int)algorithms.size()) {
|
||||
@ -658,8 +653,9 @@ static Cipher::CipherAlgorithm selectCipherAlgorithm() {
|
||||
}
|
||||
|
||||
it = algorithms.begin();
|
||||
while (--cipherNum) // numbering starts at 1
|
||||
while (--cipherNum != 0) { // numbering starts at 1
|
||||
++it;
|
||||
}
|
||||
|
||||
Cipher::CipherAlgorithm alg = *it;
|
||||
|
||||
@ -692,7 +688,7 @@ static Interface selectNameCoding() {
|
||||
cout << "\n" << _("Enter the number corresponding to your choice: ");
|
||||
char answer[10];
|
||||
char *res = fgets(answer, sizeof(answer), stdin);
|
||||
int algNum = (res == 0 ? 0 : atoi(answer));
|
||||
int algNum = (res == nullptr ? 0 : atoi(answer));
|
||||
cout << "\n";
|
||||
|
||||
if (algNum < 1 || algNum > (int)algorithms.size()) {
|
||||
@ -701,8 +697,9 @@ static Interface selectNameCoding() {
|
||||
}
|
||||
|
||||
it = algorithms.begin();
|
||||
while (--algNum) // numbering starts at 1
|
||||
while (--algNum != 0) { // numbering starts at 1
|
||||
++it;
|
||||
}
|
||||
|
||||
// xgroup(setup)
|
||||
cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str())
|
||||
@ -737,13 +734,17 @@ static int selectKeySize(const Cipher::CipherAlgorithm &alg) {
|
||||
if (numAvail < 5) {
|
||||
// show them all
|
||||
for (int i = 0; i <= numAvail; ++i) {
|
||||
if (i) cout << ", ";
|
||||
if (i != 0) {
|
||||
cout << ", ";
|
||||
}
|
||||
cout << alg.keyLength.min() + i * alg.keyLength.inc();
|
||||
}
|
||||
} else {
|
||||
// partial
|
||||
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.max() - alg.keyLength.inc();
|
||||
@ -754,7 +755,7 @@ static int selectKeySize(const Cipher::CipherAlgorithm &alg) {
|
||||
|
||||
char answer[10];
|
||||
char *res = fgets(answer, sizeof(answer), stdin);
|
||||
int keySize = (res == 0 ? 0 : atoi(answer));
|
||||
int keySize = (res == nullptr ? 0 : atoi(answer));
|
||||
cout << "\n";
|
||||
|
||||
keySize = alg.keyLength.closest(keySize);
|
||||
@ -794,7 +795,9 @@ static int selectBlockSize(const Cipher::CipherAlgorithm &alg) {
|
||||
char *res = fgets(answer, sizeof(answer), stdin);
|
||||
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);
|
||||
|
||||
@ -816,10 +819,11 @@ static bool boolDefault(const char *prompt, bool defaultValue) {
|
||||
|
||||
string yesno;
|
||||
|
||||
if (defaultValue == true)
|
||||
if (defaultValue) {
|
||||
yesno = "[y]/n: ";
|
||||
else
|
||||
} else {
|
||||
yesno = "y/[n]: ";
|
||||
}
|
||||
|
||||
string response;
|
||||
bool value;
|
||||
@ -831,10 +835,12 @@ static bool boolDefault(const char *prompt, bool defaultValue) {
|
||||
if (cin.fail() || response == "") {
|
||||
value = defaultValue;
|
||||
break;
|
||||
} else if (response == "y") {
|
||||
}
|
||||
if (response == "y") {
|
||||
value = true;
|
||||
break;
|
||||
} else if (response == "n") {
|
||||
}
|
||||
if (response == "n") {
|
||||
value = false;
|
||||
break;
|
||||
}
|
||||
@ -873,10 +879,11 @@ static void selectBlockMAC(int *macBytes, int *macRandBytes, bool forceMac) {
|
||||
addMAC = true;
|
||||
}
|
||||
|
||||
if (addMAC)
|
||||
if (addMAC) {
|
||||
*macBytes = 8;
|
||||
else
|
||||
} else {
|
||||
*macBytes = 0;
|
||||
}
|
||||
|
||||
// xgroup(setup)
|
||||
cout << _(
|
||||
@ -893,9 +900,13 @@ static void selectBlockMAC(int *macBytes, int *macRandBytes, bool forceMac) {
|
||||
char *res = fgets(answer, sizeof(answer), stdin);
|
||||
cout << "\n";
|
||||
|
||||
randSize = (res == 0 ? 0 : atoi(answer));
|
||||
if (randSize < 0) randSize = 0;
|
||||
if (randSize > 8) randSize = 8;
|
||||
randSize = (res == nullptr ? 0 : atoi(answer));
|
||||
if (randSize < 0) {
|
||||
randSize = 0;
|
||||
}
|
||||
if (randSize > 8) {
|
||||
randSize = 8;
|
||||
}
|
||||
|
||||
*macRandBytes = randSize;
|
||||
}
|
||||
@ -956,9 +967,7 @@ RootPtr createV6Config(EncFS_Context *ctx,
|
||||
const std::string passwordProgram = opts->passwordProgram;
|
||||
bool useStdin = opts->useStdin;
|
||||
bool reverseEncryption = opts->reverseEncryption;
|
||||
ConfigMode configMode = (useStdin &&
|
||||
opts->configMode == Config_Prompt) ? Config_Standard
|
||||
: opts->configMode;
|
||||
ConfigMode configMode = opts->configMode;
|
||||
bool annotate = opts->annotate;
|
||||
|
||||
RootPtr rootInfo;
|
||||
@ -978,7 +987,9 @@ RootPtr createV6Config(EncFS_Context *ctx,
|
||||
" 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);
|
||||
(void)res;
|
||||
@ -1024,7 +1035,7 @@ RootPtr createV6Config(EncFS_Context *ctx,
|
||||
alg = findCipherAlgorithm("AES", keySize);
|
||||
|
||||
// If case-insensitive system, opt for Block32 filename encoding
|
||||
#if defined(__APPLE__) || defined(WIN32)
|
||||
#if DEFAULT_CASE_INSENSITIVE
|
||||
nameIOIface = BlockNameIO::CurrentInterface(true);
|
||||
#else
|
||||
nameIOIface = BlockNameIO::CurrentInterface();
|
||||
@ -1053,6 +1064,14 @@ RootPtr createV6Config(EncFS_Context *ctx,
|
||||
if (opts->requireMac) {
|
||||
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()) {
|
||||
@ -1079,13 +1098,15 @@ RootPtr createV6Config(EncFS_Context *ctx,
|
||||
/* 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 == false) opts->readOnly = false;
|
||||
if (!uniqueIV) {
|
||||
opts->readOnly = false;
|
||||
}
|
||||
} else {
|
||||
chainedIV = selectChainedIV();
|
||||
uniqueIV = selectUniqueIV(true);
|
||||
if (chainedIV && uniqueIV)
|
||||
if (chainedIV && uniqueIV) {
|
||||
externalIV = selectExternalChainedIV();
|
||||
else {
|
||||
} else {
|
||||
// xgroup(setup)
|
||||
cout << _("External chained IV disabled, as both 'IV chaining'\n"
|
||||
"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"),
|
||||
alg.name.c_str(), keySize, blockSize);
|
||||
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);
|
||||
|
||||
@ -1156,7 +1176,7 @@ RootPtr createV6Config(EncFS_Context *ctx,
|
||||
"later using encfsctl.\n\n");
|
||||
|
||||
int encodedKeySize = cipher->encodedKeySize();
|
||||
unsigned char *encodedKey = new unsigned char[encodedKeySize];
|
||||
auto *encodedKey = new unsigned char[encodedKeySize];
|
||||
|
||||
CipherKey volumeKey = cipher->newRandomKey();
|
||||
|
||||
@ -1164,15 +1184,15 @@ RootPtr createV6Config(EncFS_Context *ctx,
|
||||
CipherKey userKey;
|
||||
VLOG(1) << "useStdin: " << useStdin;
|
||||
if (useStdin) {
|
||||
if (annotate) cerr << "$PROMPT$ new_passwd" << endl;
|
||||
if (annotate) {
|
||||
cerr << "$PROMPT$ new_passwd" << endl;
|
||||
}
|
||||
userKey = config->getUserKey(useStdin);
|
||||
} else if (!passwordProgram.empty())
|
||||
} else if (!passwordProgram.empty()) {
|
||||
userKey = config->getUserKey(passwordProgram, rootDir);
|
||||
else
|
||||
} else {
|
||||
userKey = config->getNewUserKey();
|
||||
|
||||
if (userKey == nullptr)
|
||||
return rootInfo;
|
||||
}
|
||||
|
||||
cipher->writeKey(volumeKey, encodedKey, userKey);
|
||||
userKey.reset();
|
||||
@ -1214,11 +1234,10 @@ RootPtr createV6Config(EncFS_Context *ctx,
|
||||
fsConfig->idleTracking = enableIdleTracking;
|
||||
fsConfig->opts = opts;
|
||||
|
||||
rootInfo = RootPtr(new EncFS_Root);
|
||||
rootInfo = std::make_shared<encfs::EncFS_Root>();
|
||||
rootInfo->cipher = cipher;
|
||||
rootInfo->volumeKey = volumeKey;
|
||||
rootInfo->root =
|
||||
std::shared_ptr<DirNode>(new DirNode(ctx, rootDir, fsConfig));
|
||||
rootInfo->root = std::make_shared<DirNode>(ctx, rootDir, fsConfig);
|
||||
|
||||
return rootInfo;
|
||||
}
|
||||
@ -1232,17 +1251,18 @@ void showFSInfo(const EncFSConfig *config) {
|
||||
config->cipherIface.name().c_str(), config->cipherIface.current(),
|
||||
config->cipherIface.revision(), config->cipherIface.age());
|
||||
// check if we support this interface..
|
||||
if (!cipher)
|
||||
if (!cipher) {
|
||||
cout << _(" (NOT supported)\n");
|
||||
else {
|
||||
} else {
|
||||
// if we're using a newer interface, show the version number
|
||||
if (config->cipherIface != cipher->interface()) {
|
||||
Interface iface = cipher->interface();
|
||||
// xgroup(diag)
|
||||
cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.current(),
|
||||
iface.revision(), iface.age());
|
||||
} else
|
||||
} else {
|
||||
cout << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -1264,8 +1284,9 @@ void showFSInfo(const EncFSConfig *config) {
|
||||
Interface iface = nameCoder->interface();
|
||||
cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.current(),
|
||||
iface.revision(), iface.age());
|
||||
} else
|
||||
} else {
|
||||
cout << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -1274,17 +1295,18 @@ void showFSInfo(const EncFSConfig *config) {
|
||||
if (!cipher) {
|
||||
// xgroup(diag)
|
||||
cout << _(" (NOT supported)\n");
|
||||
} else
|
||||
} else {
|
||||
cout << "\n";
|
||||
}
|
||||
}
|
||||
if (config->kdfIterations > 0 && config->salt.size() > 0) {
|
||||
if (config->kdfIterations > 0 && !config->salt.empty()) {
|
||||
cout << autosprintf(_("Using PBKDF2, with %i iterations"),
|
||||
config->kdfIterations)
|
||||
<< "\n";
|
||||
cout << autosprintf(_("Salt Size: %i bits"), (int)(8 * config->salt.size()))
|
||||
<< "\n";
|
||||
}
|
||||
if (config->blockMACBytes || config->blockMACRandBytes) {
|
||||
if ((config->blockMACBytes != 0) || (config->blockMACRandBytes != 0)) {
|
||||
if (config->subVersion < 20040813) {
|
||||
cout << autosprintf(
|
||||
// xgroup(diag)
|
||||
@ -1353,14 +1375,19 @@ CipherKey EncFSConfig::makeKey(const char *password, int passwdLen) {
|
||||
CipherKey userKey;
|
||||
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
|
||||
// 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
|
||||
salt.resize(20);
|
||||
}
|
||||
|
||||
if (salt.size() > 0) {
|
||||
if (!salt.empty()) {
|
||||
// if iterations isn't known, then we're creating a new key, so
|
||||
// randomize the salt..
|
||||
if (kdfIterations == 0 &&
|
||||
@ -1385,8 +1412,9 @@ CipherKey EncFSConfig::getUserKey(bool useStdin) {
|
||||
if (useStdin) {
|
||||
res = fgets(passBuf, sizeof(passBuf), stdin);
|
||||
// Kill the trailing newline.
|
||||
if (passBuf[strlen(passBuf) - 1] == '\n')
|
||||
if (passBuf[strlen(passBuf) - 1] == '\n') {
|
||||
passBuf[strlen(passBuf) - 1] = '\0';
|
||||
}
|
||||
} else {
|
||||
// xgroup(common)
|
||||
res = readpassphrase(_("EncFS Password: "), passBuf, sizeof(passBuf),
|
||||
@ -1394,10 +1422,12 @@ CipherKey EncFSConfig::getUserKey(bool useStdin) {
|
||||
}
|
||||
|
||||
CipherKey userKey;
|
||||
if (!res)
|
||||
cerr << _("Zero length password not allowed\n");
|
||||
else
|
||||
if (res == nullptr) {
|
||||
cerr << _("fatal: error reading password\n");
|
||||
exit(1);
|
||||
} else {
|
||||
userKey = makeKey(passBuf, strlen(passBuf));
|
||||
}
|
||||
|
||||
memset(passBuf, 0, sizeof(passBuf));
|
||||
|
||||
@ -1408,21 +1438,23 @@ std::string readPassword(int FD) {
|
||||
char buffer[1024];
|
||||
string result;
|
||||
|
||||
while (1) {
|
||||
while (true) {
|
||||
ssize_t rdSize = recv(FD, buffer, sizeof(buffer), 0);
|
||||
|
||||
if (rdSize > 0) {
|
||||
result.append(buffer, rdSize);
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
} else
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// chop off trailing "\n" if present..
|
||||
// This is done so that we can use standard programs like ssh-askpass
|
||||
// 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);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1454,7 +1486,7 @@ CipherKey EncFSConfig::getUserKey(const std::string &passProg,
|
||||
argv[0] = "/bin/sh";
|
||||
argv[1] = "-c";
|
||||
argv[2] = passProg.c_str();
|
||||
argv[3] = 0;
|
||||
argv[3] = nullptr;
|
||||
|
||||
// child process.. run the command and send output to fds[0]
|
||||
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]);
|
||||
close(fds[1]);
|
||||
|
||||
waitpid(pid, NULL, 0);
|
||||
waitpid(pid, nullptr, 0);
|
||||
|
||||
// convert to key..
|
||||
result = makeKey(password.c_str(), password.length());
|
||||
@ -1516,7 +1548,8 @@ CipherKey EncFSConfig::getNewUserKey() {
|
||||
char *res2 = readpassphrase(_("Verify Encfs Password: "), passBuf2,
|
||||
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));
|
||||
} else {
|
||||
// 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).
|
||||
* If uniqueIV is off, writing can be allowed, because there
|
||||
* is no header that could be overwritten */
|
||||
if (config->uniqueIV == false) opts->readOnly = false;
|
||||
if (!config->uniqueIV) {
|
||||
opts->readOnly = false;
|
||||
}
|
||||
}
|
||||
|
||||
// first, instanciate the cipher.
|
||||
@ -1567,7 +1602,7 @@ RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts) {
|
||||
}
|
||||
|
||||
if (opts->delayMount) {
|
||||
rootInfo = RootPtr(new EncFS_Root);
|
||||
rootInfo = std::make_shared<encfs::EncFS_Root>();
|
||||
rootInfo->cipher = cipher;
|
||||
rootInfo->root = std::shared_ptr<DirNode>();
|
||||
return rootInfo;
|
||||
@ -1578,12 +1613,17 @@ RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts) {
|
||||
|
||||
if (opts->passwordProgram.empty()) {
|
||||
VLOG(1) << "useStdin: " << opts->useStdin;
|
||||
if (opts->annotate) cerr << "$PROMPT$ passwd" << endl;
|
||||
if (opts->annotate) {
|
||||
cerr << "$PROMPT$ passwd" << endl;
|
||||
}
|
||||
userKey = config->getUserKey(opts->useStdin);
|
||||
} else
|
||||
} else {
|
||||
userKey = config->getUserKey(opts->passwordProgram, opts->rootDir);
|
||||
}
|
||||
|
||||
if (!userKey) return rootInfo;
|
||||
if (!userKey) {
|
||||
return rootInfo;
|
||||
}
|
||||
|
||||
VLOG(1) << "cipher key size = " << cipher->encodedKeySize();
|
||||
// decode volume key..
|
||||
@ -1623,11 +1663,10 @@ RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts) {
|
||||
fsConfig->reverseEncryption = opts->reverseEncryption;
|
||||
fsConfig->opts = opts;
|
||||
|
||||
rootInfo = RootPtr(new EncFS_Root);
|
||||
rootInfo = std::make_shared<encfs::EncFS_Root>();
|
||||
rootInfo->cipher = cipher;
|
||||
rootInfo->volumeKey = volumeKey;
|
||||
rootInfo->root =
|
||||
std::shared_ptr<DirNode>(new DirNode(ctx, opts->rootDir, fsConfig));
|
||||
rootInfo->root = std::make_shared<DirNode>(ctx, opts->rootDir, fsConfig);
|
||||
} else {
|
||||
if (opts->createIfNotFound) {
|
||||
// creating a new encrypted filesystem
|
||||
@ -1645,10 +1684,9 @@ int remountFS(EncFS_Context *ctx) {
|
||||
if (rootInfo) {
|
||||
ctx->setRoot(rootInfo->root);
|
||||
return 0;
|
||||
} else {
|
||||
RLOG(WARNING) << "Remount failed";
|
||||
return -EACCES;
|
||||
}
|
||||
RLOG(WARNING) << "Remount failed";
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
} // namespace encfs
|
||||
|
@ -60,7 +60,7 @@ struct 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 };
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
#include "Interface.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "ConfigVar.h"
|
||||
#include "Error.h"
|
||||
|
||||
@ -28,25 +30,19 @@ namespace encfs {
|
||||
Interface::Interface(const char *name_, int Current, int Revision, int Age)
|
||||
: _name(name_), _current(Current), _revision(Revision), _age(Age) {}
|
||||
|
||||
Interface::Interface(const std::string &name_, int Current, int Revision,
|
||||
int Age)
|
||||
: _name(name_), _current(Current), _revision(Revision), _age(Age) {}
|
||||
Interface::Interface(std::string name_, int Current, int Revision, int Age)
|
||||
: _name(std::move(name_)),
|
||||
_current(Current),
|
||||
_revision(Revision),
|
||||
_age(Age) {}
|
||||
|
||||
Interface::Interface(const Interface &src)
|
||||
: _name(src._name),
|
||||
_current(src._current),
|
||||
_revision(src._revision),
|
||||
_age(src._age) {}
|
||||
|
||||
= default;
|
||||
|
||||
Interface::Interface() : _current(0), _revision(0), _age(0) {}
|
||||
|
||||
Interface &Interface::operator=(const Interface &src) {
|
||||
_name = src._name;
|
||||
_current = src._current;
|
||||
_revision = src._revision;
|
||||
_age = src._age;
|
||||
return *this;
|
||||
}
|
||||
Interface &Interface::operator=(const Interface &src) = default;
|
||||
|
||||
const std::string &Interface::name() const { return _name; }
|
||||
|
||||
@ -87,12 +83,13 @@ static int sign( int a, int b )
|
||||
#else
|
||||
// simple, easy to check, unlikely to break due to unforseen events..
|
||||
static int sign(int a, int b) {
|
||||
if (a < b)
|
||||
if (a < b) {
|
||||
return 0;
|
||||
else if (a == b)
|
||||
}
|
||||
if (a == b) {
|
||||
return 1;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -111,7 +108,9 @@ bool Interface::implements(const Interface &B) const {
|
||||
<< ":" << age() << ") implements " << B.name() << "(" << B.current()
|
||||
<< ":" << B.revision() << ")";
|
||||
|
||||
if (name() != B.name()) return false;
|
||||
if (name() != B.name()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int currentDiff = current() - B.current();
|
||||
return (currentDiff >= 0 && currentDiff <= age());
|
||||
@ -120,29 +119,29 @@ bool Interface::implements(const Interface &B) const {
|
||||
bool operator<(const Interface &A, const Interface &B) {
|
||||
if (A.name() == B.name()) {
|
||||
return (diffSum(A, B) < EqualVersion);
|
||||
} else
|
||||
return A.name() < B.name();
|
||||
}
|
||||
return A.name() < B.name();
|
||||
}
|
||||
|
||||
bool operator>(const Interface &A, const Interface &B) {
|
||||
if (A.name() == B.name()) {
|
||||
return (diffSum(A, B) > EqualVersion);
|
||||
} else
|
||||
return A.name() < B.name();
|
||||
}
|
||||
return A.name() < B.name();
|
||||
}
|
||||
|
||||
bool operator<=(const Interface &A, const Interface &B) {
|
||||
if (A.name() == B.name()) {
|
||||
return (diffSum(A, B) <= EqualVersion);
|
||||
} else
|
||||
return A.name() < B.name();
|
||||
}
|
||||
return A.name() < B.name();
|
||||
}
|
||||
|
||||
bool operator>=(const Interface &A, const Interface &B) {
|
||||
if (A.name() == B.name()) {
|
||||
return (diffSum(A, B) >= EqualVersion);
|
||||
} else
|
||||
return A.name() < B.name();
|
||||
}
|
||||
return A.name() < B.name();
|
||||
}
|
||||
|
||||
ConfigVar &operator<<(ConfigVar &dst, const Interface &iface) {
|
||||
|
@ -37,7 +37,7 @@ class Interface {
|
||||
are implemented.
|
||||
*/
|
||||
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();
|
||||
|
||||
|
@ -20,10 +20,11 @@
|
||||
|
||||
#include "MACFileIO.h"
|
||||
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
#include <utility>
|
||||
|
||||
#include "BlockFileIO.h"
|
||||
#include "Cipher.h"
|
||||
@ -56,10 +57,9 @@ int dataBlockSize(const FSConfigPtr &cfg) {
|
||||
cfg->config->blockMACRandBytes;
|
||||
}
|
||||
|
||||
MACFileIO::MACFileIO(const std::shared_ptr<FileIO> &_base,
|
||||
const FSConfigPtr &cfg)
|
||||
MACFileIO::MACFileIO(std::shared_ptr<FileIO> _base, const FSConfigPtr &cfg)
|
||||
: BlockFileIO(dataBlockSize(cfg), cfg),
|
||||
base(_base),
|
||||
base(std::move(_base)),
|
||||
cipher(cfg->cipher),
|
||||
key(cfg->key),
|
||||
macBytes(cfg->config->blockMACBytes),
|
||||
@ -72,7 +72,7 @@ MACFileIO::MACFileIO(const std::shared_ptr<FileIO> &_base,
|
||||
<< ", randBytes = " << cfg->config->blockMACRandBytes;
|
||||
}
|
||||
|
||||
MACFileIO::~MACFileIO() {}
|
||||
MACFileIO::~MACFileIO() = default;
|
||||
|
||||
Interface MACFileIO::interface() const { return MACFileIO_iface; }
|
||||
|
||||
@ -137,7 +137,9 @@ off_t MACFileIO::getSize() const {
|
||||
int bs = blockSize() + headerSize;
|
||||
|
||||
off_t size = base->getSize();
|
||||
if (size > 0) size = locWithoutHeader(size, bs, headerSize);
|
||||
if (size > 0) {
|
||||
size = locWithoutHeader(size, bs, headerSize);
|
||||
}
|
||||
|
||||
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
|
||||
bool skipBlock = true;
|
||||
if (_allowHoles) {
|
||||
for (int i = 0; i < readSize; ++i)
|
||||
for (int i = 0; i < readSize; ++i) {
|
||||
if (tmp.data[i] != 0) {
|
||||
skipBlock = false;
|
||||
break;
|
||||
}
|
||||
} else if (macBytes > 0)
|
||||
}
|
||||
} else if (macBytes > 0) {
|
||||
skipBlock = false;
|
||||
}
|
||||
|
||||
if (readSize > headerSize) {
|
||||
if (!skipBlock) {
|
||||
@ -200,7 +204,9 @@ ssize_t MACFileIO::readOneBlock(const IORequest &req) const {
|
||||
memcpy(req.data, tmp.data + headerSize, readSize);
|
||||
} else {
|
||||
VLOG(1) << "readSize " << readSize << " at offset " << req.offset;
|
||||
if (readSize > 0) readSize = 0;
|
||||
if (readSize > 0) {
|
||||
readSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MemoryPool::release(mb);
|
||||
@ -224,8 +230,9 @@ int MACFileIO::writeOneBlock(const IORequest &req) {
|
||||
memset(newReq.data, 0, headerSize);
|
||||
memcpy(newReq.data + headerSize, req.data, req.dataLen);
|
||||
if (randBytes > 0) {
|
||||
if (!cipher->randomize(newReq.data + macBytes, randBytes, false))
|
||||
if (!cipher->randomize(newReq.data + macBytes, randBytes, false)) {
|
||||
return -EBADMSG;
|
||||
}
|
||||
}
|
||||
|
||||
if (macBytes > 0) {
|
||||
@ -251,9 +258,11 @@ int MACFileIO::truncate(off_t size) {
|
||||
int headerSize = macBytes + randBytes;
|
||||
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;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ class MACFileIO : public BlockFileIO {
|
||||
result in a warning message from encfs -- the garbled data will still
|
||||
be made available..
|
||||
*/
|
||||
MACFileIO(const std::shared_ptr<FileIO> &base, const FSConfigPtr &cfg);
|
||||
MACFileIO(std::shared_ptr<FileIO> base, const FSConfigPtr &cfg);
|
||||
MACFileIO();
|
||||
virtual ~MACFileIO();
|
||||
|
||||
|
@ -44,7 +44,7 @@ struct BlockList {
|
||||
};
|
||||
|
||||
static BlockList *allocBlock(int size) {
|
||||
BlockList *block = new BlockList;
|
||||
auto *block = new BlockList;
|
||||
block->size = size;
|
||||
block->data = BUF_MEM_new();
|
||||
BUF_MEM_grow(block->data, size);
|
||||
@ -61,30 +61,33 @@ static void freeBlock(BlockList *el) {
|
||||
}
|
||||
|
||||
static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static BlockList *gMemPool = NULL;
|
||||
static BlockList *gMemPool = nullptr;
|
||||
|
||||
MemBlock MemoryPool::allocate(int size) {
|
||||
pthread_mutex_lock(&gMPoolMutex);
|
||||
|
||||
BlockList *parent = NULL;
|
||||
BlockList *parent = nullptr;
|
||||
BlockList *block = gMemPool;
|
||||
// check if we already have a large enough block available..
|
||||
while (block != NULL && block->size < size) {
|
||||
while (block != nullptr && block->size < size) {
|
||||
parent = block;
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
// unlink block from list
|
||||
if (block) {
|
||||
if (!parent)
|
||||
if (block != nullptr) {
|
||||
if (parent == nullptr) {
|
||||
gMemPool = block->next;
|
||||
else
|
||||
} else {
|
||||
parent->next = block->next;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&gMPoolMutex);
|
||||
|
||||
if (!block) block = allocBlock(size);
|
||||
block->next = NULL;
|
||||
if (block == nullptr) {
|
||||
block = allocBlock(size);
|
||||
}
|
||||
block->next = nullptr;
|
||||
|
||||
MemBlock result;
|
||||
result.data = BLOCKDATA(block);
|
||||
@ -98,7 +101,7 @@ MemBlock MemoryPool::allocate(int size) {
|
||||
void MemoryPool::release(const MemBlock &mb) {
|
||||
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..
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(block->data->data, block->size);
|
||||
@ -115,11 +118,11 @@ void MemoryPool::destroyAll() {
|
||||
pthread_mutex_lock(&gMPoolMutex);
|
||||
|
||||
BlockList *block = gMemPool;
|
||||
gMemPool = NULL;
|
||||
gMemPool = nullptr;
|
||||
|
||||
pthread_mutex_unlock(&gMPoolMutex);
|
||||
|
||||
while (block != NULL) {
|
||||
while (block != nullptr) {
|
||||
BlockList *next = block->next;
|
||||
|
||||
freeBlock(block);
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include "NameIO.h"
|
||||
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <cstring>
|
||||
// for static build. Need to reference the modules which are registered at
|
||||
// run-time, to ensure that the linker doesn't optimize them away.
|
||||
@ -55,14 +55,14 @@ struct NameIOAlg {
|
||||
Interface iface;
|
||||
};
|
||||
|
||||
typedef multimap<string, NameIOAlg> NameIOMap_t;
|
||||
static NameIOMap_t *gNameIOMap = 0;
|
||||
using NameIOMap_t = multimap<string, NameIOAlg>;
|
||||
static NameIOMap_t *gNameIOMap = nullptr;
|
||||
|
||||
list<NameIO::Algorithm> NameIO::GetAlgorithmList(bool includeHidden) {
|
||||
AddSymbolReferences();
|
||||
|
||||
list<Algorithm> result;
|
||||
if (gNameIOMap) {
|
||||
if (gNameIOMap != nullptr) {
|
||||
NameIOMap_t::const_iterator it;
|
||||
NameIOMap_t::const_iterator end = gNameIOMap->end();
|
||||
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,
|
||||
const Interface &iface, Constructor constructor,
|
||||
bool hidden) {
|
||||
if (!gNameIOMap) gNameIOMap = new NameIOMap_t;
|
||||
if (gNameIOMap == nullptr) {
|
||||
gNameIOMap = new NameIOMap_t;
|
||||
}
|
||||
|
||||
NameIOAlg alg;
|
||||
alg.hidden = hidden;
|
||||
@ -98,7 +100,7 @@ std::shared_ptr<NameIO> NameIO::New(const string &name,
|
||||
const std::shared_ptr<Cipher> &cipher,
|
||||
const CipherKey &key) {
|
||||
std::shared_ptr<NameIO> result;
|
||||
if (gNameIOMap) {
|
||||
if (gNameIOMap != nullptr) {
|
||||
NameIOMap_t::const_iterator it = gNameIOMap->find(name);
|
||||
if (it != gNameIOMap->end()) {
|
||||
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 CipherKey &key) {
|
||||
std::shared_ptr<NameIO> result;
|
||||
if (gNameIOMap) {
|
||||
if (gNameIOMap != nullptr) {
|
||||
NameIOMap_t::const_iterator it;
|
||||
NameIOMap_t::const_iterator end = gNameIOMap->end();
|
||||
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() {}
|
||||
NameIO::~NameIO() = default;
|
||||
|
||||
void NameIO::setChainedNameIV(bool enable) { chainedNameIV = enable; }
|
||||
|
||||
@ -143,15 +145,16 @@ std::string NameIO::recodePath(
|
||||
uint64_t *iv) const {
|
||||
string output;
|
||||
|
||||
while (*path) {
|
||||
while (*path != 0) {
|
||||
if (*path == '/') {
|
||||
if (!output.empty()) // don't start the string with '/'
|
||||
if (!output.empty()) { // don't start the string with '/'
|
||||
output += '/';
|
||||
}
|
||||
++path;
|
||||
} else {
|
||||
bool isDotFile = (*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
|
||||
if (isDotFile && (path[len - 1] == '.') && (len <= 2)) {
|
||||
@ -162,7 +165,9 @@ std::string NameIO::recodePath(
|
||||
|
||||
// figure out buffer sizes
|
||||
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;
|
||||
|
||||
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 {
|
||||
// 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,
|
||||
&NameIO::encodeName, iv);
|
||||
}
|
||||
|
||||
std::string NameIO::_decodePath(const char *cipherPath, uint64_t *iv) const {
|
||||
// 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,
|
||||
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 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 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 {
|
||||
@ -232,7 +241,7 @@ std::string NameIO::_encodeName(const char *plaintextName, int length) const {
|
||||
BUFFER_INIT_S(codeBuf, 32, (unsigned int)approxLen + 1, bufSize)
|
||||
|
||||
// code the name
|
||||
int codedLen = encodeName(plaintextName, length, 0, codeBuf, bufSize);
|
||||
int codedLen = encodeName(plaintextName, length, nullptr, codeBuf, bufSize);
|
||||
rAssert(codedLen <= approxLen);
|
||||
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)
|
||||
|
||||
// code the name
|
||||
int codedLen = decodeName(encodedName, length, 0, codeBuf, bufSize);
|
||||
int codedLen = decodeName(encodedName, length, nullptr, codeBuf, bufSize);
|
||||
rAssert(codedLen <= approxLen);
|
||||
rAssert(codeBuf[codedLen] == '\0');
|
||||
|
||||
|
@ -37,7 +37,7 @@ class Cipher;
|
||||
|
||||
class NameIO {
|
||||
public:
|
||||
typedef std::shared_ptr<NameIO> (*Constructor)(
|
||||
using Constructor = std::shared_ptr<NameIO> (*)(
|
||||
const Interface &iface, const std::shared_ptr<Cipher> &cipher,
|
||||
const CipherKey &key);
|
||||
|
||||
@ -47,7 +47,7 @@ class NameIO {
|
||||
Interface iface;
|
||||
};
|
||||
|
||||
typedef std::list<Algorithm> AlgorithmList;
|
||||
using AlgorithmList = std::list<Algorithm>;
|
||||
static AlgorithmList GetAlgorithmList(bool includeHidden = false);
|
||||
|
||||
static std::shared_ptr<NameIO> New(const Interface &iface,
|
||||
@ -139,7 +139,7 @@ class NameIO {
|
||||
delete[] Name; \
|
||||
Name = Name##_Raw; \
|
||||
} \
|
||||
} while (0);
|
||||
} while (false);
|
||||
|
||||
} // namespace encfs
|
||||
|
||||
|
@ -49,24 +49,24 @@ static bool NullCipher_registered = Cipher::Register(
|
||||
|
||||
class NullKey : public AbstractCipherKey {
|
||||
public:
|
||||
NullKey() {}
|
||||
virtual ~NullKey() {}
|
||||
NullKey() = default;
|
||||
~NullKey() override = default;
|
||||
};
|
||||
|
||||
class NullDestructor {
|
||||
public:
|
||||
NullDestructor() {}
|
||||
NullDestructor(const NullDestructor &) {}
|
||||
~NullDestructor() {}
|
||||
NullDestructor() = default;
|
||||
NullDestructor(const NullDestructor &) = default;
|
||||
~NullDestructor() = default;
|
||||
|
||||
NullDestructor &operator=(const NullDestructor &) { return *this; }
|
||||
NullDestructor &operator=(const NullDestructor &) = default;
|
||||
void operator()(NullKey *&) {}
|
||||
};
|
||||
std::shared_ptr<AbstractCipherKey> gNullKey(new NullKey(), NullDestructor());
|
||||
|
||||
NullCipher::NullCipher(const Interface &iface_) { this->iface = iface_; }
|
||||
|
||||
NullCipher::~NullCipher() {}
|
||||
NullCipher::~NullCipher() = default;
|
||||
|
||||
Interface NullCipher::interface() const { return iface; }
|
||||
|
||||
|
@ -41,9 +41,9 @@ static Interface NNIOIface("nameio/null", 1, 0, 0);
|
||||
static bool NullNameIO_registered =
|
||||
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; }
|
||||
|
||||
|
@ -21,13 +21,14 @@
|
||||
#ifdef linux
|
||||
#define _XOPEN_SOURCE 500 // pick up pread , pwrite
|
||||
#endif
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <cerrno>
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <utility>
|
||||
|
||||
#include "Error.h"
|
||||
#include "FileIO.h"
|
||||
@ -53,8 +54,8 @@ inline void swap(int &x, int &y) {
|
||||
RawFileIO::RawFileIO()
|
||||
: knownSize(false), fileSize(0), fd(-1), oldfd(-1), canWrite(false) {}
|
||||
|
||||
RawFileIO::RawFileIO(const std::string &fileName)
|
||||
: name(fileName),
|
||||
RawFileIO::RawFileIO(std::string fileName)
|
||||
: name(std::move(fileName)),
|
||||
knownSize(false),
|
||||
fileSize(0),
|
||||
fd(-1),
|
||||
@ -68,9 +69,13 @@ RawFileIO::~RawFileIO() {
|
||||
swap(_fd, fd);
|
||||
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; }
|
||||
@ -110,7 +115,7 @@ static int open_readonly_workaround(const char *path, int flags) {
|
||||
it..
|
||||
*/
|
||||
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;
|
||||
|
||||
int result = 0;
|
||||
@ -123,7 +128,9 @@ int RawFileIO::open(int flags) {
|
||||
int finalFlags = requestWrite ? O_RDWR : O_RDONLY;
|
||||
|
||||
#if defined(O_LARGEFILE)
|
||||
if (flags & O_LARGEFILE) finalFlags |= O_LARGEFILE;
|
||||
if ((flags & O_LARGEFILE) != 0) {
|
||||
finalFlags |= O_LARGEFILE;
|
||||
}
|
||||
#else
|
||||
#warning O_LARGEFILE not supported
|
||||
#endif
|
||||
@ -183,14 +190,12 @@ off_t RawFileIO::getSize() const {
|
||||
const_cast<RawFileIO *>(this)->fileSize = stbuf.st_size;
|
||||
const_cast<RawFileIO *>(this)->knownSize = true;
|
||||
return fileSize;
|
||||
} else {
|
||||
int eno = errno;
|
||||
RLOG(ERROR) << "getSize on " << name << " failed: " << strerror(eno);
|
||||
return -eno;
|
||||
}
|
||||
} else {
|
||||
return fileSize;
|
||||
int eno = errno;
|
||||
RLOG(ERROR) << "getSize on " << name << " failed: " << strerror(eno);
|
||||
return -eno;
|
||||
}
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
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) {
|
||||
rAssert(fd >= 0);
|
||||
rAssert(true == canWrite);
|
||||
rAssert(canWrite);
|
||||
|
||||
int retrys = 10;
|
||||
void *buf = req.data;
|
||||
@ -217,7 +222,7 @@ int RawFileIO::write(const IORequest &req) {
|
||||
off_t offset = req.offset;
|
||||
|
||||
int eno = 0;
|
||||
while (bytes && retrys > 0) {
|
||||
while ((bytes != 0) && retrys > 0) {
|
||||
errno = 0;
|
||||
ssize_t writeSize = ::pwrite(fd, buf, bytes, offset);
|
||||
eno = errno;
|
||||
@ -243,11 +248,15 @@ int RawFileIO::write(const IORequest &req) {
|
||||
} else {
|
||||
if (knownSize) {
|
||||
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 true;
|
||||
}
|
||||
|
||||
int RawFileIO::truncate(off_t size) {
|
||||
@ -255,8 +264,9 @@ int RawFileIO::truncate(off_t size) {
|
||||
|
||||
if (fd >= 0 && canWrite) {
|
||||
res = ::ftruncate(fd, size);
|
||||
} else
|
||||
} else {
|
||||
res = ::truncate(name.c_str(), size);
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
int eno = errno;
|
||||
@ -271,10 +281,10 @@ int RawFileIO::truncate(off_t size) {
|
||||
}
|
||||
|
||||
if (fd >= 0 && canWrite) {
|
||||
#ifdef FDATASYNC
|
||||
#if defined(HAVE_FDATASYNC)
|
||||
::fdatasync(fd);
|
||||
#else
|
||||
::fsync(fd);
|
||||
::fsync(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ namespace encfs {
|
||||
class RawFileIO : public FileIO {
|
||||
public:
|
||||
RawFileIO();
|
||||
RawFileIO(const std::string &fileName);
|
||||
RawFileIO(std::string fileName);
|
||||
virtual ~RawFileIO();
|
||||
|
||||
virtual Interface interface() const;
|
||||
|
@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <cstring>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
@ -36,8 +36,8 @@
|
||||
#include "Interface.h"
|
||||
#include "Mutex.h"
|
||||
#include "Range.h"
|
||||
#include "SSL_Compat.h"
|
||||
#include "SSL_Cipher.h"
|
||||
#include "SSL_Compat.h"
|
||||
#include "intl/gettext.h"
|
||||
|
||||
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,
|
||||
const unsigned char *data, int dataLen, unsigned int rounds,
|
||||
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..
|
||||
}
|
||||
|
||||
unsigned char mdBuf[EVP_MAX_MD_SIZE];
|
||||
unsigned int mds = 0;
|
||||
int addmd = 0;
|
||||
int nkey = key ? keyLen : 0;
|
||||
int niv = iv ? ivLen : 0;
|
||||
int nkey = key != nullptr ? keyLen : 0;
|
||||
int niv = iv != nullptr ? ivLen : 0;
|
||||
|
||||
EVP_MD_CTX *cx = EVP_MD_CTX_new();
|
||||
EVP_MD_CTX_init(cx);
|
||||
|
||||
for (;;) {
|
||||
EVP_DigestInit_ex(cx, md, NULL);
|
||||
if (addmd++) EVP_DigestUpdate(cx, mdBuf, mds);
|
||||
EVP_DigestInit_ex(cx, md, nullptr);
|
||||
if ((addmd++) != 0) {
|
||||
EVP_DigestUpdate(cx, mdBuf, mds);
|
||||
}
|
||||
EVP_DigestUpdate(cx, data, dataLen);
|
||||
EVP_DigestFinal_ex(cx, mdBuf, &mds);
|
||||
|
||||
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_DigestFinal_ex(cx, mdBuf, &mds);
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
int toCopy = MIN(nkey, mds - offset);
|
||||
if (toCopy) {
|
||||
if (toCopy != 0) {
|
||||
memcpy(key, mdBuf + offset, toCopy);
|
||||
key += toCopy;
|
||||
nkey -= toCopy;
|
||||
offset += toCopy;
|
||||
}
|
||||
toCopy = MIN(niv, mds - offset);
|
||||
if (toCopy) {
|
||||
if (toCopy != 0) {
|
||||
memcpy(iv, mdBuf + offset, toCopy);
|
||||
iv += toCopy;
|
||||
niv -= toCopy;
|
||||
offset += toCopy;
|
||||
}
|
||||
if ((nkey == 0) && (niv == 0)) break;
|
||||
if ((nkey == 0) && (niv == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
EVP_MD_CTX_free(cx);
|
||||
OPENSSL_cleanse(mdBuf, sizeof(mdBuf));
|
||||
@ -125,13 +130,15 @@ int TimedPBKDF2(const char *pass, int passlen, const unsigned char *salt,
|
||||
timeval start, end;
|
||||
|
||||
for (;;) {
|
||||
gettimeofday(&start, 0);
|
||||
gettimeofday(&start, nullptr);
|
||||
int res =
|
||||
PKCS5_PBKDF2_HMAC_SHA1(pass, passlen, const_cast<unsigned char *>(salt),
|
||||
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);
|
||||
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)) {
|
||||
// estimate number of iterations to get close to desired time
|
||||
iter = (int)((double)iter * (double)desiredPDFTime / (double)delta);
|
||||
} else
|
||||
} else {
|
||||
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
|
||||
static Interface BlowfishInterface("ssl/blowfish", 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
|
||||
|
||||
@ -160,7 +209,9 @@ static Range BFKeyRange(128, 256, 32);
|
||||
static Range BFBlockRange(64, 4096, 8);
|
||||
|
||||
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);
|
||||
|
||||
@ -185,12 +236,14 @@ static Range AESBlockRange(64, 4096, 16);
|
||||
|
||||
static std::shared_ptr<Cipher> NewAESCipher(const Interface &iface,
|
||||
int keyLen) {
|
||||
if (keyLen <= 0) keyLen = 192;
|
||||
if (keyLen <= 0) {
|
||||
keyLen = 192;
|
||||
}
|
||||
|
||||
keyLen = AESKeyRange.closest(keyLen);
|
||||
|
||||
const EVP_CIPHER *blockCipher = 0;
|
||||
const EVP_CIPHER *streamCipher = 0;
|
||||
const EVP_CIPHER *blockCipher = nullptr;
|
||||
const EVP_CIPHER *streamCipher = nullptr;
|
||||
|
||||
switch (keyLen) {
|
||||
case 128:
|
||||
@ -238,13 +291,13 @@ class SSLKey : public AbstractCipherKey {
|
||||
HMAC_CTX *mac_ctx;
|
||||
|
||||
SSLKey(int keySize, int ivLength);
|
||||
~SSLKey();
|
||||
~SSLKey() override;
|
||||
};
|
||||
|
||||
SSLKey::SSLKey(int keySize_, int ivLength_) {
|
||||
this->keySize = keySize_;
|
||||
this->ivLength = ivLength_;
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
pthread_mutex_init(&mutex, nullptr);
|
||||
buffer = (unsigned char *)OPENSSL_malloc(keySize + ivLength);
|
||||
memset(buffer, 0, keySize + ivLength);
|
||||
|
||||
@ -272,7 +325,7 @@ SSLKey::~SSLKey() {
|
||||
|
||||
keySize = 0;
|
||||
ivLength = 0;
|
||||
buffer = 0;
|
||||
buffer = nullptr;
|
||||
|
||||
EVP_CIPHER_CTX_free(block_enc);
|
||||
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);
|
||||
// initialize the cipher context once so that we don't have to do it for
|
||||
// every block..
|
||||
EVP_EncryptInit_ex(key->block_enc, _blockCipher, NULL, NULL, NULL);
|
||||
EVP_DecryptInit_ex(key->block_dec, _blockCipher, NULL, NULL, NULL);
|
||||
EVP_EncryptInit_ex(key->stream_enc, _streamCipher, NULL, NULL, NULL);
|
||||
EVP_DecryptInit_ex(key->stream_dec, _streamCipher, NULL, NULL, NULL);
|
||||
EVP_EncryptInit_ex(key->block_enc, _blockCipher, nullptr, nullptr, nullptr);
|
||||
EVP_DecryptInit_ex(key->block_dec, _blockCipher, nullptr, nullptr, nullptr);
|
||||
EVP_EncryptInit_ex(key->stream_enc, _streamCipher, nullptr, nullptr, nullptr);
|
||||
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_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_dec, 0);
|
||||
|
||||
EVP_EncryptInit_ex(key->block_enc, NULL, NULL, KeyData(key), NULL);
|
||||
EVP_DecryptInit_ex(key->block_dec, NULL, NULL, KeyData(key), NULL);
|
||||
EVP_EncryptInit_ex(key->stream_enc, NULL, NULL, KeyData(key), NULL);
|
||||
EVP_DecryptInit_ex(key->stream_dec, NULL, NULL, KeyData(key), NULL);
|
||||
EVP_EncryptInit_ex(key->block_enc, nullptr, nullptr, KeyData(key), nullptr);
|
||||
EVP_DecryptInit_ex(key->block_dec, nullptr, nullptr, KeyData(key), nullptr);
|
||||
EVP_EncryptInit_ex(key->stream_enc, nullptr, nullptr, KeyData(key), nullptr);
|
||||
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_,
|
||||
@ -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; }
|
||||
|
||||
@ -366,8 +419,9 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength,
|
||||
if (res <= 0) {
|
||||
RLOG(WARNING) << "openssl error, PBKDF2 failed";
|
||||
return CipherKey();
|
||||
} else
|
||||
iterationCount = res;
|
||||
}
|
||||
iterationCount = res;
|
||||
|
||||
} else {
|
||||
// known iteration length
|
||||
if (PKCS5_PBKDF2_HMAC_SHA1(
|
||||
@ -401,9 +455,8 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) {
|
||||
}
|
||||
} else {
|
||||
// for backward compatibility with filesystems created with 1:0
|
||||
bytes = EVP_BytesToKey(_blockCipher, EVP_sha1(), NULL,
|
||||
(unsigned char *)password, passwdLength, 16,
|
||||
KeyData(key), IVData(key));
|
||||
EVP_BytesToKey(_blockCipher, EVP_sha1(), nullptr, (unsigned char *)password,
|
||||
passwdLength, 16, KeyData(key), IVData(key));
|
||||
}
|
||||
|
||||
initKey(key, _blockCipher, _streamCipher, _keySize);
|
||||
@ -425,8 +478,9 @@ CipherKey SSL_Cipher::newRandomKey() {
|
||||
int saltLen = 20;
|
||||
unsigned char saltBuf[saltLen];
|
||||
|
||||
if (!randomize(tmpBuf, bufLen, true) || !randomize(saltBuf, saltLen, true))
|
||||
if (!randomize(tmpBuf, bufLen, true) || !randomize(saltBuf, saltLen, true)) {
|
||||
return CipherKey();
|
||||
}
|
||||
|
||||
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 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);
|
||||
if (chainedIV) {
|
||||
if (chainedIV != nullptr) {
|
||||
// toss in the chained IV as well
|
||||
uint64_t tmp = *chainedIV;
|
||||
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..
|
||||
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]);
|
||||
}
|
||||
|
||||
uint64_t value = (uint64_t)h[0];
|
||||
for (int i = 1; i < 8; ++i) value = (value << 8) | (uint64_t)h[i];
|
||||
auto value = (uint64_t)h[0];
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
value = (value << 8) | (uint64_t)h[i];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
@ -505,9 +562,8 @@ bool SSL_Cipher::randomize(unsigned char *buf, int len,
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
uint64_t tmp = _checksum_64(mk.get(), data, len, chainedIV);
|
||||
|
||||
if (chainedIV) *chainedIV = tmp;
|
||||
if (chainedIV != nullptr) {
|
||||
*chainedIV = tmp;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
@ -529,8 +587,9 @@ CipherKey SSL_Cipher::readKey(const unsigned char *data,
|
||||
|
||||
// First N bytes are checksum bytes.
|
||||
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];
|
||||
}
|
||||
|
||||
memcpy(tmpBuf, data + KEY_CHECKSUM_BYTES, _keySize + _ivLength);
|
||||
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(key2->keySize == _keySize);
|
||||
|
||||
if (memcmp(key1->buffer, key2->buffer, _keySize + _ivLength) != 0)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
return memcmp(key1->buffer, key2->buffer, _keySize + _ivLength) == 0;
|
||||
}
|
||||
|
||||
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
|
||||
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, md, 8);
|
||||
HMAC_Final(key->mac_ctx, md, &mdLen);
|
||||
@ -694,10 +750,12 @@ static void flipBytes(unsigned char *buf, int size) {
|
||||
unsigned char revBuf[64];
|
||||
|
||||
int bytesLeft = size;
|
||||
while (bytesLeft) {
|
||||
while (bytesLeft != 0) {
|
||||
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);
|
||||
bytesLeft -= toFlip;
|
||||
@ -707,11 +765,15 @@ static void flipBytes(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) {
|
||||
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
|
||||
@ -732,7 +794,7 @@ bool SSL_Cipher::streamEncode(unsigned char *buf, int size, uint64_t iv64,
|
||||
shuffleBytes(buf, size);
|
||||
|
||||
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_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);
|
||||
|
||||
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_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;
|
||||
|
||||
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_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);
|
||||
|
||||
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_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;
|
||||
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_EncryptFinal_ex(key->block_enc, buf + 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;
|
||||
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_DecryptFinal_ex(key->block_dec, buf + dstLen, &tmpLen);
|
||||
dstLen += tmpLen;
|
||||
|
@ -31,7 +31,7 @@
|
||||
#ifndef EVP_CIPHER
|
||||
struct evp_cipher_st;
|
||||
|
||||
typedef struct evp_cipher_st EVP_CIPHER;
|
||||
using EVP_CIPHER = struct evp_cipher_st;
|
||||
#endif
|
||||
|
||||
namespace encfs {
|
||||
|
@ -30,8 +30,7 @@
|
||||
#define HMAC_CTX_reset HMAC_CTX_cleanup
|
||||
|
||||
// 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));
|
||||
if (ctx != NULL) {
|
||||
memset(ctx, 0, sizeof(HMAC_CTX));
|
||||
@ -40,8 +39,7 @@ HMAC_CTX *HMAC_CTX_new(void)
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void HMAC_CTX_free(HMAC_CTX *ctx)
|
||||
{
|
||||
void HMAC_CTX_free(HMAC_CTX *ctx) {
|
||||
if (ctx != NULL) {
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
OPENSSL_free(ctx);
|
||||
|
@ -20,8 +20,9 @@
|
||||
|
||||
#include "StreamNameIO.h"
|
||||
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include "Cipher.h"
|
||||
#include "CipherKey.h"
|
||||
@ -72,11 +73,12 @@ Interface StreamNameIO::CurrentInterface() {
|
||||
}
|
||||
|
||||
StreamNameIO::StreamNameIO(const Interface &iface,
|
||||
const std::shared_ptr<Cipher> &cipher,
|
||||
const CipherKey &key)
|
||||
: _interface(iface.current()), _cipher(cipher), _key(key) {}
|
||||
std::shared_ptr<Cipher> cipher, CipherKey key)
|
||||
: _interface(iface.current()),
|
||||
_cipher(std::move(cipher)),
|
||||
_key(std::move(key)) {}
|
||||
|
||||
StreamNameIO::~StreamNameIO() {}
|
||||
StreamNameIO::~StreamNameIO() = default;
|
||||
|
||||
Interface StreamNameIO::interface() const { return CurrentInterface(); }
|
||||
|
||||
@ -94,7 +96,9 @@ int StreamNameIO::encodeName(const char *plaintextName, int length,
|
||||
uint64_t *iv, char *encodedName,
|
||||
int bufferLength) const {
|
||||
uint64_t tmpIV = 0;
|
||||
if (iv && _interface >= 2) tmpIV = *iv;
|
||||
if ((iv != nullptr) && _interface >= 2) {
|
||||
tmpIV = *iv;
|
||||
}
|
||||
|
||||
unsigned int mac =
|
||||
_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;
|
||||
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);
|
||||
|
||||
@ -153,7 +159,9 @@ int StreamNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
|
||||
((unsigned int)((unsigned char)tmpBuf[1]));
|
||||
|
||||
// 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);
|
||||
} else {
|
||||
|
@ -36,8 +36,8 @@ class StreamNameIO : public NameIO {
|
||||
public:
|
||||
static Interface CurrentInterface();
|
||||
|
||||
StreamNameIO(const Interface &iface, const std::shared_ptr<Cipher> &cipher,
|
||||
const CipherKey &key);
|
||||
StreamNameIO(const Interface &iface, std::shared_ptr<Cipher> cipher,
|
||||
CipherKey key);
|
||||
virtual ~StreamNameIO();
|
||||
|
||||
virtual Interface interface() const;
|
||||
|
@ -22,7 +22,9 @@
|
||||
|
||||
#include <algorithm> // for remove_if
|
||||
#include <cstring> // for NULL
|
||||
#include <fstream> // for ifstream
|
||||
#include <memory> // for shared_ptr
|
||||
#include <sstream> // for ostringstream
|
||||
|
||||
#include <tinyxml2.h> // for XMLElement, XMLNode, XMLDocument (ptr only)
|
||||
|
||||
@ -32,7 +34,7 @@
|
||||
|
||||
namespace encfs {
|
||||
|
||||
XmlValue::~XmlValue() {}
|
||||
XmlValue::~XmlValue() = default;
|
||||
|
||||
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 {
|
||||
XmlValuePtr value = find(path);
|
||||
if (!value) return false;
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = value->text();
|
||||
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 {
|
||||
XmlValuePtr value = find(path);
|
||||
if (!value) return false;
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = atoi(value->text().c_str());
|
||||
return true;
|
||||
@ -60,7 +66,9 @@ bool XmlValue::read(const char *path, int *out) const {
|
||||
|
||||
bool XmlValue::read(const char *path, long *out) const {
|
||||
XmlValuePtr value = find(path);
|
||||
if (!value) return false;
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = atol(value->text().c_str());
|
||||
return true;
|
||||
@ -68,7 +76,9 @@ bool XmlValue::read(const char *path, long *out) const {
|
||||
|
||||
bool XmlValue::read(const char *path, double *out) const {
|
||||
XmlValuePtr value = find(path);
|
||||
if (!value) return false;
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = atof(value->text().c_str());
|
||||
return true;
|
||||
@ -76,16 +86,20 @@ bool XmlValue::read(const char *path, double *out) const {
|
||||
|
||||
bool XmlValue::read(const char *path, bool *out) const {
|
||||
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;
|
||||
}
|
||||
|
||||
bool XmlValue::readB64(const char *path, unsigned char *data,
|
||||
int length) const {
|
||||
XmlValuePtr value = find(path);
|
||||
if (!value) return false;
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string s = value->text();
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -108,7 +122,9 @@ bool XmlValue::readB64(const char *path, unsigned char *data,
|
||||
|
||||
bool XmlValue::read(const char *path, Interface *out) const {
|
||||
XmlValuePtr node = find(path);
|
||||
if (!node) return false;
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = node->read("name", &out->name()) &&
|
||||
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 value;
|
||||
if (element == NULL) return value;
|
||||
if (element == nullptr) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const tinyxml2::XMLNode *child = element->FirstChild();
|
||||
if (child) {
|
||||
if (child != nullptr) {
|
||||
const tinyxml2::XMLText *childText = child->ToText();
|
||||
if (childText) value = childText->Value();
|
||||
if (childText != nullptr) {
|
||||
value = childText->Value();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
@ -137,22 +157,21 @@ class XmlNode : virtual public XmlValue {
|
||||
XmlNode(const tinyxml2::XMLElement *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] == '@') {
|
||||
const char *value = element->Attribute(name + 1);
|
||||
if (value)
|
||||
return XmlValuePtr(new XmlValue(value));
|
||||
else
|
||||
return XmlValuePtr();
|
||||
} else {
|
||||
const tinyxml2::XMLElement *el = element->FirstChildElement(name);
|
||||
if (el)
|
||||
return XmlValuePtr(new XmlNode(el));
|
||||
else
|
||||
return XmlValuePtr();
|
||||
if (value != nullptr) {
|
||||
return std::make_shared<encfs::XmlValue>(value);
|
||||
}
|
||||
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() {}
|
||||
XmlReader::~XmlReader() = default;
|
||||
|
||||
bool XmlReader::load(const char *fileName) {
|
||||
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;
|
||||
}
|
||||
|
||||
XmlValuePtr XmlReader::operator[](const char *name) const {
|
||||
tinyxml2::XMLNode *node = pd->doc->FirstChildElement(name);
|
||||
if (node == NULL) {
|
||||
if (node == nullptr) {
|
||||
RLOG(ERROR) << "Xml node " << name << " not found";
|
||||
return XmlValuePtr(new XmlValue());
|
||||
return std::make_shared<encfs::XmlValue>();
|
||||
}
|
||||
|
||||
tinyxml2::XMLElement *element = node->ToElement();
|
||||
if (element == NULL) {
|
||||
if (element == nullptr) {
|
||||
RLOG(ERROR) << "Xml node " << name << " not element";
|
||||
return XmlValuePtr(new XmlValue());
|
||||
return std::make_shared<encfs::XmlValue>();
|
||||
}
|
||||
|
||||
return XmlValuePtr(new XmlNode(element));
|
||||
|
@ -29,7 +29,7 @@
|
||||
namespace encfs {
|
||||
|
||||
class XmlValue;
|
||||
typedef std::shared_ptr<XmlValue> XmlValuePtr;
|
||||
using XmlValuePtr = std::shared_ptr<XmlValue>;
|
||||
|
||||
class XmlValue {
|
||||
std::string value;
|
||||
|
@ -27,10 +27,10 @@
|
||||
/* Specification. */
|
||||
#include "autosprintf.h"
|
||||
|
||||
#include <stdarg.h> // for va_list
|
||||
#include <stdio.h> // for NULL, vasprintf
|
||||
#include <stdlib.h> // for free
|
||||
#include <string.h> // for strdup
|
||||
#include <cstdarg> // for va_list
|
||||
#include <cstdio> // for NULL, vasprintf
|
||||
#include <cstdlib> // for free
|
||||
#include <cstring> // for strdup
|
||||
|
||||
namespace gnu {
|
||||
|
||||
@ -38,13 +38,15 @@ namespace gnu {
|
||||
autosprintf::autosprintf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
if (vasprintf(&str, format, args) < 0) str = NULL;
|
||||
if (vasprintf(&str, format, args) < 0) {
|
||||
str = nullptr;
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Copy constructor. Necessary because the destructor is nontrivial. */
|
||||
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. */
|
||||
@ -52,15 +54,15 @@ autosprintf::~autosprintf() { free(str); }
|
||||
|
||||
/* Conversion to string. */
|
||||
autosprintf::operator char *() const {
|
||||
if (str != NULL) {
|
||||
if (str != nullptr) {
|
||||
size_t length = strlen(str) + 1;
|
||||
char *copy = new char[length];
|
||||
auto *copy = new char[length];
|
||||
memcpy(copy, str, length);
|
||||
return copy;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
autosprintf::operator std::string() const {
|
||||
return std::string(str ? str : "(error in autosprintf)");
|
||||
}
|
||||
return std::string(str != nullptr ? str : "(error in autosprintf)");
|
||||
}
|
||||
} // namespace gnu
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
#include <ctype.h> // for toupper
|
||||
#include <cctype> // for toupper
|
||||
|
||||
#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..
|
||||
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 char *outLoc) {
|
||||
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.
|
||||
// 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;
|
||||
workBits += src2Pow;
|
||||
--srcLen;
|
||||
@ -82,7 +86,7 @@ static void changeBase2Inline(unsigned char *src, int srcLen, int src2Pow,
|
||||
work >>= dst2Pow;
|
||||
workBits -= dst2Pow;
|
||||
|
||||
if (srcLen) {
|
||||
if (srcLen != 0) {
|
||||
// more input left, so recurse
|
||||
changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte,
|
||||
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,
|
||||
bool outputPartialLastByte) {
|
||||
changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte, 0, 0,
|
||||
0);
|
||||
nullptr);
|
||||
}
|
||||
|
||||
// character set for ascii b64:
|
||||
@ -119,12 +123,14 @@ void B64ToAscii(unsigned char *in, int length) {
|
||||
for (int offset = 0; offset < length; ++offset) {
|
||||
int ch = in[offset];
|
||||
if (ch > 11) {
|
||||
if (ch > 37)
|
||||
if (ch > 37) {
|
||||
ch += 'a' - 38;
|
||||
else
|
||||
} else {
|
||||
ch += 'A' - 12;
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
ch = B642AsciiTable[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) {
|
||||
while (length--) {
|
||||
while ((length--) != 0) {
|
||||
unsigned char ch = *in++;
|
||||
if (ch >= 'A') {
|
||||
if (ch >= 'a')
|
||||
if (ch >= 'a') {
|
||||
ch += 38 - 'a';
|
||||
else
|
||||
} else {
|
||||
ch += 12 - 'A';
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
ch = Ascii2B64Table[ch] - '0';
|
||||
|
||||
}
|
||||
*out++ = ch;
|
||||
}
|
||||
}
|
||||
@ -156,10 +163,11 @@ void AsciiToB64(unsigned char *out, const unsigned char *in, int length) {
|
||||
void B32ToAscii(unsigned char *buf, int len) {
|
||||
for (int offset = 0; offset < len; ++offset) {
|
||||
int ch = buf[offset];
|
||||
if (ch >= 0 && ch < 26)
|
||||
if (ch >= 0 && ch < 26) {
|
||||
ch += 'A';
|
||||
else
|
||||
} else {
|
||||
ch += '2' - 26;
|
||||
}
|
||||
|
||||
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) {
|
||||
while (length--) {
|
||||
while ((length--) != 0) {
|
||||
unsigned char ch = *in++;
|
||||
int lch = toupper(ch);
|
||||
if (lch >= 'A')
|
||||
if (lch >= 'A') {
|
||||
lch -= 'A';
|
||||
else
|
||||
} else {
|
||||
lch += 26 - '2';
|
||||
|
||||
}
|
||||
*out++ = (unsigned char)lch;
|
||||
}
|
||||
}
|
||||
@ -221,7 +229,7 @@ bool B64StandardDecode(unsigned char *out, const unsigned char *in, int inLen) {
|
||||
buf = buf << 6 | c;
|
||||
|
||||
/* If the buffer is full, split it into bytes */
|
||||
if (buf & 0x1000000) {
|
||||
if ((buf & 0x1000000) != 0u) {
|
||||
*out++ = buf >> 16;
|
||||
*out++ = buf >> 8;
|
||||
*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 >> 2;
|
||||
} else if (buf & 0x1000) {
|
||||
} else if ((buf & 0x1000) != 0u) {
|
||||
*out++ = buf >> 4;
|
||||
}
|
||||
|
||||
@ -248,7 +256,7 @@ std::string B64StandardEncode(std::vector<unsigned char> inputBuffer) {
|
||||
std::string encodedString;
|
||||
encodedString.reserve(B256ToB64Bytes(inputBuffer.size()));
|
||||
long temp;
|
||||
std::vector<unsigned char>::iterator cursor = inputBuffer.begin();
|
||||
auto cursor = inputBuffer.begin();
|
||||
for (size_t idx = 0; idx < inputBuffer.size() / 3; idx++) {
|
||||
temp = (*cursor++) << 16; // Convert to big endian
|
||||
temp += (*cursor++) << 8;
|
||||
|
243
encfs/encfs.cpp
243
encfs/encfs.cpp
@ -18,17 +18,17 @@
|
||||
#include "encfs.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#ifdef linux
|
||||
@ -41,7 +41,7 @@
|
||||
#include <attr/xattr.h>
|
||||
#endif
|
||||
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -76,7 +76,9 @@ static EncFS_Context *context() {
|
||||
* if the argument is NULL.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@ -89,7 +91,9 @@ static int withCipherPath(const char *opName, const char *path,
|
||||
|
||||
int res = -EIO;
|
||||
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
|
||||
if (!FSRoot) return res;
|
||||
if (!FSRoot) {
|
||||
return res;
|
||||
}
|
||||
|
||||
try {
|
||||
string cyName = FSRoot->cipherPath(path);
|
||||
@ -111,6 +115,27 @@ static int withCipherPath(const char *opName, const char *path,
|
||||
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
|
||||
static int withFileNode(const char *opName, const char *path,
|
||||
struct fuse_file_info *fi,
|
||||
@ -119,12 +144,15 @@ static int withFileNode(const char *opName, const char *path,
|
||||
|
||||
int res = -EIO;
|
||||
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
|
||||
if (!FSRoot) return res;
|
||||
if (!FSRoot) {
|
||||
return res;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
auto do_op = [&FSRoot, opName, &op](FileNode *fnode) {
|
||||
auto do_op = [&FSRoot, opName, &op](std::shared_ptr<FileNode> fnode) {
|
||||
rAssert(fnode != nullptr);
|
||||
checkCanary(fnode);
|
||||
VLOG(1) << "op: " << opName << " : " << fnode->cipherName();
|
||||
|
||||
// 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() << "'";
|
||||
return -EIO;
|
||||
}
|
||||
return op(fnode);
|
||||
return op(fnode.get());
|
||||
};
|
||||
|
||||
if (fi != nullptr && fi->fh != 0)
|
||||
res = do_op(reinterpret_cast<FileNode *>(fi->fh));
|
||||
else
|
||||
res = do_op(FSRoot->lookupNode(path, opName).get());
|
||||
if (fi != nullptr && fi->fh != 0) {
|
||||
auto node = ctx->lookupFuseFh(fi->fh);
|
||||
if (node == nullptr) {
|
||||
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) {
|
||||
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) {
|
||||
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,
|
||||
@ -202,7 +236,9 @@ int encfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||
|
||||
int res = ESUCCESS;
|
||||
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
|
||||
if (!FSRoot) return res;
|
||||
if (!FSRoot) {
|
||||
return res;
|
||||
}
|
||||
|
||||
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 (filler(buf, name.c_str(), &st, 0, 0)) break;
|
||||
#else
|
||||
if (filler(buf, name.c_str(), &st, 0)) break;
|
||||
if (filler(buf, name.c_str(), &st, 0) != 0) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
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) {
|
||||
EncFS_Context *ctx = context();
|
||||
|
||||
if (isReadOnly(ctx)) return -EROFS;
|
||||
if (isReadOnly(ctx)) {
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
int res = -EIO;
|
||||
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
|
||||
if (!FSRoot) return res;
|
||||
if (!FSRoot) {
|
||||
return res;
|
||||
}
|
||||
|
||||
try {
|
||||
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");
|
||||
|
||||
struct stat st;
|
||||
if (dnode->getAttr(&st) == 0)
|
||||
if (dnode->getAttr(&st) == 0) {
|
||||
res = fnode->mknod(mode, rdev, uid, st.st_gid);
|
||||
}
|
||||
}
|
||||
} catch (encfs::Error &err) {
|
||||
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();
|
||||
EncFS_Context *ctx = context();
|
||||
|
||||
if (isReadOnly(ctx)) return -EROFS;
|
||||
if (isReadOnly(ctx)) {
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
int res = -EIO;
|
||||
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
|
||||
if (!FSRoot) return res;
|
||||
if (!FSRoot) {
|
||||
return res;
|
||||
}
|
||||
|
||||
try {
|
||||
uid_t uid = 0;
|
||||
@ -307,8 +354,9 @@ int encfs_mkdir(const char *path, mode_t mode) {
|
||||
FSRoot->lookupNode(parent.c_str(), "mkdir");
|
||||
|
||||
struct stat st;
|
||||
if (dnode->getAttr(&st) == 0)
|
||||
if (dnode->getAttr(&st) == 0) {
|
||||
res = FSRoot->mkdir(path, mode, uid, st.st_gid);
|
||||
}
|
||||
}
|
||||
} catch (encfs::Error &err) {
|
||||
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) {
|
||||
EncFS_Context *ctx = context();
|
||||
|
||||
if (isReadOnly(ctx)) return -EROFS;
|
||||
if (isReadOnly(ctx)) {
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
int res = -EIO;
|
||||
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
|
||||
if (!FSRoot) return res;
|
||||
if (!FSRoot) {
|
||||
return res;
|
||||
}
|
||||
|
||||
try {
|
||||
// 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) {
|
||||
if (isReadOnly(NULL)) return -EROFS;
|
||||
if (isReadOnly(nullptr)) {
|
||||
return -EROFS;
|
||||
}
|
||||
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) {
|
||||
int res = ESUCCESS;
|
||||
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
|
||||
if (!FSRoot) return res;
|
||||
if (!FSRoot) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = ::readlink(cyName.c_str(), buf, size - 1);
|
||||
|
||||
if (res == -1) return -errno;
|
||||
if (res == -1) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
buf[res] = '\0'; // ensure null termination
|
||||
string decodedName;
|
||||
@ -363,10 +421,9 @@ int _do_readlink(EncFS_Context *ctx, const string &cyName, char *buf,
|
||||
buf[size - 1] = '\0';
|
||||
|
||||
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) {
|
||||
@ -380,11 +437,15 @@ int encfs_readlink(const char *path, char *buf, size_t size) {
|
||||
int encfs_symlink(const char *to, const char *from) {
|
||||
EncFS_Context *ctx = context();
|
||||
|
||||
if (isReadOnly(ctx)) return -EROFS;
|
||||
if (isReadOnly(ctx)) {
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
int res = -EIO;
|
||||
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
|
||||
if (!FSRoot) return res;
|
||||
if (!FSRoot) {
|
||||
return res;
|
||||
}
|
||||
|
||||
try {
|
||||
string fromCName = FSRoot->cipherPath(from);
|
||||
@ -403,13 +464,18 @@ int encfs_symlink(const char *to, const char *from) {
|
||||
oldgid = setfsgid(context->gid);
|
||||
}
|
||||
res = ::symlink(toCName.c_str(), fromCName.c_str());
|
||||
if (olduid >= 0) setfsuid(olduid);
|
||||
if (oldgid >= 0) setfsgid(oldgid);
|
||||
if (olduid >= 0) {
|
||||
setfsuid(olduid);
|
||||
}
|
||||
if (oldgid >= 0) {
|
||||
setfsgid(oldgid);
|
||||
}
|
||||
|
||||
if (res == -1)
|
||||
if (res == -1) {
|
||||
res = -errno;
|
||||
else
|
||||
} else {
|
||||
res = ESUCCESS;
|
||||
}
|
||||
} catch (encfs::Error &err) {
|
||||
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) {
|
||||
EncFS_Context *ctx = context();
|
||||
|
||||
if (isReadOnly(ctx)) return -EROFS;
|
||||
if (isReadOnly(ctx)) {
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
int res = -EIO;
|
||||
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
|
||||
if (!FSRoot) return res;
|
||||
if (!FSRoot) {
|
||||
return res;
|
||||
}
|
||||
|
||||
try {
|
||||
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) {
|
||||
EncFS_Context *ctx = context();
|
||||
|
||||
if (isReadOnly(ctx)) return -EROFS;
|
||||
if (isReadOnly(ctx)) {
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
int res = -EIO;
|
||||
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
|
||||
if (!FSRoot) return res;
|
||||
if (!FSRoot) {
|
||||
return res;
|
||||
}
|
||||
|
||||
try {
|
||||
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) {
|
||||
if (isReadOnly(NULL)) return -EROFS;
|
||||
if (isReadOnly(nullptr)) {
|
||||
return -EROFS;
|
||||
}
|
||||
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) {
|
||||
if (isReadOnly(NULL)) return -EROFS;
|
||||
if (isReadOnly(nullptr)) {
|
||||
return -EROFS;
|
||||
}
|
||||
return withCipherPath("chown", path, bind(_do_chown, _1, _2, uid, gid));
|
||||
}
|
||||
|
||||
int _do_truncate(FileNode *fnode, off_t size) { return fnode->truncate(size); }
|
||||
|
||||
int encfs_truncate(const char *path, off_t size) {
|
||||
if (isReadOnly(NULL)) return -EROFS;
|
||||
return withFileNode("truncate", path, NULL, bind(_do_truncate, _1, size));
|
||||
if (isReadOnly(nullptr)) {
|
||||
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) {
|
||||
if (isReadOnly(NULL)) return -EROFS;
|
||||
if (isReadOnly(nullptr)) {
|
||||
return -EROFS;
|
||||
}
|
||||
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) {
|
||||
if (isReadOnly(NULL)) return -EROFS;
|
||||
if (isReadOnly(nullptr)) {
|
||||
return -EROFS;
|
||||
}
|
||||
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]) {
|
||||
if (isReadOnly(NULL)) return -EROFS;
|
||||
if (isReadOnly(nullptr)) {
|
||||
return -EROFS;
|
||||
}
|
||||
return withCipherPath("utimens", path, bind(_do_utimens, _1, _2, ts));
|
||||
}
|
||||
|
||||
int encfs_open(const char *path, struct fuse_file_info *file) {
|
||||
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;
|
||||
}
|
||||
|
||||
int res = -EIO;
|
||||
std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
|
||||
if (!FSRoot) return res;
|
||||
if (!FSRoot) {
|
||||
return res;
|
||||
}
|
||||
|
||||
try {
|
||||
std::shared_ptr<FileNode> fnode =
|
||||
@ -531,8 +621,8 @@ int encfs_open(const char *path, struct fuse_file_info *file) {
|
||||
<< file->flags;
|
||||
|
||||
if (res >= 0) {
|
||||
file->fh =
|
||||
reinterpret_cast<uintptr_t>(ctx->putNode(path, std::move(fnode)));
|
||||
ctx->putNode(path, fnode);
|
||||
file->fh = fnode->fuseFh;
|
||||
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 res = encfs_mknod(path, mode, 0);
|
||||
if (res) {
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -587,7 +677,8 @@ int encfs_release(const char *path, struct fuse_file_info *finfo) {
|
||||
EncFS_Context *ctx = context();
|
||||
|
||||
try {
|
||||
ctx->eraseNode(path, reinterpret_cast<FileNode *>(finfo->fh));
|
||||
auto fnode = ctx->lookupFuseFh(finfo->fh);
|
||||
ctx->eraseNode(path, fnode);
|
||||
return ESUCCESS;
|
||||
} catch (encfs::Error &err) {
|
||||
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) {
|
||||
if (isReadOnly(NULL)) return -EROFS;
|
||||
if (isReadOnly(nullptr)) {
|
||||
return -EROFS;
|
||||
}
|
||||
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 res = fnode->write(offset, ptr, size);
|
||||
if (res < 0)
|
||||
if (res < 0) {
|
||||
return res;
|
||||
else
|
||||
return size;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int encfs_write(const char *path, const char *buf, size_t size, off_t offset,
|
||||
struct fuse_file_info *file) {
|
||||
if (isReadOnly(NULL)) return -EROFS;
|
||||
if (isReadOnly(nullptr)) {
|
||||
return -EROFS;
|
||||
}
|
||||
return withFileNode("write", path, file,
|
||||
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;
|
||||
try {
|
||||
(void)path; // path should always be '/' for now..
|
||||
rAssert(st != NULL);
|
||||
rAssert(st != nullptr);
|
||||
string cyName = ctx->rootCipherDir;
|
||||
|
||||
VLOG(1) << "doing statfs of " << cyName;
|
||||
res = statvfs(cyName.c_str(), st);
|
||||
if (!res) {
|
||||
if (res == 0) {
|
||||
// adjust maximum name length..
|
||||
st->f_namemax = 6 * (st->f_namemax - 2) / 8; // approx..
|
||||
}
|
||||
if (res == -1) res = -errno;
|
||||
if (res == -1) {
|
||||
res = -errno;
|
||||
}
|
||||
} catch (encfs::Error &err) {
|
||||
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
|
||||
int _do_setxattr(EncFS_Context *, const string &cyName, const char *name,
|
||||
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);
|
||||
}
|
||||
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
|
||||
int _do_setxattr(EncFS_Context *, const string &cyName, const char *name,
|
||||
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,
|
||||
size_t size, int flags) {
|
||||
if (isReadOnly(NULL)) return -EROFS;
|
||||
if (isReadOnly(nullptr)) {
|
||||
return -EROFS;
|
||||
}
|
||||
return withCipherPath("setxattr", path,
|
||||
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
|
||||
int _do_getxattr(EncFS_Context *, const string &cyName, const char *name,
|
||||
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);
|
||||
}
|
||||
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
|
||||
int _do_getxattr(EncFS_Context *, const string &cyName, const char *name,
|
||||
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,
|
||||
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,
|
||||
size_t size) {
|
||||
#ifdef XATTR_ADD_OPT
|
||||
int options = 0;
|
||||
int options = XATTR_NOFOLLOW;
|
||||
int res = ::listxattr(cyName.c_str(), list, size, options);
|
||||
#else
|
||||
int res = ::listxattr(cyName.c_str(), list, size);
|
||||
int res = ::llistxattr(cyName.c_str(), list, size);
|
||||
#endif
|
||||
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) {
|
||||
#ifdef XATTR_ADD_OPT
|
||||
int options = 0;
|
||||
int options = XATTR_NOFOLLOW;
|
||||
int res = ::removexattr(cyName.c_str(), name, options);
|
||||
#else
|
||||
int res = ::removexattr(cyName.c_str(), name);
|
||||
int res = ::lremovexattr(cyName.c_str(), name);
|
||||
#endif
|
||||
return (res == -1) ? -errno : res;
|
||||
}
|
||||
|
||||
int encfs_removexattr(const char *path, const char *name) {
|
||||
if (isReadOnly(NULL)) return -EROFS;
|
||||
if (isReadOnly(nullptr)) {
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
return withCipherPath("removexattr", path,
|
||||
bind(_do_removexattr, _1, _2, name));
|
||||
|
@ -21,7 +21,7 @@
|
||||
#ifndef _encfs_incl_
|
||||
#define _encfs_incl_
|
||||
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
#include <fuse.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
279
encfs/encfs.pod
279
encfs/encfs.pod
@ -16,12 +16,13 @@ encfs - mounts or creates an encrypted virtual filesystem
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<encfs> [B<--version>] [B<-s>] [B<-f>] [B<-v>|B<--verbose>]
|
||||
[B<-i MINUTES>|B<--idle=MINUTES>] [B<--extpass=program>]
|
||||
[B<-S>|B<--stdinpass>] [B<--anykey>] [B<--forcedecode>]
|
||||
[B<-d>|B<--fuse-debug>] [B<--public>] [B<--no-default-flags>]
|
||||
[B<--ondemand>] [B<--delaymount>] [B<--reverse>] [B<--standard>]
|
||||
[B<-o FUSE_OPTION>]
|
||||
B<encfs> [B<--version>] [B<-v>|B<--verbose>] [B<-t>|B<--syslogtag>]
|
||||
[B<-s>] [B<-f>] [B<--annotate>] [B<--standard>] [B<--paranoia>]
|
||||
[B<--reverse>] [B<--extpass=program>] [B<-S>|B<--stdinpass>]
|
||||
[B<--anykey>] [B<--forcedecode>] [B<-require-macs>]
|
||||
[B<-i MINUTES>|B<--idle=MINUTES>] [B<-m>|B<--ondemand>] [B<--delaymount>]
|
||||
[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>
|
||||
[B<--> [I<Fuse Mount Options>]]
|
||||
|
||||
@ -42,13 +43,29 @@ may be an increasing number of choices.
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<-i>, B<--idle=MINUTES>
|
||||
=item B<--version>
|
||||
|
||||
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.
|
||||
Shows B<EncFS> version. Using B<--verbose> before B<--version> may display
|
||||
additional information.
|
||||
|
||||
=item B<-v>, B<--verbose>
|
||||
|
||||
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>
|
||||
|
||||
@ -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
|
||||
syslog.
|
||||
|
||||
=item B<-v>, B<--verbose>
|
||||
=item B<--annotate>
|
||||
|
||||
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.
|
||||
Print annotation lines to stderr during configuration.
|
||||
|
||||
=item B<-s>
|
||||
=item B<--standard>
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
=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
|
||||
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<--paranoia>
|
||||
|
||||
=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<--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.
|
||||
Same as B<--standard>, but for B<paranoia> mode.
|
||||
|
||||
=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
|
||||
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>
|
||||
|
||||
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.
|
||||
|
||||
=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
|
||||
|
||||
=head1 ENVIRONMENT VARIABLES
|
||||
|
@ -53,8 +53,6 @@ using namespace std;
|
||||
using gnu::autosprintf;
|
||||
using namespace encfs;
|
||||
|
||||
INITIALIZE_EASYLOGGINGPP
|
||||
|
||||
static int showInfo(int argc, char **argv);
|
||||
static int showVersion(int argc, char **argv);
|
||||
static int chpasswd(int argc, char **argv);
|
||||
|
@ -6,16 +6,17 @@
|
||||
# Contributed by David Rosenstrauch.
|
||||
|
||||
canonicalize() {
|
||||
cd "$1"
|
||||
cd "$1" || return
|
||||
pwd
|
||||
}
|
||||
|
||||
|
||||
if [ -z "$1" -o "$1" = "-h" ]; then
|
||||
echo Usage: encfssh encrypted_directory [unencrypted-directory [-p]]
|
||||
case $1 in "" | -h | --help)
|
||||
echo "Usage: encfssh encrypted_directory [unencrypted-directory [-p]]"
|
||||
echo " -p mount the unencrypted directory as public"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
enc_dir=$1
|
||||
unenc_dir_given=false
|
||||
@ -28,42 +29,65 @@ if [ ! -z "$2" ]; then
|
||||
mount_public=true
|
||||
fi
|
||||
done
|
||||
[ -d "$unenc_dir" ] || mkdir $unenc_dir
|
||||
[ -d "$unenc_dir" ] || mkdir -- "$unenc_dir"
|
||||
else
|
||||
unenc_dir=$(mktemp -d .XXXXXXXX)
|
||||
fi
|
||||
|
||||
if [ ! -d "$enc_dir" ]; then
|
||||
mkdir $enc_dir
|
||||
mkdir -- "$enc_dir"
|
||||
fi
|
||||
|
||||
enc_dir=$(canonicalize "$enc_dir")
|
||||
unenc_dir=$(canonicalize "$unenc_dir")
|
||||
|
||||
options=""
|
||||
if $unenc_dir_given; then
|
||||
if $mount_public; then
|
||||
options=
|
||||
if [ "$unenc_dir_given" = "true" ]; then
|
||||
if [ "$mount_public" = "true" ]; then
|
||||
options="-- -o allow_other"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 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"
|
||||
rmdir $unenc_dir
|
||||
rmdir -- "$unenc_dir"
|
||||
exit 1
|
||||
fi
|
||||
if ! $unenc_dir_given; then
|
||||
chmod 700 $unenc_dir
|
||||
if ! [ "$unenc_dir_given" = "true" ]; then
|
||||
chmod 700 "$unenc_dir"
|
||||
fi
|
||||
echo "Directory is $unenc_dir"
|
||||
orig_dir=$(pwd)
|
||||
cd $unenc_dir
|
||||
echo "Directory is $unenc_dir" >&2
|
||||
cd "$unenc_dir" || exit
|
||||
|
||||
# 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:+fusermount -u}"
|
||||
FUSE_UMOUNT="${FUSE_UMOUNT:-umount}"
|
||||
fuse_umount() {
|
||||
if command -v fusermount >/dev/null 2>&1; then
|
||||
fusermount -u "$@"
|
||||
else
|
||||
umount "$@" # MacOS case
|
||||
fi
|
||||
}
|
||||
|
||||
# Set the shell up
|
||||
exec /bin/sh -c "$SHELL ; cd $orig_dir ; $FUSE_UMOUNT $unenc_dir ; if ! $unenc_dir_given; then rmdir $unenc_dir; fi"
|
||||
# Honor the SHELL environment variable to select a shell to run
|
||||
"$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"
|
||||
|
232
encfs/main.cpp
232
encfs/main.cpp
@ -18,18 +18,18 @@
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <exception>
|
||||
#include <getopt.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <pthread.h>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "Context.h"
|
||||
@ -43,11 +43,6 @@
|
||||
#include "i18n.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
|
||||
* not have a short version */
|
||||
#define LONG_OPT_ANNOTATE 513
|
||||
@ -58,8 +53,6 @@ using namespace std;
|
||||
using namespace encfs;
|
||||
using gnu::autosprintf;
|
||||
|
||||
INITIALIZE_EASYLOGGINGPP
|
||||
|
||||
namespace encfs {
|
||||
|
||||
class DirNode;
|
||||
@ -80,6 +73,7 @@ struct EncFS_Args {
|
||||
int idleTimeout; // 0 == idle time in minutes to trigger unmount
|
||||
const char *fuseArgv[MaxFuseArgs];
|
||||
int fuseArgc;
|
||||
std::string syslogTag; // syslog tag to use when logging using syslog
|
||||
|
||||
std::shared_ptr<EncFS_Opts> opts;
|
||||
|
||||
@ -91,17 +85,36 @@ struct EncFS_Args {
|
||||
ostringstream ss;
|
||||
ss << (isDaemon ? "(daemon) " : "(fg) ");
|
||||
ss << (isThreaded ? "(threaded) " : "(UP) ");
|
||||
if (idleTimeout > 0) ss << "(timeout " << idleTimeout << ") ";
|
||||
if (opts->checkKey) ss << "(keyCheck) ";
|
||||
if (opts->forceDecode) ss << "(forceDecode) ";
|
||||
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] << ' ';
|
||||
|
||||
if (idleTimeout > 0) {
|
||||
ss << "(timeout " << idleTimeout << ") ";
|
||||
}
|
||||
if (opts->checkKey) {
|
||||
ss << "(keyCheck) ";
|
||||
}
|
||||
if (opts->forceDecode) {
|
||||
ss << "(forceDecode) ";
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
@ -167,18 +180,21 @@ static void FuseUsage() {
|
||||
|
||||
int argc = 2;
|
||||
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) \
|
||||
do { \
|
||||
rAssert(out->fuseArgc < MaxFuseArgs); \
|
||||
out->fuseArgv[out->fuseArgc++] = (ARG); \
|
||||
} while (0)
|
||||
} while (false)
|
||||
|
||||
static string slashTerminate(const string &src) {
|
||||
string result = src;
|
||||
if (result[result.length() - 1] != '/') result.append("/");
|
||||
if (result[result.length() - 1] != '/') {
|
||||
result.append("/");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -190,6 +206,7 @@ static bool processArgs(int argc, char *argv[],
|
||||
out->isVerbose = false;
|
||||
out->idleTimeout = 0;
|
||||
out->fuseArgc = 0;
|
||||
out->syslogTag = "encfs";
|
||||
out->opts->idleTracking = false;
|
||||
out->opts->checkKey = true;
|
||||
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
|
||||
// any flags
|
||||
out->fuseArgv[1] = NULL;
|
||||
out->fuseArgv[1] = nullptr;
|
||||
++out->fuseArgc;
|
||||
|
||||
// TODO: can flags be internationalized?
|
||||
static struct option long_options[] = {
|
||||
{"fuse-debug", 0, 0, 'd'}, // Fuse debug mode
|
||||
{"forcedecode", 0, 0, 'D'}, // force decode
|
||||
{"fuse-debug", 0, nullptr, 'd'}, // Fuse debug mode
|
||||
{"forcedecode", 0, nullptr, 'D'}, // force decode
|
||||
// {"foreground", 0, 0, 'f'}, // foreground mode (no daemon)
|
||||
{"fuse-help", 0, 0, 'H'}, // fuse_mount usage
|
||||
{"idle", 1, 0, 'i'}, // idle timeout
|
||||
{"anykey", 0, 0, 'k'}, // skip key checks
|
||||
{"no-default-flags", 0, 0, 'N'}, // don't use default fuse flags
|
||||
{"ondemand", 0, 0, 'm'}, // mount on-demand
|
||||
{"delaymount", 0, 0, 'M'}, // delay initial mount until use
|
||||
{"public", 0, 0, 'P'}, // public mode
|
||||
{"extpass", 1, 0, 'p'}, // external password program
|
||||
{"fuse-help", 0, nullptr, 'H'}, // fuse_mount usage
|
||||
{"idle", 1, nullptr, 'i'}, // idle timeout
|
||||
{"anykey", 0, nullptr, 'k'}, // skip key checks
|
||||
{"no-default-flags", 0, nullptr, 'N'}, // don't use default fuse flags
|
||||
{"ondemand", 0, nullptr, 'm'}, // mount on-demand
|
||||
{"delaymount", 0, nullptr, 'M'}, // delay initial mount until use
|
||||
{"public", 0, nullptr, 'P'}, // public mode
|
||||
{"extpass", 1, nullptr, 'p'}, // external password program
|
||||
// {"single-thread", 0, 0, 's'}, // single-threaded mode
|
||||
{"stdinpass", 0, 0, 'S'}, // read password from stdin
|
||||
{"annotate", 0, 0,
|
||||
LONG_OPT_ANNOTATE}, // Print annotation lines to stderr
|
||||
{"nocache", 0, 0, LONG_OPT_NOCACHE}, // disable caching
|
||||
{"verbose", 0, 0, 'v'}, // verbose mode
|
||||
{"version", 0, 0, 'V'}, // version
|
||||
{"reverse", 0, 0, 'r'}, // reverse encryption
|
||||
{"standard", 0, 0, '1'}, // standard configuration
|
||||
{"paranoia", 0, 0, '2'}, // standard configuration
|
||||
{"require-macs", 0, 0, LONG_OPT_REQUIRE_MAC}, // require MACs
|
||||
{0, 0, 0, 0}};
|
||||
{"stdinpass", 0, nullptr, 'S'}, // read password from stdin
|
||||
{"syslogtag", 1, nullptr, 't'}, // syslog tag
|
||||
{"annotate", 0, nullptr,
|
||||
LONG_OPT_ANNOTATE}, // Print annotation lines to stderr
|
||||
{"nocache", 0, nullptr, LONG_OPT_NOCACHE}, // disable caching
|
||||
{"verbose", 0, nullptr, 'v'}, // verbose mode
|
||||
{"version", 0, nullptr, 'V'}, // version
|
||||
{"reverse", 0, nullptr, 'r'}, // reverse encryption
|
||||
{"standard", 0, nullptr, '1'}, // standard configuration
|
||||
{"paranoia", 0, nullptr, '2'}, // standard configuration
|
||||
{"require-macs", 0, nullptr, LONG_OPT_REQUIRE_MAC}, // require MACs
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
|
||||
while (1) {
|
||||
while (true) {
|
||||
int option_index = 0;
|
||||
|
||||
// 's' : single-threaded mode
|
||||
@ -247,10 +265,13 @@ static bool processArgs(int argc, char *argv[],
|
||||
// 'm' : mount-on-demand
|
||||
// 'S' : password from stdin
|
||||
// 'o' : arguments meant for fuse
|
||||
// 't' : syslog tag
|
||||
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) {
|
||||
case '1':
|
||||
@ -265,6 +286,9 @@ static bool processArgs(int argc, char *argv[],
|
||||
case 'S':
|
||||
out->opts->useStdin = true;
|
||||
break;
|
||||
case 't':
|
||||
out->syslogTag = optarg;
|
||||
break;
|
||||
case LONG_OPT_ANNOTATE:
|
||||
out->opts->annotate = true;
|
||||
break;
|
||||
@ -283,7 +307,7 @@ static bool processArgs(int argc, char *argv[],
|
||||
PUSHARG("-d");
|
||||
break;
|
||||
case 'i':
|
||||
out->idleTimeout = strtol(optarg, (char **)NULL, 10);
|
||||
out->idleTimeout = strtol(optarg, (char **)nullptr, 10);
|
||||
out->opts->idleTracking = true;
|
||||
break;
|
||||
case 'k':
|
||||
@ -342,9 +366,9 @@ static bool processArgs(int argc, char *argv[],
|
||||
out->opts->passwordProgram.assign(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
if (geteuid() != 0)
|
||||
if (geteuid() != 0) {
|
||||
RLOG(WARNING) << "option '--public' ignored for non-root user";
|
||||
else {
|
||||
} else {
|
||||
out->opts->ownerCreate = true;
|
||||
// add 'allow_other' option
|
||||
// add 'default_permissions' option (default)
|
||||
@ -355,6 +379,12 @@ static bool processArgs(int argc, char *argv[],
|
||||
case 'V':
|
||||
// xgroup(usage)
|
||||
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);
|
||||
break;
|
||||
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
|
||||
// the mount point.
|
||||
@ -486,15 +518,10 @@ static bool processArgs(int argc, char *argv[],
|
||||
static void *idleMonitor(void *);
|
||||
|
||||
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
|
||||
conn->async_read = true;
|
||||
|
||||
if (ctx->args->isDaemon) {
|
||||
// Switch to using syslog.
|
||||
encfs::rlogAction = el::base::DispatchAction::SysLog;
|
||||
}
|
||||
conn->async_read = 1u;
|
||||
|
||||
// if an idle timeout is specified, then setup a thread to monitor the
|
||||
// filesystem.
|
||||
@ -502,7 +529,8 @@ void *encfs_init(fuse_conn_info *conn) {
|
||||
VLOG(1) << "starting idle monitoring thread";
|
||||
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) {
|
||||
int eno = errno;
|
||||
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
|
||||
// we've processed it and only allowed through what we support.
|
||||
std::shared_ptr<EncFS_Args> encfsArgs(new EncFS_Args);
|
||||
for (int i = 0; i < MaxFuseArgs; ++i)
|
||||
encfsArgs->fuseArgv[i] = NULL; // libfuse expects null args..
|
||||
for (int i = 0; i < MaxFuseArgs; ++i) {
|
||||
encfsArgs->fuseArgv[i] = nullptr; // libfuse expects null args..
|
||||
}
|
||||
|
||||
if (argc == 1 || !processArgs(argc, argv, encfsArgs)) {
|
||||
usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (encfsArgs->isVerbose) {
|
||||
el::Loggers::setVerboseLevel(1);
|
||||
}
|
||||
|
||||
encfs::initLogging(encfsArgs->isVerbose);
|
||||
encfs::initLogging(encfsArgs->isVerbose, encfsArgs->isDaemon);
|
||||
ELPP_INITIALIZE_SYSLOG(encfsArgs->syslogTag.c_str(), LOG_PID, LOG_USER);
|
||||
|
||||
VLOG(1) << "Root directory: " << encfsArgs->opts->rootDir;
|
||||
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
|
||||
// the filesystem.
|
||||
auto ctx = std::shared_ptr<EncFS_Context>(new EncFS_Context);
|
||||
auto ctx = std::make_shared<EncFS_Context>();
|
||||
ctx->publicFilesystem = encfsArgs->opts->ownerCreate;
|
||||
RootPtr rootInfo = initFS(ctx.get(), encfsArgs->opts);
|
||||
|
||||
@ -617,7 +643,7 @@ int main(int argc, char *argv[]) {
|
||||
ctx->args = encfsArgs;
|
||||
ctx->opts = encfsArgs->opts;
|
||||
|
||||
if (encfsArgs->isThreaded == false && encfsArgs->idleTimeout > 0) {
|
||||
if (!encfsArgs->isThreaded && encfsArgs->idleTimeout > 0) {
|
||||
// xgroup(usage)
|
||||
cerr << _("Note: requested single-threaded mode, but an idle\n"
|
||||
"timeout was specified. The filesystem will operate\n"
|
||||
@ -639,7 +665,9 @@ int main(int argc, char *argv[]) {
|
||||
try {
|
||||
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
|
||||
// exit. Only print information if fuse_main returned
|
||||
@ -653,9 +681,13 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
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) &&
|
||||
(endTime - startTime <= 1)) {
|
||||
@ -684,7 +716,7 @@ int main(int argc, char *argv[]) {
|
||||
pthread_cond_signal(&ctx->wakeupCond);
|
||||
pthread_mutex_unlock(&ctx->wakeupMutex);
|
||||
VLOG(1) << "joining with idle monitoring thread";
|
||||
pthread_join(ctx->monitorThread, 0);
|
||||
pthread_join(ctx->monitorThread, nullptr);
|
||||
VLOG(1) << "join done";
|
||||
}
|
||||
}
|
||||
@ -710,34 +742,45 @@ const int ActivityCheckInterval = 10;
|
||||
static bool unmountFS(EncFS_Context *ctx);
|
||||
|
||||
static void *idleMonitor(void *_arg) {
|
||||
EncFS_Context *ctx = (EncFS_Context *)_arg;
|
||||
auto *ctx = (EncFS_Context *)_arg;
|
||||
std::shared_ptr<EncFS_Args> arg = ctx->args;
|
||||
|
||||
const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval;
|
||||
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);
|
||||
|
||||
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;
|
||||
else
|
||||
} else {
|
||||
if (idleCycles >= timeoutCycles) {
|
||||
RLOG(INFO) << "Filesystem no longer inactive: "
|
||||
<< arg->opts->mountPoint;
|
||||
}
|
||||
idleCycles = 0;
|
||||
}
|
||||
|
||||
if (idleCycles >= timeoutCycles) {
|
||||
int openCount = ctx->openFileCount();
|
||||
if (openCount == 0) {
|
||||
if (unmountFS(ctx)) {
|
||||
unmountres = unmountFS(ctx);
|
||||
if (unmountres) {
|
||||
// wait for main thread to wake us up
|
||||
pthread_cond_wait(&ctx->wakeupCond, &ctx->wakeupMutex);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
RLOG(WARNING) << "Filesystem " << arg->opts->mountPoint
|
||||
<< " inactivity detected, but still " << openCount
|
||||
<< " opened files";
|
||||
RLOG(WARNING) << "Filesystem inactive, but " << openCount
|
||||
<< " files opened: " << arg->opts->mountPoint;
|
||||
}
|
||||
}
|
||||
|
||||
@ -745,7 +788,7 @@ static void *idleMonitor(void *_arg) {
|
||||
<< timeoutCycles;
|
||||
|
||||
struct timeval currentTime;
|
||||
gettimeofday(¤tTime, 0);
|
||||
gettimeofday(¤tTime, nullptr);
|
||||
struct timespec wakeupTime;
|
||||
wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval;
|
||||
wakeupTime.tv_nsec = currentTime.tv_usec * 1000;
|
||||
@ -754,9 +797,15 @@ static void *idleMonitor(void *_arg) {
|
||||
|
||||
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";
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool unmountFS(EncFS_Context *ctx) {
|
||||
@ -767,11 +816,14 @@ static bool unmountFS(EncFS_Context *ctx) {
|
||||
|
||||
ctx->setRoot(std::shared_ptr<DirNode>());
|
||||
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;
|
||||
}
|
||||
|
@ -31,8 +31,6 @@
|
||||
using namespace std;
|
||||
using namespace encfs;
|
||||
|
||||
INITIALIZE_EASYLOGGINGPP
|
||||
|
||||
void genKey(const std::shared_ptr<Cipher> &cipher) {
|
||||
CipherKey key = cipher->newRandomKey();
|
||||
|
||||
|
@ -20,9 +20,9 @@
|
||||
|
||||
#include "openssl.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <openssl/crypto.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NO_DES
|
||||
#include <openssl/rand.h>
|
||||
@ -37,20 +37,21 @@ namespace encfs {
|
||||
|
||||
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,
|
||||
int caller_line) {
|
||||
(void)caller_file;
|
||||
(void)caller_line;
|
||||
|
||||
if (!crypto_locks) {
|
||||
if (crypto_locks == nullptr) {
|
||||
VLOG(1) << "Allocating " << CRYPTO_num_locks() << " locks for OpenSSL";
|
||||
crypto_locks = new pthread_mutex_t[CRYPTO_num_locks()];
|
||||
for (int i = 0; i < CRYPTO_num_locks(); ++i)
|
||||
pthread_mutex_init(crypto_locks + i, 0);
|
||||
for (int i = 0; i < CRYPTO_num_locks(); ++i) {
|
||||
pthread_mutex_init(crypto_locks + i, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
if ((mode & CRYPTO_LOCK) != 0) {
|
||||
pthread_mutex_lock(crypto_locks + n);
|
||||
} else {
|
||||
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() {
|
||||
if (crypto_locks) {
|
||||
for (int i = 0; i < CRYPTO_num_locks(); ++i)
|
||||
if (crypto_locks != nullptr) {
|
||||
for (int i = 0; i < CRYPTO_num_locks(); ++i) {
|
||||
pthread_mutex_destroy(crypto_locks + i);
|
||||
}
|
||||
delete[] crypto_locks;
|
||||
crypto_locks = NULL;
|
||||
crypto_locks = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +97,9 @@ void openssl_shutdown(bool threaded) {
|
||||
ENGINE_cleanup();
|
||||
#endif
|
||||
|
||||
if (threaded) pthreads_locking_cleanup();
|
||||
if (threaded) {
|
||||
pthreads_locking_cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace encfs
|
||||
|
@ -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). */
|
||||
if (bufsiz == 0) {
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
return (nullptr);
|
||||
}
|
||||
|
||||
restart:
|
||||
@ -85,9 +85,9 @@ restart:
|
||||
* stdin and write to stderr unless a tty is required.
|
||||
*/
|
||||
if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) {
|
||||
if (flags & RPP_REQUIRE_TTY) {
|
||||
if ((flags & RPP_REQUIRE_TTY) != 0) {
|
||||
errno = ENOTTY;
|
||||
return (NULL);
|
||||
return (nullptr);
|
||||
}
|
||||
input = STDIN_FILENO;
|
||||
output = STDERR_FILENO;
|
||||
@ -112,7 +112,9 @@ restart:
|
||||
/* Turn off echo if possible. */
|
||||
if (tcgetattr(input, &oterm) == 0) {
|
||||
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
|
||||
if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
|
||||
term.c_cc[VSTATUS] = _POSIX_VDISABLE;
|
||||
@ -127,35 +129,46 @@ restart:
|
||||
end = buf + bufsiz - 1;
|
||||
for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) {
|
||||
if (p < end) {
|
||||
if ((flags & RPP_SEVENBIT)) ch &= 0x7f;
|
||||
if (isalpha(ch)) {
|
||||
if ((flags & RPP_FORCELOWER)) ch = tolower(ch);
|
||||
if ((flags & RPP_FORCEUPPER)) ch = toupper(ch);
|
||||
if ((flags & RPP_SEVENBIT) != 0) {
|
||||
ch &= 0x7f;
|
||||
}
|
||||
if (isalpha(ch) != 0) {
|
||||
if ((flags & RPP_FORCELOWER) != 0) {
|
||||
ch = tolower(ch);
|
||||
}
|
||||
if ((flags & RPP_FORCEUPPER) != 0) {
|
||||
ch = toupper(ch);
|
||||
}
|
||||
}
|
||||
*p++ = ch;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
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. */
|
||||
if (memcmp(&term, &oterm, sizeof(term)) != 0)
|
||||
if (memcmp(&term, &oterm, sizeof(term)) != 0) {
|
||||
(void)tcsetattr(input, _T_FLUSH, &oterm);
|
||||
(void)sigaction(SIGINT, &saveint, NULL);
|
||||
(void)sigaction(SIGHUP, &savehup, NULL);
|
||||
(void)sigaction(SIGQUIT, &savequit, NULL);
|
||||
(void)sigaction(SIGTERM, &saveterm, NULL);
|
||||
(void)sigaction(SIGTSTP, &savetstp, NULL);
|
||||
(void)sigaction(SIGTTIN, &savettin, NULL);
|
||||
(void)sigaction(SIGTTOU, &savettou, NULL);
|
||||
if (input != STDIN_FILENO) (void)close(input);
|
||||
}
|
||||
(void)sigaction(SIGINT, &saveint, nullptr);
|
||||
(void)sigaction(SIGHUP, &savehup, nullptr);
|
||||
(void)sigaction(SIGQUIT, &savequit, nullptr);
|
||||
(void)sigaction(SIGTERM, &saveterm, nullptr);
|
||||
(void)sigaction(SIGTSTP, &savetstp, nullptr);
|
||||
(void)sigaction(SIGTTIN, &savettin, nullptr);
|
||||
(void)sigaction(SIGTTOU, &savettou, nullptr);
|
||||
if (input != STDIN_FILENO) {
|
||||
(void)close(input);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we were interrupted by a signal, resend it to ourselves
|
||||
* now that we have restored the signal handlers.
|
||||
*/
|
||||
if (signo) {
|
||||
if (signo != 0) {
|
||||
kill(getpid(), signo);
|
||||
switch (signo) {
|
||||
case SIGTSTP:
|
||||
@ -167,7 +180,7 @@ restart:
|
||||
}
|
||||
|
||||
errno = save_errno;
|
||||
return (nr == -1 ? NULL : buf);
|
||||
return (nr == -1 ? nullptr : buf);
|
||||
}
|
||||
#endif /* HAVE_READPASSPHRASE */
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
#include "NameIO.h"
|
||||
#include "Range.h"
|
||||
#include "StreamNameIO.h"
|
||||
#include "internal/easylogging++.h"
|
||||
#include "easylogging++.h"
|
||||
|
||||
#define NO_DES
|
||||
#include <openssl/ssl.h>
|
||||
@ -49,8 +49,6 @@
|
||||
using namespace std;
|
||||
using namespace encfs;
|
||||
|
||||
INITIALIZE_EASYLOGGINGPP
|
||||
|
||||
const int FSBlockSize = 256;
|
||||
|
||||
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);
|
||||
|
||||
// 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";
|
||||
int tmpFd = mkstemp(&name[0]);
|
||||
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));
|
||||
{
|
||||
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);
|
||||
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()));
|
||||
|
||||
|
||||
// check..
|
||||
rAssert(cfg.cipherIface.implements(cfg2.cipherIface));
|
||||
rAssert(cfg.keySize == cfg2.keySize);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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}>)
|
@ -1,6 +0,0 @@
|
||||
all: xmltest
|
||||
xmltest: xmltest.cpp tinyxml2.cpp tinyxml2.h
|
||||
test: clean xmltest
|
||||
./xmltest
|
||||
clean:
|
||||
rm -f *.o xmltest
|
4
po/ar.po
4
po/ar.po
@ -455,8 +455,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr "الإعدادات المحملة غير متوافقة مع --reverse\n"
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "الدليل \"%s\" غير موجود. هل ينبغي إنشاؤه؟ (y، n) "
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
|
||||
msgstr "الدليل \"%s\" غير موجود. هل ينبغي إنشاؤه؟ (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/be.po
4
po/be.po
@ -419,8 +419,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "Дырэкторыя \"%s\" не існуе.Ці трэба яе стварыць? (y,n) "
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
|
||||
msgstr "Дырэкторыя \"%s\" не існуе.Ці трэба яе стварыць? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/bg.po
4
po/bg.po
@ -446,8 +446,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "Директорията \"%s\" не съществува. Да бъде ли създадена? (д,н) "
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
|
||||
msgstr "Директорията \"%s\" не съществува. Да бъде ли създадена? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
2
po/bs.po
2
po/bs.po
@ -418,7 +418,7 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, 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 ""
|
||||
|
||||
msgid ""
|
||||
|
4
po/ca.po
4
po/ca.po
@ -450,9 +450,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, 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 directori \"%s\" no existeix. Desitges crear el nou directori? (y,n) "
|
||||
"El directori \"%s\" no existeix. Desitges crear el nou directori? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/cs.po
4
po/cs.po
@ -450,8 +450,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
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) "
|
||||
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) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/da.po
4
po/da.po
@ -451,8 +451,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "Mappen \"%s\" eksisterer ikke. Skal den oprettes? (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) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/de.po
4
po/de.po
@ -517,8 +517,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
|
||||
|
||||
#, c-format
|
||||
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) "
|
||||
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) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
@ -486,9 +486,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
|
||||
|
||||
#, 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? (j,n) "
|
||||
"Das Verzeichnis \"%s\" existiert nicht. Soll es angelegt werden? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
@ -489,9 +489,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
|
||||
|
||||
#, 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? (j,n) "
|
||||
"Das Verzeichnis \"%s\" existiert nicht. Soll es erstellt werden? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
@ -490,9 +490,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
|
||||
|
||||
#, 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) "
|
||||
"Das Verzeichnis \"%s\" existiert nicht. Soll es angelegt werden? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/el.po
4
po/el.po
@ -443,8 +443,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "Ο φάκελος \"%s\" δεν υπάρχει. Να τον δημιουργήσω? (y/n) "
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
|
||||
msgstr "Ο φάκελος \"%s\" δεν υπάρχει. Να τον δημιουργήσω? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
@ -153,7 +153,7 @@ msgid "Incorrect number of arguments for command \"%s\""
|
||||
msgstr ""
|
||||
|
||||
#, 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 ""
|
||||
|
||||
msgid "Unable to create directory: "
|
||||
|
4
po/eo.po
4
po/eo.po
@ -423,8 +423,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "La dosierujo \"%s\" ne ekzistas. Ĉu ĝi estu kreota? "
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
|
||||
msgstr "La dosierujo \"%s\" ne ekzistas. Ĉu ĝi estu kreota? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/es.po
4
po/es.po
@ -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"
|
||||
|
||||
#, c-format
|
||||
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) "
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
|
||||
msgstr "El directorio \"%s\" no existe. ¿Debería ser creado? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
@ -468,8 +468,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "El directorio \"%s\" no existe. ¿Deberia ser creado? (s,n) "
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
|
||||
msgstr "El directorio \"%s\" no existe. ¿Deberia ser creado? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
@ -420,7 +420,7 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, 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 ""
|
||||
|
||||
msgid ""
|
||||
|
2
po/et.po
2
po/et.po
@ -415,7 +415,7 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, 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 ""
|
||||
|
||||
msgid ""
|
||||
|
4
po/fi.po
4
po/fi.po
@ -482,8 +482,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "Hakemistoa \"%s\" ei ole olemassa. Luodaanko se? (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) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/fr.po
4
po/fr.po
@ -493,8 +493,8 @@ msgstr ""
|
||||
"La configuration chargée n'est pas compatible avec l'option --reverse\n"
|
||||
|
||||
#, c-format
|
||||
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) "
|
||||
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) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
@ -482,8 +482,8 @@ msgstr ""
|
||||
"La configuration chargée n'est pas compatible avec l'option --reverse\n"
|
||||
|
||||
#, c-format
|
||||
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) "
|
||||
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) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/gl.po
4
po/gl.po
@ -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"
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "O directorio \"%s\" non existe. Debería crealo? (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) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/he.po
4
po/he.po
@ -477,8 +477,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr "התצורה שנטענה אינה תואמת ל --reverse\n"
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "התקייה \"%s\" אינה קיימת. האם ליצור אותה? (y,n) "
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
|
||||
msgstr "התקייה \"%s\" אינה קיימת. האם ליצור אותה? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
2
po/hr.po
2
po/hr.po
@ -415,7 +415,7 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, 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 ""
|
||||
|
||||
msgid ""
|
||||
|
4
po/hu.po
4
po/hu.po
@ -485,8 +485,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
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) "
|
||||
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) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/id.po
4
po/id.po
@ -432,9 +432,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, 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 ""
|
||||
"Tidak ada direktori \"%s\", perlukah membuat direktori tersebut? (ya, tidak) "
|
||||
"Tidak ada direktori \"%s\", perlukah membuat direktori tersebut? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/it.po
4
po/it.po
@ -521,8 +521,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr "La configurazione caricata non è compatibile con --reverse\n"
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "La directory \"%s\" non esiste. Deve essere creata? (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) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/ja.po
4
po/ja.po
@ -452,8 +452,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "ディレクトリ \"%s\" が存在しません。作成しますか? (y,n) "
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,N) "
|
||||
msgstr "ディレクトリ \"%s\" が存在しません。作成しますか? (y,N) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
2
po/ko.po
2
po/ko.po
@ -420,7 +420,7 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, 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 ""
|
||||
|
||||
msgid ""
|
||||
|
4
po/lv.po
4
po/lv.po
@ -475,8 +475,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "Mape \"%s\" neeksistē. Vai radīt to? (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) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
4
po/nb.po
4
po/nb.po
@ -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"
|
||||
|
||||
#, c-format
|
||||
msgid "The directory \"%s\" does not exist. Should it be created? (y,n) "
|
||||
msgstr "Katalogen \"%s\" eksisterer ikke. Skal den opprettes? (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) "
|
||||
|
||||
msgid ""
|
||||
"The external initialization-vector chaining option has been\n"
|
||||
|
@ -434,8 +434,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
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) "
|
||||
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) "
|
||||
|
||||
msgid ""
|
||||
"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
Loading…
Reference in New Issue
Block a user