Merge branch 'master' into errno

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

View File

@ -1,9 +1,12 @@
dist: trusty
language: cpp
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

View File

@ -1,15 +1,19 @@
# 3.1 preferred, but we can often get by with 2.8.
# 3.0.2 preferred, but we can often get by with 2.8.
cmake_minimum_required(VERSION 2.8)
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)

View File

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

View File

@ -46,7 +46,7 @@ EncFS depends on a number of libraries:
* tinyxml2 : for reading and writing XML configuration files
* 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

View File

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

View File

@ -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 ..

View File

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

View File

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

View File

@ -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
View File

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

View File

@ -3,8 +3,14 @@
#cmakedefine HAVE_ATTR_XATTR_H
#cmakedefine HAVE_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

View File

@ -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" $@

View File

@ -67,15 +67,18 @@ 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);
}
if (_cache.dataLen > 0) {
clearCache(_cache, _blockSize);
}
// cache results of read -- issue reads for full blocks
IORequest tmp;
@ -86,12 +89,12 @@ ssize_t BlockFileIO::cacheReadOneBlock(const IORequest &req) const {
if (result > 0) {
_cache.offset = req.offset;
_cache.dataLen = result; // the amount we really have
if (result > req.dataLen)
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,7 +129,7 @@ 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;
// if the request is larger then a block, then request each block
@ -132,18 +137,20 @@ ssize_t BlockFileIO::read(const IORequest &req) const {
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;
blockReq.data = nullptr;
unsigned char *out = req.data;
while (size) {
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)
if (partialOffset == 0 && size >= (size_t)_blockSize) {
blockReq.data = out;
else {
if (!mb.data) mb = MemoryPool::allocate(_blockSize);
} else {
if (mb.data == nullptr) {
mb = MemoryPool::allocate(_blockSize);
}
blockReq.data = mb.data;
}
@ -158,8 +165,9 @@ ssize_t BlockFileIO::read(const IORequest &req) const {
CHECK(cpySize <= readSize);
// if we read to a temporary buffer, then move the data
if (blockReq.data != out)
if (blockReq.data != out) {
memcpy(out, blockReq.data + partialOffset, cpySize);
}
result += cpySize;
size -= cpySize;
@ -167,10 +175,13 @@ ssize_t BlockFileIO::read(const IORequest &req) const {
++blockNum;
partialOffset = 0;
if (readSize < _blockSize) break;
if (readSize < _blockSize) {
break;
}
}
if (mb.data) MemoryPool::release(mb);
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,9 +278,10 @@ 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;

View File

@ -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);
}
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,9 +122,9 @@ 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);
}
@ -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,

View File

@ -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();

View File

@ -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);

View File

@ -44,7 +44,7 @@ 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,
using CipherConstructor = std::shared_ptr<Cipher> (*)(const Interface &iface,
int keyLenBits);
struct CipherAlgorithm {
@ -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);

View File

@ -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,9 +112,10 @@ bool CipherFileIO::setIV(uint64_t iv) {
}
}
if (fileIV == 0) {
if (initHeader() < 0)
if (initHeader() < 0) {
return false;
}
}
uint64_t oldIV = externalIV;
externalIV = iv;
@ -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,9 +346,10 @@ 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) {
VLOG(1) << "streamRead(data, " << readSize << ", IV)";
@ -367,9 +383,10 @@ int CipherFileIO::writeOneBlock(const IORequest &req) {
if (haveHeader && fileIV == 0) {
int res = initHeader();
if (res < 0)
if (res < 0) {
return res;
}
}
bool ok;
if (req.dataLen != bs) {
@ -397,42 +414,44 @@ 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);
}
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);
}
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
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);
}
@ -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;
}
}
bool CipherFileIO::isWritable() const { return base->isWritable(); }

View File

@ -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;

View File

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

View File

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

View File

@ -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,10 +130,10 @@ 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;
}

View File

@ -20,7 +20,7 @@
#include "ConfigVar.h"
#include "internal/easylogging++.h"
#include "easylogging++.h"
#include <cstring>
#include "Error.h"
@ -43,9 +43,9 @@ 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;
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,9 +143,9 @@ int ConfigVar::readInt(int defaultValue) const {
int bytes = this->size();
int offset = at();
if (offset >= bytes)
if (offset >= bytes) {
return defaultValue;
else
}
return readInt();
}
@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;
return true;
} else {
if (fileType) *fileType = 0;
return false;
if (inode != nullptr) {
*inode = de->d_ino;
}
return true;
}
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);
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,7 +478,8 @@ 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,
*/
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!
@ -485,8 +487,8 @@ bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP,
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,11 +608,12 @@ 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,
*/
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,19 +651,31 @@ 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);
// See if we already have a FileNode for this path.
if (ctx != nullptr) {
node = ctx->lookupNode(plainName);
// 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()));
(rootDir + cipherName).c_str(), fuseFh));
if (fsConfig->config->externalIVChaining) node->setName(0, 0, iv);
if (fsConfig->config->externalIVChaining) {
node->setName(nullptr, nullptr, iv);
}
VLOG(1) << "created FileNode for " << node->cipherName();
}
}
return node;
}
@ -656,20 +688,22 @@ 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,
"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>();
}
@ -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..

View 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();

View File

@ -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);
}

View File

@ -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.

View File

@ -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

View File

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

View File

@ -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;
}
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,20 +260,23 @@ 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;
}

View File

@ -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;

View File

@ -23,8 +23,9 @@
#define _XOPEN_SOURCE 500 // make sure pwrite() is pulled in
#endif
#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,53 +112,44 @@ 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);
}
@ -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;
}
}
/**
@ -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;
}
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,19 +1251,20 @@ 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";
}
}
}
{
// xgroup(diag)
cout << autosprintf(_("Filename encoding: \"%s\", version %i:%i:%i"),
@ -1264,27 +1284,29 @@ 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";
}
}
}
{
cout << autosprintf(_("Key Size: %i bits"), config->keySize);
cipher = config->getCipher();
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;
}
}
} // namespace encfs

View File

@ -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 };

View File

@ -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,11 +83,12 @@ 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;
}
#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,28 +119,28 @@ 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();
}
bool operator>(const Interface &A, const Interface &B) {
if (A.name() == B.name()) {
return (diffSum(A, B) > EqualVersion);
} else
}
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();
}
bool operator>=(const Interface &A, const Interface &B) {
if (A.name() == B.name()) {
return (diffSum(A, B) >= EqualVersion);
} else
}
return A.name() < B.name();
}

View File

@ -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();

View File

@ -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,9 +230,10 @@ 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) {
// compute the mac (which includes the random data) and fill it in
@ -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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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');

View File

@ -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

View File

@ -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; }

View File

@ -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; }

View File

@ -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;
}
}
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,7 +281,7 @@ int RawFileIO::truncate(off_t size) {
}
if (fd >= 0 && canWrite) {
#ifdef FDATASYNC
#if defined(HAVE_FDATASYNC)
::fdatasync(fd);
#else
::fsync(fd);

View File

@ -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;

View File

@ -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,9 +146,10 @@ 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;
}
}
}
// - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for
@ -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;
} 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;

View File

@ -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 {

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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
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));

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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,9 +314,10 @@ 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,9 +354,10 @@ 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;
}
}
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;
}
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));

View File

@ -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>

View File

@ -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

View File

@ -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);

View File

@ -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"

View File

@ -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,
{"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, 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}};
{"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(&currentTime, 0);
gettimeofday(&currentTime, 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;
}

View File

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

View File

@ -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

View File

@ -76,7 +76,7 @@ char *readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) {
/* I suppose we could alloc on demand in this case (XXX). */
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 */

View File

@ -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,7 +191,7 @@ 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..

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -455,8 +455,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "الإعدادات المحملة غير متوافقة مع --reverse\n"
#, 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"

View File

@ -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"

View File

@ -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"

View File

@ -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 ""

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -517,8 +517,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
#, 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"

View File

@ -486,9 +486,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
#, 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"

View File

@ -489,9 +489,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
#, 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"

View File

@ -490,9 +490,9 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n"
#, 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"

View File

@ -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"

View File

@ -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: "

View File

@ -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"

View File

@ -512,8 +512,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "La configuración cargada no es compatible con --reverse\n"
#, 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"

View File

@ -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"

View File

@ -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 ""

View File

@ -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 ""

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -484,8 +484,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "A configuración cargada non é compatíbel con --reverse\n"
#, 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"

View File

@ -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"

View File

@ -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 ""

View File

@ -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"

View File

@ -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"

View File

@ -521,8 +521,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "La configurazione caricata non è compatibile con --reverse\n"
#, 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"

View File

@ -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"

View File

@ -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 ""

View File

@ -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"

View File

@ -447,8 +447,8 @@ msgid "The configuration loaded is not compatible with --reverse\n"
msgstr "Innstillingene som er lastet er ikke kompatible med --reverse\n"
#, 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"

View File

@ -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