diff --git a/.travis.yml b/.travis.yml index 65cb0ab..65c1794 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,12 @@ +dist: trusty + language: cpp -sudo: false +sudo: true compiler: - clang + - gcc branches: only: @@ -18,12 +21,11 @@ env: - secure: "KuAAwjiIqkk4vqSX/M3ZZIvQs6edm+tV8IADiklTUYZIFyxu8FgZ6RbDdMD2sef5bNZA1OZhlcbeRtiKff5CfMtvzc607Lg3NUkpi+ShMynWgqS/e0uCMf9ogEJlUiZMxf4juBi7v6DyMl/WV6pAdJmdfHtzcj8GF2mgTfQjkO8=" before_script: - - mkdir build - - cd build - - cmake .. + - sudo modprobe fuse + - cmake --version script: - - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make && ./checkops ; fi + - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./build.sh && ./test.sh ; fi addons: coverity_scan: @@ -39,7 +41,9 @@ addons: sources: - ubuntu-toolchain-r-test packages: + - attr - clang - - cmake + - fuse - libfuse-dev - + - gettext + - cmake3 diff --git a/CMakeLists.txt b/CMakeLists.txt index 62eab18..30fa9a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,19 @@ -# 3.1 preferred, but we can often get by with 2.8. +# 3.0.2 preferred, but we can often get by with 2.8. cmake_minimum_required(VERSION 2.8) +if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} LESS 3.0.2) + message(WARNING "You should use cmake 3.0.2 or newer for configuration to run correctly.") +endif() + project(EncFS C CXX) set (ENCFS_MAJOR 1) set (ENCFS_MINOR 9) -set (ENCFS_PATCH 1) +set (ENCFS_PATCH 2) set (ENCFS_VERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}.${ENCFS_PATCH}") set (ENCFS_SOVERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}") set (ENCFS_NAME "Encrypted Filesystem") -option(IWYU "Build with IWYU analyais." OFF) +option(IWYU "Build with IWYU analysis." OFF) set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake") @@ -18,6 +22,7 @@ option (BUILD_SHARED_LIBS "build shared libraries" OFF) option (USE_INTERNAL_TINYXML "use built-in TinyXML2" ON) option (ENABLE_NLS "compile with Native Language Support (using gettext)" ON) option (INSTALL_LIBENCFS "install libencfs" OFF) +option (LINT "enable lint output" OFF) if (NOT DEFINED LIB_INSTALL_DIR) set (LIB_INSTALL_DIR lib) @@ -31,10 +36,10 @@ if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.0) else () if (CMAKE_COMPILER_IS_GNUCXX) message ("** Assuming that GNU CXX uses -std=c++11 flag for C++11 compatibility.") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + list(APPEND CMAKE_CXX_FLAGS "-std=c++11") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") message ("** Assuming that Clang uses -std=c++11 flag for C++11 compatibility.") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + list(APPEND CMAKE_CXX_FLAGS "-std=c++11") else() message ("** No CMAKE C++11 check. If the build breaks, you're on your own.") endif() @@ -55,6 +60,12 @@ if (APPLE) endif() endif() +if (WIN32 OR APPLE) + set(DEFAULT_CASE_INSENSITIVE TRUE) +else() + set(DEFAULT_CASE_INSENSITIVE FALSE) +endif() + # Check for FUSE. find_package (FUSE REQUIRED) include_directories (${FUSE_INCLUDE_DIR}) @@ -64,17 +75,6 @@ add_definitions (-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26) find_package (OpenSSL REQUIRED) include_directories (${OPENSSL_INCLUDE_DIR}) -if (USE_INTERNAL_TINYXML) - message("-- Using local TinyXML2 copy") - add_subdirectory(internal/tinyxml2-3.0.0) - include_directories(${CMAKE_CURRENT_LIST_DIR}/internal/tinyxml2-3.0.0) - link_directories(${CMAKE_BINARY_DIR}/internal/tinyxml2-3.0.0) - set(TINYXML_LIBRARIES tinyxml2) -else () - find_package (TinyXML REQUIRED) - include_directories (${TINYXML_INCLUDE_DIR}) -endif () - find_program (POD2MAN pod2man) # Check for include files and stdlib properties. @@ -82,21 +82,21 @@ include (CheckIncludeFileCXX) check_include_file_cxx (attr/xattr.h HAVE_ATTR_XATTR_H) check_include_file_cxx (sys/xattr.h HAVE_SYS_XATTR_H) +include(CheckStructHasMember) +check_struct_has_member(dirent d_type dirent.h HAVE_DIRENT_D_TYPE LANGUAGE CXX) + # Check if xattr functions take extra arguments, as they do on OSX. -# Output error is misleading, so do this test quietly. include (CheckCXXSourceCompiles) -set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) -set (CMAKE_REQUIRED_QUIET True) check_cxx_source_compiles ("#include #include 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) diff --git a/ChangeLog b/ChangeLog index 27381e4..5d38a0d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,15 @@ +v1.9.2 / 2017-07-25 +=================== + * fix a use-after-free bug that was introduced in v1.9-rc1 (#214) + * cast booleans to int before writing the XML config (#343) + * support reading the config file from pipes (#253) + * add "-t" option to set syslog tag + * allow read/write in standard reverse mode (#301) + * reject empty passwords + * support building with openssl 1.1 v1.9.1 / 2016-09-18 -================== +=================== * add filehandle null check * bump version to 1.9.1 * prevent crash in elpp when verbose logging is enabled diff --git a/INSTALL.md b/INSTALL.md index 28cb422..8d0db64 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -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 diff --git a/build.sh b/build.sh index f5cf5cb..04604d7 100755 --- a/build.sh +++ b/build.sh @@ -1,15 +1,15 @@ -#!/bin/bash +#!/bin/bash -eu -set -eu +# Make sure we are in the directory this script is in. +cd "$(dirname "$0")" -if [ ! -d build ] +if [[ ! -d build ]] then mkdir build cd build cmake .. -else - cd build + cd .. fi -make +make -j2 -C build diff --git a/ci/config.sh b/ci/config.sh index c6c414a..96c4ee3 100755 --- a/ci/config.sh +++ b/ci/config.sh @@ -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 .. diff --git a/ci/install-cmake.sh b/ci/install-cmake.sh deleted file mode 100755 index 6d83860..0000000 --- a/ci/install-cmake.sh +++ /dev/null @@ -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 diff --git a/circle.yml b/circle.yml index c570296..133221b 100644 --- a/circle.yml +++ b/circle.yml @@ -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 diff --git a/cmake/FindFUSE.cmake b/cmake/FindFUSE.cmake index b1e8861..bb8cb50 100644 --- a/cmake/FindFUSE.cmake +++ b/cmake/FindFUSE.cmake @@ -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 diff --git a/cmake/FindIntl.cmake b/cmake/FindIntl.cmake new file mode 100644 index 0000000..5b719c6 --- /dev/null +++ b/cmake/FindIntl.cmake @@ -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 + +# 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() diff --git a/config.h.cmake b/config.h.cmake index 2beb78d..8548d70 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -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 diff --git a/devmode b/devmode index bdb3b63..f77a73a 100755 --- a/devmode +++ b/devmode @@ -1,5 +1,5 @@ # Script which sets up the CMake build for Debug mode. # After running, chdir to the build subdir ane run "make" mkdir build -cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug \ +cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug -DLINT=ON \ -DCMAKE_CXX_FLAGS="-O1 -fsanitize=address -fno-omit-frame-pointer" $@ diff --git a/encfs/BlockFileIO.cpp b/encfs/BlockFileIO.cpp index 11c46de..399d35e 100644 --- a/encfs/BlockFileIO.cpp +++ b/encfs/BlockFileIO.cpp @@ -67,31 +67,34 @@ ssize_t BlockFileIO::cacheReadOneBlock(const IORequest &req) const { * in the last block of a file, which may be smaller than the blocksize. * For reverse encryption, the cache must not be used at all, because * the lower file may have changed behind our back. */ - if ((_noCache == false) && (req.offset == _cache.offset) && - (_cache.dataLen != 0)) { + if ((!_noCache) && (req.offset == _cache.offset) && (_cache.dataLen != 0)) { // satisfy request from cache int len = req.dataLen; - if (_cache.dataLen < len) len = _cache.dataLen; // Don't read past EOF + if (_cache.dataLen < len) { + len = _cache.dataLen; // Don't read past EOF + } memcpy(req.data, _cache.data, len); return len; - } else { - if (_cache.dataLen > 0) clearCache(_cache, _blockSize); - - // cache results of read -- issue reads for full blocks - IORequest tmp; - tmp.offset = req.offset; - tmp.data = _cache.data; - tmp.dataLen = _blockSize; - ssize_t result = readOneBlock(tmp); - if (result > 0) { - _cache.offset = req.offset; - _cache.dataLen = result; // the amount we really have - if (result > req.dataLen) - result = req.dataLen; // only as much as requested - memcpy(req.data, _cache.data, result); - } - return result; } + if (_cache.dataLen > 0) { + clearCache(_cache, _blockSize); + } + + // cache results of read -- issue reads for full blocks + IORequest tmp; + tmp.offset = req.offset; + tmp.data = _cache.data; + tmp.dataLen = _blockSize; + ssize_t result = readOneBlock(tmp); + if (result > 0) { + _cache.offset = req.offset; + _cache.dataLen = result; // the amount we really have + if (result > req.dataLen) { + result = req.dataLen; // only as much as requested + } + memcpy(req.data, _cache.data, result); + } + return result; } int BlockFileIO::cacheWriteOneBlock(const IORequest &req) { @@ -101,7 +104,9 @@ int BlockFileIO::cacheWriteOneBlock(const IORequest &req) { _cache.offset = req.offset; _cache.dataLen = req.dataLen; int res = writeOneBlock(req); - if (res < 0) clearCache(_cache, _blockSize); + if (res < 0) { + clearCache(_cache, _blockSize); + } return res; } @@ -124,53 +129,59 @@ ssize_t BlockFileIO::read(const IORequest &req) const { // read completely within a single block -- can be handled as-is by // readOneBlock(). return cacheReadOneBlock(req); - } else { - size_t size = req.dataLen; + } + size_t size = req.dataLen; - // if the request is larger then a block, then request each block - // individually - MemBlock mb; // in case we need to allocate a temporary block.. - IORequest blockReq; // for requests we may need to make - blockReq.dataLen = _blockSize; - blockReq.data = NULL; + // if the request is larger then a block, then request each block + // individually + MemBlock mb; // in case we need to allocate a temporary block.. + IORequest blockReq; // for requests we may need to make + blockReq.dataLen = _blockSize; + blockReq.data = nullptr; - unsigned char *out = req.data; - while (size) { - blockReq.offset = blockNum * _blockSize; + unsigned char *out = req.data; + while (size != 0u) { + blockReq.offset = blockNum * _blockSize; - // if we're reading a full block, then read directly into the - // result buffer instead of using a temporary - if (partialOffset == 0 && size >= (size_t)_blockSize) - blockReq.data = out; - else { - if (!mb.data) mb = MemoryPool::allocate(_blockSize); - blockReq.data = mb.data; + // if we're reading a full block, then read directly into the + // result buffer instead of using a temporary + if (partialOffset == 0 && size >= (size_t)_blockSize) { + blockReq.data = out; + } else { + if (mb.data == nullptr) { + mb = MemoryPool::allocate(_blockSize); } - - ssize_t readSize = cacheReadOneBlock(blockReq); - if (readSize < 0) { - result = readSize; - break; - } - if (readSize <= partialOffset) break; // didn't get enough bytes - - int cpySize = min((size_t)(readSize - partialOffset), size); - CHECK(cpySize <= readSize); - - // if we read to a temporary buffer, then move the data - if (blockReq.data != out) - memcpy(out, blockReq.data + partialOffset, cpySize); - - result += cpySize; - size -= cpySize; - out += cpySize; - ++blockNum; - partialOffset = 0; - - if (readSize < _blockSize) break; + blockReq.data = mb.data; } - if (mb.data) MemoryPool::release(mb); + ssize_t readSize = cacheReadOneBlock(blockReq); + if (readSize < 0) { + result = readSize; + break; + } + if (readSize <= partialOffset) break; // didn't get enough bytes + + int cpySize = min((size_t)(readSize - partialOffset), size); + CHECK(cpySize <= readSize); + + // if we read to a temporary buffer, then move the data + if (blockReq.data != out) { + memcpy(out, blockReq.data + partialOffset, cpySize); + } + + result += cpySize; + size -= cpySize; + out += cpySize; + ++blockNum; + partialOffset = 0; + + if (readSize < _blockSize) { + break; + } + } + + if (mb.data != nullptr) { + MemoryPool::release(mb); } return result; @@ -184,7 +195,9 @@ int BlockFileIO::write(const IORequest &req) { CHECK(_blockSize != 0); off_t fileSize = getSize(); - if (fileSize < 0) return fileSize; + if (fileSize < 0) { + return fileSize; + } // where write request begins off_t blockNum = req.offset / _blockSize; @@ -195,39 +208,45 @@ int BlockFileIO::write(const IORequest &req) { ssize_t lastBlockSize = fileSize % _blockSize; off_t lastNonEmptyBlock = lastFileBlock; - if (lastBlockSize == 0) --lastNonEmptyBlock; + if (lastBlockSize == 0) { + --lastNonEmptyBlock; + } if (req.offset > fileSize) { // extend file first to fill hole with 0's.. const bool forceWrite = false; int res = padFile(fileSize, req.offset, forceWrite); - if (res < 0) + if (res < 0) { return res; + } } // check against edge cases where we can just let the base class handle the // request as-is.. if (partialOffset == 0 && req.dataLen <= _blockSize) { // if writing a full block.. pretty safe.. - if (req.dataLen == _blockSize) return cacheWriteOneBlock(req); + if (req.dataLen == _blockSize) { + return cacheWriteOneBlock(req); + } // if writing a partial block, but at least as much as what is // already there.. - if (blockNum == lastFileBlock && req.dataLen >= lastBlockSize) + if (blockNum == lastFileBlock && req.dataLen >= lastBlockSize) { return cacheWriteOneBlock(req); + } } // have to merge data with existing block(s).. MemBlock mb; IORequest blockReq; - blockReq.data = NULL; + blockReq.data = nullptr; blockReq.dataLen = _blockSize; int res = 0; size_t size = req.dataLen; unsigned char *inPtr = req.data; - while (size) { + while (size != 0u) { blockReq.offset = blockNum * _blockSize; int toCopy = min((size_t)(_blockSize - partialOffset), size); @@ -241,7 +260,9 @@ int BlockFileIO::write(const IORequest &req) { } else { // need a temporary buffer, since we have to either merge or pad // the data. - if (!mb.data) mb = MemoryPool::allocate(_blockSize); + if (mb.data == nullptr) { + mb = MemoryPool::allocate(_blockSize); + } memset(mb.data, 0, _blockSize); blockReq.data = mb.data; @@ -257,8 +278,9 @@ int BlockFileIO::write(const IORequest &req) { } // extend data if necessary.. - if (partialOffset + toCopy > blockReq.dataLen) + if (partialOffset + toCopy > blockReq.dataLen) { blockReq.dataLen = partialOffset + toCopy; + } } // merge in the data to be written.. memcpy(blockReq.data + partialOffset, inPtr, toCopy); @@ -277,7 +299,9 @@ int BlockFileIO::write(const IORequest &req) { partialOffset = 0; } - if (mb.data) MemoryPool::release(mb); + if (mb.data != nullptr) { + MemoryPool::release(mb); + } return res; } @@ -309,7 +333,7 @@ int BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) { req.dataLen = oldSize % _blockSize; int outSize = newSize % _blockSize; // outSize > req.dataLen - if (outSize) { + if (outSize != 0) { memset(mb.data, 0, outSize); if ((res = cacheReadOneBlock(req)) >= 0) { req.dataLen = outSize; @@ -360,7 +384,9 @@ int BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) { } } - if (mb.data) MemoryPool::release(mb); + if (mb.data != nullptr) { + MemoryPool::release(mb); + } return res; } @@ -376,14 +402,17 @@ int BlockFileIO::truncateBase(off_t size, FileIO *base) { // states that it will pad with 0's. // do the truncate so that the underlying filesystem can allocate // the space, and then we'll fill it in padFile.. - if (base) res = base->truncate(size); + if (base != nullptr) { + res = base->truncate(size); + } const bool forceWrite = true; - if (!(res < 0)) + if (!(res < 0)) { res = padFile(oldSize, size, forceWrite); + } } else if (size == oldSize) { // the easiest case, but least likely.... - } else if (partialBlock) { + } else if (partialBlock != 0) { // partial block after truncate. Need to read in the block being // truncated before the truncate. Then write it back out afterwards, // since the encoding will change.. @@ -396,23 +425,28 @@ int BlockFileIO::truncateBase(off_t size, FileIO *base) { req.data = mb.data; ssize_t rdSz = cacheReadOneBlock(req); - if (rdSz < 0) + if (rdSz < 0) { res = rdSz; + } // do the truncate - else if (base) + else if (base != nullptr) { res = base->truncate(size); + } // write back out partial block req.dataLen = partialBlock; - if (!res) + if (!(res < 0)) { res = cacheWriteOneBlock(req); + } MemoryPool::release(mb); } else { // truncating on a block bounday. No need to re-encode the last // block.. - if (base) res = base->truncate(size); + if (base != nullptr) { + res = base->truncate(size); + } } return res; diff --git a/encfs/BlockNameIO.cpp b/encfs/BlockNameIO.cpp index 573c96b..e6ebeb9 100644 --- a/encfs/BlockNameIO.cpp +++ b/encfs/BlockNameIO.cpp @@ -22,6 +22,7 @@ #include #include +#include #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 NewBlockNameIO( const Interface &iface, const std::shared_ptr &cipher, const CipherKey &key) { int blockSize = 8; - if (cipher) blockSize = cipher->cipherBlockSize(); + if (cipher) { + blockSize = cipher->cipherBlockSize(); + } return std::shared_ptr( new BlockNameIO(iface, cipher, key, blockSize, false)); @@ -48,7 +51,9 @@ static std::shared_ptr NewBlockNameIO32( const Interface &iface, const std::shared_ptr &cipher, const CipherKey &key) { int blockSize = 8; - if (cipher) blockSize = cipher->cipherBlockSize(); + if (cipher) { + blockSize = cipher->cipherBlockSize(); + } return std::shared_ptr( new BlockNameIO(iface, cipher, key, blockSize, true)); @@ -88,26 +93,25 @@ static bool BlockIO32_registered = NameIO::Register( */ Interface BlockNameIO::CurrentInterface(bool caseInsensitive) { // implement major version 4 plus support for two prior versions - if (caseInsensitive) + if (caseInsensitive) { return Interface("nameio/block32", 4, 0, 2); - else - return Interface("nameio/block", 4, 0, 2); + } + return Interface("nameio/block", 4, 0, 2); } -BlockNameIO::BlockNameIO(const Interface &iface, - const std::shared_ptr &cipher, - const CipherKey &key, int blockSize, +BlockNameIO::BlockNameIO(const Interface &iface, std::shared_ptr cipher, + CipherKey key, int blockSize, bool caseInsensitiveEncoding) : _interface(iface.current()), _bs(blockSize), - _cipher(cipher), - _key(key), + _cipher(std::move(cipher)), + _key(std::move(key)), _caseInsensitive(caseInsensitiveEncoding) { // just to be safe.. rAssert(blockSize < 128); } -BlockNameIO::~BlockNameIO() {} +BlockNameIO::~BlockNameIO() = default; Interface BlockNameIO::interface() const { return CurrentInterface(_caseInsensitive); @@ -118,10 +122,10 @@ int BlockNameIO::maxEncodedNameLen(int plaintextNameLen) const { // the size of too much space rather then too little. int numBlocks = (plaintextNameLen + _bs) / _bs; int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes - if (_caseInsensitive) + if (_caseInsensitive) { return B256ToB32Bytes(encodedNameLen); - else - return B256ToB64Bytes(encodedNameLen); + } + return B256ToB64Bytes(encodedNameLen); } int BlockNameIO::maxDecodedNameLen(int encodedNameLen) const { @@ -135,7 +139,9 @@ int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv, // Pad encryption buffer to block boundary.. int padding = _bs - length % _bs; - if (padding == 0) padding = _bs; // padding a full extra block! + if (padding == 0) { + padding = _bs; // padding a full extra block! + } rAssert(bufferLength >= length + 2 + padding); memset(encodedName + length + 2, (unsigned char)padding, padding); @@ -145,7 +151,9 @@ int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv, // store the IV before it is modified by the MAC call. uint64_t tmpIV = 0; - if (iv && _interface >= 3) tmpIV = *iv; + if ((iv != nullptr) && _interface >= 3) { + tmpIV = *iv; + } // include padding in MAC computation unsigned int mac = _cipher->MAC_16((unsigned char *)encodedName + 2, @@ -210,7 +218,9 @@ int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv, ((unsigned int)((unsigned char)tmpBuf[1])); uint64_t tmpIV = 0; - if (iv && _interface >= 3) tmpIV = *iv; + if ((iv != nullptr) && _interface >= 3) { + tmpIV = *iv; + } bool ok; ok = _cipher->blockDecode((unsigned char *)tmpBuf + 2, decodedStreamLen, diff --git a/encfs/BlockNameIO.h b/encfs/BlockNameIO.h index 4ea0594..653159f 100644 --- a/encfs/BlockNameIO.h +++ b/encfs/BlockNameIO.h @@ -41,8 +41,8 @@ class BlockNameIO : public NameIO { public: static Interface CurrentInterface(bool caseInsensitive = false); - BlockNameIO(const Interface &iface, const std::shared_ptr &cipher, - const CipherKey &key, int blockSize, + BlockNameIO(const Interface &iface, std::shared_ptr cipher, + CipherKey key, int blockSize, bool caseInsensitiveEncoding = false); virtual ~BlockNameIO(); diff --git a/encfs/Cipher.cpp b/encfs/Cipher.cpp index 2e1bed7..bbe43cf 100644 --- a/encfs/Cipher.cpp +++ b/encfs/Cipher.cpp @@ -18,10 +18,10 @@ * along with this program. If not, see . */ +#include #include #include #include -#include #include #include @@ -56,8 +56,8 @@ struct CipherAlg { Range blockSize; }; -typedef multimap CipherMap_t; -static CipherMap_t *gCipherMap = NULL; +using CipherMap_t = multimap; +static CipherMap_t *gCipherMap = nullptr; std::list Cipher::GetAlgorithmList( bool includeHidden) { @@ -65,7 +65,9 @@ std::list Cipher::GetAlgorithmList( list 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::New(const string &name, int keyLen) { std::shared_ptr 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::New(const string &name, int keyLen) { } std::shared_ptr Cipher::New(const Interface &iface, int keyLen) { std::shared_ptr 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::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); diff --git a/encfs/Cipher.h b/encfs/Cipher.h index 89ed4ec..5c5d709 100644 --- a/encfs/Cipher.h +++ b/encfs/Cipher.h @@ -44,8 +44,8 @@ class Cipher { public: // if no key length was indicated when cipher was registered, then keyLen // <= 0 will be used. - typedef std::shared_ptr (*CipherConstructor)(const Interface &iface, - int keyLenBits); + using CipherConstructor = std::shared_ptr (*)(const Interface &iface, + int keyLenBits); struct CipherAlgorithm { std::string name; @@ -55,7 +55,7 @@ class Cipher { Range blockSize; }; - typedef std::list AlgorithmList; + using AlgorithmList = std::list; static AlgorithmList GetAlgorithmList(bool includeHidden = false); static std::shared_ptr New(const Interface &iface, int keyLen = -1); diff --git a/encfs/CipherFileIO.cpp b/encfs/CipherFileIO.cpp index 6cf9282..a83d821 100644 --- a/encfs/CipherFileIO.cpp +++ b/encfs/CipherFileIO.cpp @@ -20,14 +20,15 @@ #include "CipherFileIO.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #include +#include +#include #include -#include #include #include -#include #include +#include #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 &_base, +CipherFileIO::CipherFileIO(std::shared_ptr _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 &_base, << "FS block size must be multiple of cipher block size"; } -CipherFileIO::~CipherFileIO() {} +CipherFileIO::~CipherFileIO() = default; Interface CipherFileIO::interface() const { return CipherFileIO_iface; } int CipherFileIO::open(int flags) { int res = base->open(flags); - if (res >= 0) lastFlags = flags; + if (res >= 0) { + lastFlags = flags; + } return res; } @@ -109,8 +112,9 @@ bool CipherFileIO::setIV(uint64_t iv) { } } if (fileIV == 0) { - if (initHeader() < 0) + if (initHeader() < 0) { return false; + } } uint64_t oldIV = externalIV; @@ -185,14 +189,18 @@ int CipherFileIO::initHeader() { req.data = buf; req.dataLen = 8; ssize_t readSize = base->read(req); - if(readSize < 0) + if(readSize < 0) { return readSize; + } - if(!cipher->streamDecode(buf, sizeof(buf), externalIV, key)) + if(!cipher->streamDecode(buf, sizeof(buf), externalIV, key)) { return -EBADMSG; + } fileIV = 0; - for (int i = 0; i < 8; ++i) fileIV = (fileIV << 8) | (uint64_t)buf[i]; + for (int i = 0; i < 8; ++i) { + fileIV = (fileIV << 8) | (uint64_t)buf[i]; + } rAssert(fileIV != 0); // 0 is never used.. } else { @@ -206,15 +214,19 @@ int CipherFileIO::initHeader() { } fileIV = 0; - for (int i = 0; i < 8; ++i) fileIV = (fileIV << 8) | (uint64_t)buf[i]; + for (int i = 0; i < 8; ++i) { + fileIV = (fileIV << 8) | (uint64_t)buf[i]; + } - if (fileIV == 0) + if (fileIV == 0) { RLOG(WARNING) << "Unexpected result: randomize returned 8 null bytes!"; + } } while (fileIV == 0); // don't accept 0 as an option.. if (base->isWritable()) { - if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key)) + if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key)) { return -EBADMSG; + } IORequest req; req.offset = 0; @@ -222,8 +234,9 @@ int CipherFileIO::initHeader() { req.dataLen = 8; int res = base->write(req); - if (res < 0) + if (res < 0) { return res; + } } else { VLOG(1) << "base not writable, IV not written.."; } @@ -244,16 +257,18 @@ bool CipherFileIO::writeHeader() { fileIV >>= 8; } - if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key)) + if(!cipher->streamEncode(buf, sizeof(buf), externalIV, key)) { return false; + } IORequest req; req.offset = 0; req.data = buf; req.dataLen = 8; - if (base->write(req) < 0) + if (base->write(req) < 0) { return false; + } return true; } @@ -331,8 +346,9 @@ ssize_t CipherFileIO::readOneBlock(const IORequest &req) const { if (readSize > 0) { if (haveHeader && fileIV == 0) { int res = const_cast(this)->initHeader(); - if (res < 0) + if (res < 0) { return res; + } } if (readSize != bs) { @@ -367,8 +383,9 @@ int CipherFileIO::writeOneBlock(const IORequest &req) { if (haveHeader && fileIV == 0) { int res = initHeader(); - if (res < 0) + if (res < 0) { return res; + } } bool ok; @@ -397,43 +414,45 @@ int CipherFileIO::writeOneBlock(const IORequest &req) { bool CipherFileIO::blockWrite(unsigned char *buf, int size, uint64_t _iv64) const { VLOG(1) << "Called blockWrite"; - if (!fsConfig->reverseEncryption) + if (!fsConfig->reverseEncryption) { return cipher->blockEncode(buf, size, _iv64, key); - else - return cipher->blockDecode(buf, size, _iv64, key); + } + return cipher->blockDecode(buf, size, _iv64, key); } bool CipherFileIO::streamWrite(unsigned char *buf, int size, uint64_t _iv64) const { VLOG(1) << "Called streamWrite"; - if (!fsConfig->reverseEncryption) + if (!fsConfig->reverseEncryption) { return cipher->streamEncode(buf, size, _iv64, key); - else - return cipher->streamDecode(buf, size, _iv64, key); + } + return cipher->streamDecode(buf, size, _iv64, key); } bool CipherFileIO::blockRead(unsigned char *buf, int size, uint64_t _iv64) const { - if (fsConfig->reverseEncryption) + if (fsConfig->reverseEncryption) { return cipher->blockEncode(buf, size, _iv64, key); - else { - if (_allowHoles) { - // special case - leave all 0's alone - for (int i = 0; i < size; ++i) - if (buf[i] != 0) return cipher->blockDecode(buf, size, _iv64, key); - - return true; - } else - return cipher->blockDecode(buf, size, _iv64, key); } + if (_allowHoles) { + // special case - leave all 0's alone + for (int i = 0; i < size; ++i) { + if (buf[i] != 0) { + return cipher->blockDecode(buf, size, _iv64, key); + } + } + + return true; + } + return cipher->blockDecode(buf, size, _iv64, key); } bool CipherFileIO::streamRead(unsigned char *buf, int size, uint64_t _iv64) const { - if (fsConfig->reverseEncryption) + if (fsConfig->reverseEncryption) { return cipher->streamEncode(buf, size, _iv64, key); - else - return cipher->streamDecode(buf, size, _iv64, key); + } + return cipher->streamDecode(buf, size, _iv64, key); } int CipherFileIO::truncate(off_t size) { @@ -453,15 +472,18 @@ int CipherFileIO::truncate(off_t size) { } } int res = initHeader(); - if (res < 0) + if (res < 0) { return res; + } } // can't let BlockFileIO call base->truncate(), since it would be using // the wrong size.. - res = BlockFileIO::truncateBase(size, 0); + res = BlockFileIO::truncateBase(size, nullptr); - if (!(res < 0)) res = base->truncate(size + HEADER_SIZE); + if (!(res < 0)) { + res = base->truncate(size + HEADER_SIZE); + } } return res; } @@ -486,8 +508,9 @@ ssize_t CipherFileIO::read(const IORequest &origReq) const { // this is needed in any case - without IV the file cannot be decoded unsigned char headerBuf[HEADER_SIZE]; int res = const_cast(this)->generateReverseHeader(headerBuf); - if (res < 0) + if (res < 0) { return res; + } // Copy the request so we can modify it without affecting the caller IORequest req = origReq; @@ -502,8 +525,9 @@ ssize_t CipherFileIO::read(const IORequest &origReq) const { * to the data. */ if (req.offset < 0) { headerBytes = -req.offset; - if (req.dataLen < headerBytes) + if (req.dataLen < headerBytes) { headerBytes = req.dataLen; // only up to the number of bytes requested + } VLOG(1) << "Adding " << headerBytes << " header bytes"; // copy the header bytes into the data @@ -511,7 +535,9 @@ ssize_t CipherFileIO::read(const IORequest &origReq) const { memcpy(req.data, &headerBuf[headerOffset], headerBytes); // the read does not want data beyond the header - if (headerBytes == req.dataLen) return headerBytes; + if (headerBytes == req.dataLen) { + return headerBytes; + } /* The rest of the request will be read from the backing file. * As we have already generated n=headerBytes bytes, the request is @@ -525,13 +551,12 @@ ssize_t CipherFileIO::read(const IORequest &origReq) const { // read the payload ssize_t readBytes = BlockFileIO::read(req); VLOG(1) << "read " << readBytes << " bytes from backing file"; - if (readBytes < 0) + if (readBytes < 0) { return readBytes; // Return error code - else { - ssize_t sum = headerBytes + readBytes; - VLOG(1) << "returning sum=" << sum; - return sum; } + ssize_t sum = headerBytes + readBytes; + VLOG(1) << "returning sum=" << sum; + return sum; } bool CipherFileIO::isWritable() const { return base->isWritable(); } diff --git a/encfs/CipherFileIO.h b/encfs/CipherFileIO.h index d27444c..9378e88 100644 --- a/encfs/CipherFileIO.h +++ b/encfs/CipherFileIO.h @@ -45,7 +45,7 @@ struct IORequest; */ class CipherFileIO : public BlockFileIO { public: - CipherFileIO(const std::shared_ptr &base, const FSConfigPtr &cfg); + CipherFileIO(std::shared_ptr base, const FSConfigPtr &cfg); virtual ~CipherFileIO(); virtual Interface interface() const; diff --git a/encfs/CipherKey.cpp b/encfs/CipherKey.cpp index bf3f168..5a914e6 100644 --- a/encfs/CipherKey.cpp +++ b/encfs/CipherKey.cpp @@ -22,8 +22,8 @@ namespace encfs { -AbstractCipherKey::AbstractCipherKey() {} +AbstractCipherKey::AbstractCipherKey() = default; -AbstractCipherKey::~AbstractCipherKey() {} +AbstractCipherKey::~AbstractCipherKey() = default; } // namespace encfs diff --git a/encfs/CipherKey.h b/encfs/CipherKey.h index 42ddb8a..505b899 100644 --- a/encfs/CipherKey.h +++ b/encfs/CipherKey.h @@ -31,7 +31,7 @@ class AbstractCipherKey { virtual ~AbstractCipherKey(); }; -typedef std::shared_ptr CipherKey; +using CipherKey = std::shared_ptr; } // namespace encfs diff --git a/encfs/ConfigReader.cpp b/encfs/ConfigReader.cpp index e622ecf..8e2fd1a 100644 --- a/encfs/ConfigReader.cpp +++ b/encfs/ConfigReader.cpp @@ -33,23 +33,27 @@ using namespace std; namespace encfs { -ConfigReader::ConfigReader() {} +ConfigReader::ConfigReader() = default; -ConfigReader::~ConfigReader() {} +ConfigReader::~ConfigReader() = default; // read the entire file into a ConfigVar instance and then use that to decode // into mapped variables. bool ConfigReader::load(const char *fileName) { struct stat stbuf; memset(&stbuf, 0, sizeof(struct stat)); - if (lstat(fileName, &stbuf) != 0) return false; + if (lstat(fileName, &stbuf) != 0) { + return false; + } int size = stbuf.st_size; int fd = open(fileName, O_RDONLY); - if (fd < 0) return false; + if (fd < 0) { + return false; + } - char *buf = new char[size]; + auto *buf = new char[size]; int res = ::read(fd, buf, size); close(fd); @@ -126,11 +130,11 @@ ConfigVar ConfigReader::toVar() const { ConfigVar ConfigReader::operator[](const std::string &varName) const { // read only - map::const_iterator it = vars.find(varName); - if (it == vars.end()) + auto it = vars.find(varName); + if (it == vars.end()) { return ConfigVar(); - else - return it->second; + } + return it->second; } ConfigVar &ConfigReader::operator[](const std::string &varName) { diff --git a/encfs/ConfigVar.cpp b/encfs/ConfigVar.cpp index a4fadc8..4a39f00 100644 --- a/encfs/ConfigVar.cpp +++ b/encfs/ConfigVar.cpp @@ -20,7 +20,7 @@ #include "ConfigVar.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include "Error.h" @@ -43,10 +43,10 @@ ConfigVar::ConfigVar(const ConfigVar &src) { pd = src.pd; } ConfigVar::~ConfigVar() { pd.reset(); } ConfigVar &ConfigVar::operator=(const ConfigVar &src) { - if (src.pd == pd) + if (src.pd == pd) { return *this; - else - pd = src.pd; + } + pd = src.pd; return *this; } @@ -56,7 +56,9 @@ void ConfigVar::resetOffset() { pd->offset = 0; } int ConfigVar::read(unsigned char *buffer_, int bytes) const { int toCopy = MIN(bytes, pd->buffer.size() - pd->offset); - if (toCopy > 0) memcpy(buffer_, pd->buffer.data() + pd->offset, toCopy); + if (toCopy > 0) { + memcpy(buffer_, pd->buffer.data() + pd->offset, toCopy); + } pd->offset += toCopy; @@ -106,13 +108,15 @@ void ConfigVar::writeInt(int val) { // find the starting point - we only need to output starting at the most // significant non-zero digit.. int start = 0; - while (digit[start] == 0x80) ++start; + while (digit[start] == 0x80) { + ++start; + } write(digit + start, 5 - start); } int ConfigVar::readInt() const { - const unsigned char *buf = (const unsigned char *)buffer(); + const auto *buf = (const unsigned char *)buffer(); int bytes = this->size(); int offset = at(); int value = 0; @@ -122,7 +126,7 @@ int ConfigVar::readInt() const { do { unsigned char tmp = buf[offset++]; - highBitSet = tmp & 0x80; + highBitSet = ((tmp & 0x80) != 0); value = (value << 7) | (int)(tmp & 0x7f); } while (highBitSet && offset < bytes); @@ -139,10 +143,10 @@ int ConfigVar::readInt(int defaultValue) const { int bytes = this->size(); int offset = at(); - if (offset >= bytes) + if (offset >= bytes) { return defaultValue; - else - return readInt(); + } + return readInt(); } bool ConfigVar::readBool(bool defaultValue) const { @@ -184,7 +188,7 @@ const ConfigVar &operator>>(const ConfigVar &src, std::string &result) { unsigned char tmpBuf[32]; if (length > (int)sizeof(tmpBuf)) { - unsigned char *ptr = new unsigned char[length]; + auto *ptr = new unsigned char[length]; readLen = src.read(ptr, length); result.assign((char *)ptr, length); delete[] ptr; diff --git a/encfs/Context.cpp b/encfs/Context.cpp index 4cdcd36..bfbcbf3 100644 --- a/encfs/Context.cpp +++ b/encfs/Context.cpp @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #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 &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 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 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 &&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 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 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 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 diff --git a/encfs/Context.h b/encfs/Context.h index ada1e02..56b0fc4 100644 --- a/encfs/Context.h +++ b/encfs/Context.h @@ -21,7 +21,9 @@ #ifndef _Context_incl_ #define _Context_incl_ -#include +#include +#include +#include #include #include #include @@ -44,12 +46,11 @@ class EncFS_Context { std::shared_ptr lookupNode(const char *path); - int getAndResetUsageCounter(); - int openFileCount() const; + void getAndResetUsageCounter(int *usage, int *openCount); - FileNode *putNode(const char *path, std::shared_ptr &&node); + void putNode(const char *path, std::shared_ptr node); - void eraseNode(const char *path, FileNode *fnode); + void eraseNode(const char *path, std::shared_ptr 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 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>> - FileMap; + using FileMap = + std::unordered_map>>; mutable pthread_mutex_t contextMutex; FileMap openFiles; int usageCount; std::shared_ptr root; + + std::atomic currentFuseFh; + std::unordered_map> fuseFhMap; }; int remountFS(EncFS_Context *ctx); diff --git a/encfs/DirNode.cpp b/encfs/DirNode.cpp index 2e65f23..17a30f4 100644 --- a/encfs/DirNode.cpp +++ b/encfs/DirNode.cpp @@ -35,8 +35,9 @@ #include #endif -#include "internal/easylogging++.h" +#include "easylogging++.h" #include +#include #include "Context.h" #include "Error.h" @@ -51,20 +52,13 @@ class DirDeleter { void operator()(DIR *d) { ::closedir(d); } }; -DirTraverse::DirTraverse(const std::shared_ptr &_dirPtr, uint64_t _iv, - const std::shared_ptr &_naming) - : dir(_dirPtr), iv(_iv), naming(_naming) {} +DirTraverse::DirTraverse(std::shared_ptr _dirPtr, uint64_t _iv, + std::shared_ptr _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, int *fileType, ino_t *inode) { de = ::readdir(dir.get()); - if (de) { - if (fileType) { -#if defined(_DIRENT_HAVE_D_TYPE) || defined(__FreeBSD__) || defined(__APPLE__) + if (de != nullptr) { + if (fileType != nullptr) { +#if defined(HAVE_DIRENT_D_TYPE) *fileType = de->d_type; #else #warning "struct dirent.d_type not supported" *fileType = 0; #endif } - if (inode) *inode = de->d_ino; + if (inode != nullptr) { + *inode = de->d_ino; + } return true; - } else { - if (fileType) *fileType = 0; - return false; } + if (fileType != nullptr) { + *fileType = 0; + } + return false; } std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) { - struct dirent *de = 0; + struct dirent *de = nullptr; while (_nextName(de, dir, fileType, inode)) { try { uint64_t localIv = iv; @@ -109,9 +106,9 @@ std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) { } std::string DirTraverse::nextInvalid() { - struct dirent *de = 0; + struct dirent *de = nullptr; // find the first name which produces a decoding error... - while (_nextName(de, dir, (int *)0, (ino_t *)0)) { + while (_nextName(de, dir, (int *)nullptr, (ino_t *)nullptr)) { try { uint64_t localIv = iv; naming->decodePath(de->d_name, &localIv); @@ -143,17 +140,16 @@ class RenameOp { list::const_iterator last; public: - RenameOp(DirNode *_dn, const std::shared_ptr > &_renameList) - : dn(_dn), renameList(_renameList) { + RenameOp(DirNode *_dn, std::shared_ptr > _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::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(), 0, std::shared_ptr()); - } else { - std::shared_ptr dp(dir, DirDeleter()); - - uint64_t iv = 0; - // if we're using chained IV mode, then compute the IV at this - // directory level.. - try { - if (naming->getChainedNameIV()) naming->encodePath(plaintextPath, &iv); - } catch (encfs::Error &err) { - RLOG(ERROR) << "encode err: " << err.what(); - } - return DirTraverse(dp, iv, naming); } + std::shared_ptr dp(dir, DirDeleter()); + + uint64_t iv = 0; + // if we're using chained IV mode, then compute the IV at this + // directory level.. + try { + if (naming->getChainedNameIV()) { + naming->encodePath(plaintextPath, &iv); + } + } catch (encfs::Error &err) { + RLOG(ERROR) << "encode err: " << err.what(); + } + return DirTraverse(dp, iv, naming); } bool DirNode::genRenameList(list &renameList, const char *fromP, @@ -386,16 +383,20 @@ bool DirNode::genRenameList(list &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 = std::shared_ptr(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 &renameList, const char *fromP, ren.newPName = string(toP) + '/' + plainName; bool isDir; -#if defined(_DIRENT_HAVE_D_TYPE) +#if defined(HAVE_DIRENT_D_TYPE) if (de->d_type != DT_UNKNOWN) { isDir = (de->d_type == DT_DIR); } else @@ -477,16 +478,17 @@ bool DirNode::genRenameList(list &renameList, const char *fromP, will have changed.. Returns a list of renamed items on success, a null list on failure. -*/ std::shared_ptr DirNode::newRenameOp(const char *fromP, - const char *toP) { +*/ +std::shared_ptr DirNode::newRenameOp(const char *fromP, + const char *toP) { // Do the rename in two stages to avoid chasing our tail // Undo everything if we encounter an error! std::shared_ptr > renameList(new list); if (!genRenameList(*renameList.get(), fromP, toP)) { RLOG(WARNING) << "Error during generation of recursive rename list"; return std::shared_ptr(); - } else - return std::shared_ptr(new RenameOp(this, renameList)); + } + return std::make_shared(this, renameList); } int DirNode::mkdir(const char *plaintextPath, mode_t mode, uid_t uid, @@ -499,21 +501,30 @@ int DirNode::mkdir(const char *plaintextPath, mode_t mode, uid_t uid, // if uid or gid are set, then that should be the directory owner int olduid = -1; int oldgid = -1; - if (uid != 0) olduid = setfsuid(uid); - if (gid != 0) oldgid = setfsgid(gid); + if (uid != 0) { + olduid = setfsuid(uid); + } + if (gid != 0) { + oldgid = setfsgid(gid); + } int res = ::mkdir(cyName.c_str(), mode); - if (olduid >= 0) setfsuid(olduid); - if (oldgid >= 0) setfsgid(oldgid); + if (olduid >= 0) { + setfsuid(olduid); + } + if (oldgid >= 0) { + setfsgid(oldgid); + } if (res == -1) { int eno = errno; RLOG(WARNING) << "mkdir error on " << cyName << " mode " << mode << ": " << strerror(eno); res = -eno; - } else + } else { res = 0; + } return res; } @@ -536,7 +547,9 @@ int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) { renameOp = newRenameOp(fromPlaintext, toPlaintext); if (!renameOp || !renameOp->apply()) { - if (renameOp) renameOp->undo(); + if (renameOp) { + renameOp->undo(); + } RLOG(WARNING) << "rename aborted"; return -EACCES; @@ -557,7 +570,9 @@ int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) { res = -errno; renameNode(toPlaintext, fromPlaintext, false); - if (renameOp) renameOp->undo(); + if (renameOp) { + renameOp->undo(); + } } else if (preserve_mtime) { struct utimbuf ut; ut.actime = st.st_atime; @@ -593,10 +608,11 @@ int DirNode::link(const char *from, const char *to) { VLOG(1) << "hard links not supported with external IV chaining!"; } else { res = ::link(fromCName.c_str(), toCName.c_str()); - if (res == -1) + if (res == -1) { res = -errno; - else + } else { res = 0; + } } return res; @@ -605,10 +621,12 @@ int DirNode::link(const char *from, const char *to) { /* The node is keyed by filename, so a rename means the internal node names must be changed. -*/ std::shared_ptr DirNode::renameNode(const char *from, - const char *to) { +*/ +std::shared_ptr DirNode::renameNode(const char *from, + const char *to) { return renameNode(from, to, true); } + std::shared_ptr DirNode::renameNode(const char *from, const char *to, bool forwardMode) { std::shared_ptr node = findOrCreate(from); @@ -621,7 +639,9 @@ std::shared_ptr DirNode::renameNode(const char *from, const char *to, << cname; if (node->setName(to, cname.c_str(), newIV, forwardMode)) { - if (ctx) ctx->renameNode(from, to); + if (ctx != nullptr) { + ctx->renameNode(from, to); + } } else { // rename error! - put it back RLOG(ERROR) << "renameNode failed"; @@ -631,18 +651,30 @@ std::shared_ptr 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 DirNode::findOrCreate(const char *plainName) { std::shared_ptr node; - if (ctx) node = ctx->lookupNode(plainName); - if (!node) { - uint64_t iv = 0; - string cipherName = naming->encodePath(plainName, &iv); - node.reset(new FileNode(this, fsConfig, plainName, - (rootDir + cipherName).c_str())); - if (fsConfig->config->externalIVChaining) node->setName(0, 0, iv); + // See if we already have a FileNode for this path. + if (ctx != nullptr) { + node = ctx->lookupNode(plainName); - VLOG(1) << "created FileNode for " << node->cipherName(); + // If we don't, create a new one. + if (!node) { + uint64_t iv = 0; + string cipherName = naming->encodePath(plainName, &iv); + uint64_t fuseFh = ctx->nextFuseFh(); + node.reset(new FileNode(this, fsConfig, plainName, + (rootDir + cipherName).c_str(), fuseFh)); + + if (fsConfig->config->externalIVChaining) { + node->setName(nullptr, nullptr, iv); + } + + VLOG(1) << "created FileNode for " << node->cipherName(); + } } return node; @@ -656,21 +688,23 @@ shared_ptr 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 DirNode::openNode(const char *plainName, - const char *requestor, int flags, - int *result) { + "result" is set to -1 on failure, a value >= 0 on success. +*/ +std::shared_ptr 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 node = findOrCreate(plainName); - if (node && (*result = node->open(flags)) >= 0) + if (node && (*result = node->open(flags)) >= 0) { return node; - else - return std::shared_ptr(); + } + return std::shared_ptr(); } int DirNode::unlink(const char *plaintextName) { @@ -680,7 +714,7 @@ int DirNode::unlink(const char *plaintextName) { Lock _lock(mutex); int res = 0; - if (ctx && ctx->lookupNode(plaintextName)) { + if ((ctx != nullptr) && ctx->lookupNode(plaintextName)) { // If FUSE is running with "hard_remove" option where it doesn't // hide open files for us, then we can't allow an unlink of an open // file.. diff --git a/encfs/DirNode.h b/encfs/DirNode.h index a88082d..027fbea 100644 --- a/encfs/DirNode.h +++ b/encfs/DirNode.h @@ -48,8 +48,8 @@ struct RenameEl; class DirTraverse { public: - DirTraverse(const std::shared_ptr &dirPtr, uint64_t iv, - const std::shared_ptr &naming); + DirTraverse(std::shared_ptr dirPtr, uint64_t iv, + std::shared_ptr naming); DirTraverse(const DirTraverse &src); ~DirTraverse(); diff --git a/encfs/Error.cpp b/encfs/Error.cpp index bbb90ce..7d75dea 100644 --- a/encfs/Error.cpp +++ b/encfs/Error.cpp @@ -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); } diff --git a/encfs/Error.h b/encfs/Error.h index bcedd43..50cabdf 100644 --- a/encfs/Error.h +++ b/encfs/Error.h @@ -3,7 +3,7 @@ // Provides compatibility with RLog's rAssert, which throws an Error exception. -#include "internal/easylogging++.h" +#include "easylogging++.h" #include 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. diff --git a/encfs/FSConfig.h b/encfs/FSConfig.h index 39e2859..26fb0d0 100644 --- a/encfs/FSConfig.h +++ b/encfs/FSConfig.h @@ -130,7 +130,7 @@ struct FSConfig { : forceDecode(false), reverseEncryption(false), idleTracking(false) {} }; -typedef std::shared_ptr FSConfigPtr; +using FSConfigPtr = std::shared_ptr; } // namespace encfs diff --git a/encfs/FileIO.cpp b/encfs/FileIO.cpp index ab9b363..2f653e0 100644 --- a/encfs/FileIO.cpp +++ b/encfs/FileIO.cpp @@ -22,9 +22,9 @@ namespace encfs { -FileIO::FileIO() {} +FileIO::FileIO() = default; -FileIO::~FileIO() {} +FileIO::~FileIO() = default; int FileIO::blockSize() const { return 1; } diff --git a/encfs/FileNode.cpp b/encfs/FileNode.cpp index 02d5c11..c7ad57b 100644 --- a/encfs/FileNode.cpp +++ b/encfs/FileNode.cpp @@ -18,9 +18,9 @@ * along with this program. If not, see . */ -#include +#include +#include #include -#include #include #include #include @@ -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 rawIO(new RawFileIO(_cname)); io = std::shared_ptr(new CipherFileIO(rawIO, fsConfig)); - if (cfg->config->blockMACBytes || cfg->config->blockMACRandBytes) + if ((cfg->config->blockMACBytes != 0) || + (cfg->config->blockMACRandBytes != 0)) { io = std::shared_ptr(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 &io, uint64_t iv) { struct stat stbuf; - if ((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode)) + if ((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode)) { return io->setIV(iv); - else - return true; + } + return true; } bool FileNode::setName(const char *plaintextName_, const char *cipherName_, uint64_t iv, bool setIVFirst) { // Lock _lock( mutex ); - if (cipherName_) VLOG(1) << "calling setIV on " << cipherName_; + if (cipherName_ != nullptr) { + VLOG(1) << "calling setIV on " << cipherName_; + } if (setIVFirst) { - if (fsConfig->config->externalIVChaining && !setIV(io, iv)) return false; + if (fsConfig->config->externalIVChaining && !setIV(io, iv)) { + return false; + } // now change the name.. - if (plaintextName_) this->_pname = plaintextName_; - if (cipherName_) { + if (plaintextName_ != nullptr) { + this->_pname = plaintextName_; + } + if (cipherName_ != nullptr) { this->_cname = cipherName_; io->setFileName(cipherName_); } @@ -115,8 +130,10 @@ bool FileNode::setName(const char *plaintextName_, const char *cipherName_, std::string oldPName = _pname; std::string oldCName = _cname; - if (plaintextName_) this->_pname = plaintextName_; - if (cipherName_) { + if (plaintextName_ != nullptr) { + this->_pname = plaintextName_; + } + if (cipherName_ != nullptr) { this->_cname = cipherName_; io->setFileName(cipherName_); } @@ -161,11 +178,14 @@ int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) { */ if (S_ISREG(mode)) { res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode); - if (res >= 0) res = ::close(res); - } else if (S_ISFIFO(mode)) + if (res >= 0) { + res = ::close(res); + } + } else if (S_ISFIFO(mode)) { res = ::mkfifo(_cname.c_str(), mode); - else + } else { res = ::mknod(_cname.c_str(), mode, rdev); + } if (res == -1) { int eno = errno; @@ -173,8 +193,12 @@ int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) { res = -eno; } - if (olduid >= 0) setfsuid(olduid); - if (oldgid >= 0) setfsgid(oldgid); + if (olduid >= 0) { + setfsuid(olduid); + } + if (oldgid >= 0) { + setfsgid(oldgid); + } return res; } @@ -236,21 +260,24 @@ int FileNode::sync(bool datasync) { int fh = io->open(O_RDONLY); if (fh >= 0) { int res = -EIO; -#ifdef FDATASYNC - if (datasync) +#ifdef HAVE_FDATASYNC + if (datasync) { res = fdatasync(fh); - else + } else { res = fsync(fh); + } #else (void)datasync; res = fsync(fh); #endif - if (res == -1) res = -errno; + if (res == -1) { + res = -errno; + } return res; - } else - return fh; + } + return fh; } } // namespace encfs diff --git a/encfs/FileNode.h b/encfs/FileNode.h index b9fb26b..6279c33 100644 --- a/encfs/FileNode.h +++ b/encfs/FileNode.h @@ -21,6 +21,7 @@ #ifndef _FileNode_incl_ #define _FileNode_incl_ +#include #include #include #include @@ -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 canary; + + // FUSE file handle that is passed to the kernel + uint64_t fuseFh; + const char *plaintextName() const; const char *cipherName() const; diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index edd2b71..3fb0c8c 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -22,9 +22,10 @@ #ifdef linux #define _XOPEN_SOURCE 500 // make sure pwrite() is pulled in #endif -#define _BSD_SOURCE // pick up setenv on RH7.3 +#define _BSD_SOURCE // pick up setenv on RH7.3 +#define _DEFAULT_SOURCE // Replaces _BSD_SOURCE -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include #include @@ -111,54 +112,45 @@ struct ConfigInfo { // backward compatible support for older versions {".encfs5", Config_V5, "ENCFS5_CONFIG", readV5Config, writeV5Config, V5SubVersion, V5SubVersionDefault}, - {".encfs4", Config_V4, NULL, readV4Config, writeV4Config, 0, 0}, + {".encfs4", Config_V4, nullptr, readV4Config, writeV4Config, 0, 0}, // no longer support earlier versions - {".encfs3", Config_V3, NULL, NULL, NULL, 0, 0}, - {".encfs2", Config_Prehistoric, NULL, NULL, NULL, 0, 0}, - {".encfs", Config_Prehistoric, NULL, NULL, NULL, 0, 0}, - {NULL, Config_None, NULL, NULL, NULL, 0, 0}}; + {".encfs3", Config_V3, nullptr, nullptr, nullptr, 0, 0}, + {".encfs2", Config_Prehistoric, nullptr, nullptr, nullptr, 0, 0}, + {".encfs", Config_Prehistoric, nullptr, nullptr, nullptr, 0, 0}, + {nullptr, Config_None, nullptr, nullptr, nullptr, 0, 0}}; -EncFS_Root::EncFS_Root() {} +EncFS_Root::EncFS_Root() = default; -EncFS_Root::~EncFS_Root() {} +EncFS_Root::~EncFS_Root() = default; bool fileExists(const char *fileName) { struct stat buf; - if (!lstat(fileName, &buf)) { - return true; - } else { - // XXX show perror? - return false; - } + return lstat(fileName, &buf) == 0; } bool isDirectory(const char *fileName) { struct stat buf; - if (!lstat(fileName, &buf)) { + if (lstat(fileName, &buf) == 0) { return S_ISDIR(buf.st_mode); - } else { - return false; } + return false; } bool isAbsolutePath(const char *fileName) { - if (fileName && fileName[0] != '\0' && fileName[0] == '/') - return true; - else - return false; + return (fileName != nullptr) && fileName[0] != '\0' && fileName[0] == '/'; } const char *lastPathElement(const char *name) { const char *loc = strrchr(name, '/'); - return loc ? loc + 1 : name; + return loc != nullptr ? loc + 1 : name; } std::string parentDirectory(const std::string &path) { size_t last = path.find_last_of('/'); - if (last == string::npos) + if (last == string::npos) { return string(""); - else - return path.substr(0, last); + } + return path.substr(0, last); } bool userAllowMkdir(const char *path, mode_t mode) { @@ -171,7 +163,7 @@ bool userAllowMkdir(int promptno, const char *path, mode_t mode) { // xgroup(setup) cerr << autosprintf( _("The directory \"%s\" does not exist. Should it be created? " - "(y,n) "), + "(y,N) "), path); char answer[10]; char *res; @@ -188,18 +180,17 @@ bool userAllowMkdir(int promptno, const char *path, mode_t mode) { } res = fgets(answer, sizeof(answer), stdin); - if (res != 0 && toupper(answer[0]) == 'Y') { + if (res != nullptr && toupper(answer[0]) == 'Y') { int result = mkdir(path, mode); if (result < 0) { perror(_("Unable to create directory: ")); return false; - } else - return true; - } else { - // Directory not created, by user request - cerr << _("Directory not created.") << "\n"; - return false; + } + return true; } + // Directory not created, by user request + cerr << _("Directory not created.") << "\n"; + return false; } /** @@ -207,7 +198,7 @@ bool userAllowMkdir(int promptno, const char *path, mode_t mode) { */ ConfigType readConfig_load(ConfigInfo *nm, const char *path, EncFSConfig *config) { - if (nm->loadFunc) { + if (nm->loadFunc != nullptr) { try { if ((*nm->loadFunc)(path, config, nm)) { config->cfgType = nm->type; @@ -233,11 +224,11 @@ ConfigType readConfig_load(ConfigInfo *nm, const char *path, */ ConfigType readConfig(const string &rootDir, EncFSConfig *config) { ConfigInfo *nm = ConfigFileMapping; - while (nm->fileName) { + while (nm->fileName != nullptr) { // allow environment variable to override default config path - if (nm->environmentOverride != NULL) { + if (nm->environmentOverride != nullptr) { char *envFile = getenv(nm->environmentOverride); - if (envFile != NULL) { + if (envFile != nullptr) { if (!fileExists(envFile)) { RLOG(ERROR) << "fatal: config file specified by environment does not exist: " @@ -249,8 +240,9 @@ ConfigType readConfig(const string &rootDir, EncFSConfig *config) { } // the standard place to look is in the root directory string path = rootDir + nm->fileName; - if (fileExists(path.c_str())) + if (fileExists(path.c_str())) { return readConfig_load(nm, path.c_str(), config); + } ++nm; } @@ -323,7 +315,7 @@ bool readV6Config(const char *configFile, EncFSConfig *cfg, ConfigInfo *info) { int encodedSize; config->read("encodedKeySize", &encodedSize); - unsigned char *key = new unsigned char[encodedSize]; + auto *key = new unsigned char[encodedSize]; config->readB64("encodedKeyData", key, encodedSize); cfg->assignKeyData(key, encodedSize); delete[] key; @@ -331,7 +323,7 @@ bool readV6Config(const char *configFile, EncFSConfig *cfg, ConfigInfo *info) { if (cfg->subVersion >= 20080816) { int saltLen; config->read("saltLen", &saltLen); - unsigned char *salt = new unsigned char[saltLen]; + auto *salt = new unsigned char[saltLen]; config->readB64("saltData", salt, saltLen); cfg->assignSaltData(salt, saltLen); delete[] salt; @@ -445,13 +437,15 @@ bool saveConfig(ConfigType type, const string &rootDir, bool ok = false; ConfigInfo *nm = ConfigFileMapping; - while (nm->fileName) { - if (nm->type == type && nm->saveFunc) { + while (nm->fileName != nullptr) { + if (nm->type == type && (nm->saveFunc != nullptr)) { string path = rootDir + nm->fileName; - if (nm->environmentOverride != NULL) { + if (nm->environmentOverride != nullptr) { // use environment file if specified.. const char *envFile = getenv(nm->environmentOverride); - if (envFile != NULL) path.assign(envFile); + if (envFile != nullptr) { + path.assign(envFile); + } } try { @@ -536,12 +530,12 @@ bool writeV6Config(const char *configFile, const EncFSConfig *cfg) { addEl(doc, config, "nameAlg", cfg->nameIface); addEl(doc, config, "keySize", cfg->keySize); addEl(doc, config, "blockSize", cfg->blockSize); - addEl(doc, config, "uniqueIV", cfg->uniqueIV); - addEl(doc, config, "chainedNameIV", cfg->chainedNameIV); - addEl(doc, config, "externalIVChaining", cfg->externalIVChaining); + addEl(doc, config, "uniqueIV", (int)cfg->uniqueIV); + addEl(doc, config, "chainedNameIV", (int)cfg->chainedNameIV); + addEl(doc, config, "externalIVChaining", (int)cfg->externalIVChaining); addEl(doc, config, "blockMACBytes", cfg->blockMACBytes); addEl(doc, config, "blockMACRandBytes", cfg->blockMACRandBytes); - addEl(doc, config, "allowHoles", cfg->allowHoles); + addEl(doc, config, "allowHoles", (int)cfg->allowHoles); addEl(doc, config, "encodedKeySize", (int)cfg->keyData.size()); addEl(doc, config, "encodedKeyData", cfg->keyData); addEl(doc, config, "saltLen", (int)cfg->salt.size()); @@ -592,7 +586,8 @@ static Cipher::CipherAlgorithm findCipherAlgorithm(const char *name, Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); Cipher::AlgorithmList::const_iterator it; for (it = algorithms.begin(); it != algorithms.end(); ++it) { - if (!strcmp(name, it->name.c_str()) && it->keyLength.allowed(keySize)) { + if ((strcmp(name, it->name.c_str()) == 0) && + it->keyLength.allowed(keySize)) { return *it; } } @@ -649,7 +644,7 @@ static Cipher::CipherAlgorithm selectCipherAlgorithm() { cout << "\n" << _("Enter the number corresponding to your choice: "); char answer[10]; char *res = fgets(answer, sizeof(answer), stdin); - int cipherNum = (res == 0 ? 0 : atoi(answer)); + int cipherNum = (res == nullptr ? 0 : atoi(answer)); cout << "\n"; if (cipherNum < 1 || cipherNum > (int)algorithms.size()) { @@ -658,8 +653,9 @@ static Cipher::CipherAlgorithm selectCipherAlgorithm() { } it = algorithms.begin(); - while (--cipherNum) // numbering starts at 1 + while (--cipherNum != 0) { // numbering starts at 1 ++it; + } Cipher::CipherAlgorithm alg = *it; @@ -692,7 +688,7 @@ static Interface selectNameCoding() { cout << "\n" << _("Enter the number corresponding to your choice: "); char answer[10]; char *res = fgets(answer, sizeof(answer), stdin); - int algNum = (res == 0 ? 0 : atoi(answer)); + int algNum = (res == nullptr ? 0 : atoi(answer)); cout << "\n"; if (algNum < 1 || algNum > (int)algorithms.size()) { @@ -701,8 +697,9 @@ static Interface selectNameCoding() { } it = algorithms.begin(); - while (--algNum) // numbering starts at 1 + while (--algNum != 0) { // numbering starts at 1 ++it; + } // xgroup(setup) cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str()) @@ -737,13 +734,17 @@ static int selectKeySize(const Cipher::CipherAlgorithm &alg) { if (numAvail < 5) { // show them all for (int i = 0; i <= numAvail; ++i) { - if (i) cout << ", "; + if (i != 0) { + cout << ", "; + } cout << alg.keyLength.min() + i * alg.keyLength.inc(); } } else { // partial for (int i = 0; i < 3; ++i) { - if (i) cout << ", "; + if (i != 0) { + cout << ", "; + } cout << alg.keyLength.min() + i * alg.keyLength.inc(); } cout << " ... " << alg.keyLength.max() - alg.keyLength.inc(); @@ -754,7 +755,7 @@ static int selectKeySize(const Cipher::CipherAlgorithm &alg) { char answer[10]; char *res = fgets(answer, sizeof(answer), stdin); - int keySize = (res == 0 ? 0 : atoi(answer)); + int keySize = (res == nullptr ? 0 : atoi(answer)); cout << "\n"; keySize = alg.keyLength.closest(keySize); @@ -794,7 +795,9 @@ static int selectBlockSize(const Cipher::CipherAlgorithm &alg) { char *res = fgets(answer, sizeof(answer), stdin); cout << "\n"; - if (res != 0 && atoi(answer) >= alg.blockSize.min()) blockSize = atoi(answer); + if (res != nullptr && atoi(answer) >= alg.blockSize.min()) { + blockSize = atoi(answer); + } blockSize = alg.blockSize.closest(blockSize); @@ -816,10 +819,11 @@ static bool boolDefault(const char *prompt, bool defaultValue) { string yesno; - if (defaultValue == true) + if (defaultValue) { yesno = "[y]/n: "; - else + } else { yesno = "y/[n]: "; + } string response; bool value; @@ -831,10 +835,12 @@ static bool boolDefault(const char *prompt, bool defaultValue) { if (cin.fail() || response == "") { value = defaultValue; break; - } else if (response == "y") { + } + if (response == "y") { value = true; break; - } else if (response == "n") { + } + if (response == "n") { value = false; break; } @@ -873,10 +879,11 @@ static void selectBlockMAC(int *macBytes, int *macRandBytes, bool forceMac) { addMAC = true; } - if (addMAC) + if (addMAC) { *macBytes = 8; - else + } else { *macBytes = 0; + } // xgroup(setup) cout << _( @@ -893,9 +900,13 @@ static void selectBlockMAC(int *macBytes, int *macRandBytes, bool forceMac) { char *res = fgets(answer, sizeof(answer), stdin); cout << "\n"; - randSize = (res == 0 ? 0 : atoi(answer)); - if (randSize < 0) randSize = 0; - if (randSize > 8) randSize = 8; + randSize = (res == nullptr ? 0 : atoi(answer)); + if (randSize < 0) { + randSize = 0; + } + if (randSize > 8) { + randSize = 8; + } *macRandBytes = randSize; } @@ -956,9 +967,7 @@ RootPtr createV6Config(EncFS_Context *ctx, const std::string passwordProgram = opts->passwordProgram; bool useStdin = opts->useStdin; bool reverseEncryption = opts->reverseEncryption; - ConfigMode configMode = (useStdin && - opts->configMode == Config_Prompt) ? Config_Standard - : opts->configMode; + ConfigMode configMode = opts->configMode; bool annotate = opts->annotate; RootPtr rootInfo; @@ -978,7 +987,9 @@ RootPtr createV6Config(EncFS_Context *ctx, " anything else, or an empty line will select standard mode.\n" "?> "); - if (annotate) cerr << "$PROMPT$ config_option" << endl; + if (annotate) { + cerr << "$PROMPT$ config_option" << endl; + } char *res = fgets(answer, sizeof(answer), stdin); (void)res; @@ -1024,7 +1035,7 @@ RootPtr createV6Config(EncFS_Context *ctx, alg = findCipherAlgorithm("AES", keySize); // If case-insensitive system, opt for Block32 filename encoding -#if defined(__APPLE__) || defined(WIN32) +#if DEFAULT_CASE_INSENSITIVE nameIOIface = BlockNameIO::CurrentInterface(true); #else nameIOIface = BlockNameIO::CurrentInterface(); @@ -1053,6 +1064,14 @@ RootPtr createV6Config(EncFS_Context *ctx, if (opts->requireMac) { blockMACBytes = 8; } + if (reverseEncryption) { + /* Reverse mounts are read-only by default (set in main.cpp). + * If uniqueIV is off, writing can be allowed, because there + * is no header that could be overwritten */ + if (!uniqueIV) { + opts->readOnly = false; + } + } } if (answer[0] == 'x' || alg.name.empty()) { @@ -1079,13 +1098,15 @@ RootPtr createV6Config(EncFS_Context *ctx, /* Reverse mounts are read-only by default (set in main.cpp). * If uniqueIV is off, writing can be allowed, because there * is no header that could be overwritten */ - if (uniqueIV == false) opts->readOnly = false; + if (!uniqueIV) { + opts->readOnly = false; + } } else { chainedIV = selectChainedIV(); uniqueIV = selectUniqueIV(true); - if (chainedIV && uniqueIV) + if (chainedIV && uniqueIV) { externalIV = selectExternalChainedIV(); - else { + } else { // xgroup(setup) cout << _("External chained IV disabled, as both 'IV chaining'\n" "and 'unique IV' features are required for this option.") @@ -1103,10 +1124,9 @@ RootPtr createV6Config(EncFS_Context *ctx, _("Unable to instanciate cipher %s, key size %i, block size %i"), alg.name.c_str(), keySize, blockSize); return rootInfo; - } else { - VLOG(1) << "Using cipher " << alg.name << ", key size " << keySize - << ", block size " << blockSize; } + VLOG(1) << "Using cipher " << alg.name << ", key size " << keySize + << ", block size " << blockSize; std::shared_ptr 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(); rootInfo->cipher = cipher; rootInfo->volumeKey = volumeKey; - rootInfo->root = - std::shared_ptr(new DirNode(ctx, rootDir, fsConfig)); + rootInfo->root = std::make_shared(ctx, rootDir, fsConfig); return rootInfo; } @@ -1232,17 +1251,18 @@ void showFSInfo(const EncFSConfig *config) { config->cipherIface.name().c_str(), config->cipherIface.current(), config->cipherIface.revision(), config->cipherIface.age()); // check if we support this interface.. - if (!cipher) + if (!cipher) { cout << _(" (NOT supported)\n"); - else { + } else { // if we're using a newer interface, show the version number if (config->cipherIface != cipher->interface()) { Interface iface = cipher->interface(); // xgroup(diag) cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.current(), iface.revision(), iface.age()); - } else + } else { cout << "\n"; + } } } { @@ -1264,8 +1284,9 @@ void showFSInfo(const EncFSConfig *config) { Interface iface = nameCoder->interface(); cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.current(), iface.revision(), iface.age()); - } else + } else { cout << "\n"; + } } } { @@ -1274,17 +1295,18 @@ void showFSInfo(const EncFSConfig *config) { if (!cipher) { // xgroup(diag) cout << _(" (NOT supported)\n"); - } else + } else { cout << "\n"; + } } - if (config->kdfIterations > 0 && config->salt.size() > 0) { + if (config->kdfIterations > 0 && !config->salt.empty()) { cout << autosprintf(_("Using PBKDF2, with %i iterations"), config->kdfIterations) << "\n"; cout << autosprintf(_("Salt Size: %i bits"), (int)(8 * config->salt.size())) << "\n"; } - if (config->blockMACBytes || config->blockMACRandBytes) { + if ((config->blockMACBytes != 0) || (config->blockMACRandBytes != 0)) { if (config->subVersion < 20040813) { cout << autosprintf( // xgroup(diag) @@ -1353,14 +1375,19 @@ CipherKey EncFSConfig::makeKey(const char *password, int passwdLen) { CipherKey userKey; std::shared_ptr cipher = 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 &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 &opts) { } if (opts->delayMount) { - rootInfo = RootPtr(new EncFS_Root); + rootInfo = std::make_shared(); rootInfo->cipher = cipher; rootInfo->root = std::shared_ptr(); return rootInfo; @@ -1578,12 +1613,17 @@ RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr &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 &opts) { fsConfig->reverseEncryption = opts->reverseEncryption; fsConfig->opts = opts; - rootInfo = RootPtr(new EncFS_Root); + rootInfo = std::make_shared(); rootInfo->cipher = cipher; rootInfo->volumeKey = volumeKey; - rootInfo->root = - std::shared_ptr(new DirNode(ctx, opts->rootDir, fsConfig)); + rootInfo->root = std::make_shared(ctx, opts->rootDir, fsConfig); } else { if (opts->createIfNotFound) { // creating a new encrypted filesystem @@ -1645,10 +1684,9 @@ int remountFS(EncFS_Context *ctx) { if (rootInfo) { ctx->setRoot(rootInfo->root); return 0; - } else { - RLOG(WARNING) << "Remount failed"; - return -EACCES; } + RLOG(WARNING) << "Remount failed"; + return -EACCES; } } // namespace encfs diff --git a/encfs/FileUtils.h b/encfs/FileUtils.h index 7efbbf0..3e42092 100644 --- a/encfs/FileUtils.h +++ b/encfs/FileUtils.h @@ -60,7 +60,7 @@ struct EncFS_Root { ~EncFS_Root(); }; -typedef std::shared_ptr RootPtr; +using RootPtr = std::shared_ptr; enum ConfigMode { Config_Prompt, Config_Standard, Config_Paranoia }; diff --git a/encfs/Interface.cpp b/encfs/Interface.cpp index 8cd8def..86111ab 100644 --- a/encfs/Interface.cpp +++ b/encfs/Interface.cpp @@ -20,6 +20,8 @@ #include "Interface.h" +#include + #include "ConfigVar.h" #include "Error.h" @@ -28,25 +30,19 @@ namespace encfs { Interface::Interface(const char *name_, int Current, int Revision, int Age) : _name(name_), _current(Current), _revision(Revision), _age(Age) {} -Interface::Interface(const std::string &name_, int Current, int Revision, - int Age) - : _name(name_), _current(Current), _revision(Revision), _age(Age) {} +Interface::Interface(std::string name_, int Current, int Revision, int Age) + : _name(std::move(name_)), + _current(Current), + _revision(Revision), + _age(Age) {} Interface::Interface(const Interface &src) - : _name(src._name), - _current(src._current), - _revision(src._revision), - _age(src._age) {} + + = default; Interface::Interface() : _current(0), _revision(0), _age(0) {} -Interface &Interface::operator=(const Interface &src) { - _name = src._name; - _current = src._current; - _revision = src._revision; - _age = src._age; - return *this; -} +Interface &Interface::operator=(const Interface &src) = default; const std::string &Interface::name() const { return _name; } @@ -87,12 +83,13 @@ static int sign( int a, int b ) #else // simple, easy to check, unlikely to break due to unforseen events.. static int sign(int a, int b) { - if (a < b) + if (a < b) { return 0; - else if (a == b) + } + if (a == b) { return 1; - else - return 2; + } + return 2; } #endif @@ -111,7 +108,9 @@ bool Interface::implements(const Interface &B) const { << ":" << age() << ") implements " << B.name() << "(" << B.current() << ":" << B.revision() << ")"; - if (name() != B.name()) return false; + if (name() != B.name()) { + return false; + } int currentDiff = current() - B.current(); return (currentDiff >= 0 && currentDiff <= age()); @@ -120,29 +119,29 @@ bool Interface::implements(const Interface &B) const { bool operator<(const Interface &A, const Interface &B) { if (A.name() == B.name()) { return (diffSum(A, B) < EqualVersion); - } else - return A.name() < B.name(); + } + return A.name() < B.name(); } bool operator>(const Interface &A, const Interface &B) { if (A.name() == B.name()) { return (diffSum(A, B) > EqualVersion); - } else - return A.name() < B.name(); + } + return A.name() < B.name(); } bool operator<=(const Interface &A, const Interface &B) { if (A.name() == B.name()) { return (diffSum(A, B) <= EqualVersion); - } else - return A.name() < B.name(); + } + return A.name() < B.name(); } bool operator>=(const Interface &A, const Interface &B) { if (A.name() == B.name()) { return (diffSum(A, B) >= EqualVersion); - } else - return A.name() < B.name(); + } + return A.name() < B.name(); } ConfigVar &operator<<(ConfigVar &dst, const Interface &iface) { diff --git a/encfs/Interface.h b/encfs/Interface.h index 2ec101a..d1cffba 100644 --- a/encfs/Interface.h +++ b/encfs/Interface.h @@ -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(); diff --git a/encfs/MACFileIO.cpp b/encfs/MACFileIO.cpp index 9a17c7b..df7a753 100644 --- a/encfs/MACFileIO.cpp +++ b/encfs/MACFileIO.cpp @@ -20,10 +20,11 @@ #include "MACFileIO.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" +#include #include -#include #include +#include #include "BlockFileIO.h" #include "Cipher.h" @@ -56,10 +57,9 @@ int dataBlockSize(const FSConfigPtr &cfg) { cfg->config->blockMACRandBytes; } -MACFileIO::MACFileIO(const std::shared_ptr &_base, - const FSConfigPtr &cfg) +MACFileIO::MACFileIO(std::shared_ptr _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 &_base, << ", randBytes = " << cfg->config->blockMACRandBytes; } -MACFileIO::~MACFileIO() {} +MACFileIO::~MACFileIO() = default; Interface MACFileIO::interface() const { return MACFileIO_iface; } @@ -137,7 +137,9 @@ off_t MACFileIO::getSize() const { int bs = blockSize() + headerSize; off_t size = base->getSize(); - if (size > 0) size = locWithoutHeader(size, bs, headerSize); + if (size > 0) { + size = locWithoutHeader(size, bs, headerSize); + } return size; } @@ -160,13 +162,15 @@ ssize_t MACFileIO::readOneBlock(const IORequest &req) const { // don't store zeros if configured for zero-block pass-through bool skipBlock = true; if (_allowHoles) { - for (int i = 0; i < readSize; ++i) + for (int i = 0; i < readSize; ++i) { if (tmp.data[i] != 0) { skipBlock = false; break; } - } else if (macBytes > 0) + } + } else if (macBytes > 0) { skipBlock = false; + } if (readSize > headerSize) { if (!skipBlock) { @@ -200,7 +204,9 @@ ssize_t MACFileIO::readOneBlock(const IORequest &req) const { memcpy(req.data, tmp.data + headerSize, readSize); } else { VLOG(1) << "readSize " << readSize << " at offset " << req.offset; - if (readSize > 0) readSize = 0; + if (readSize > 0) { + readSize = 0; + } } MemoryPool::release(mb); @@ -224,8 +230,9 @@ int MACFileIO::writeOneBlock(const IORequest &req) { memset(newReq.data, 0, headerSize); memcpy(newReq.data + headerSize, req.data, req.dataLen); if (randBytes > 0) { - if (!cipher->randomize(newReq.data + macBytes, randBytes, false)) + if (!cipher->randomize(newReq.data + macBytes, randBytes, false)) { return -EBADMSG; + } } if (macBytes > 0) { @@ -251,9 +258,11 @@ int MACFileIO::truncate(off_t size) { int headerSize = macBytes + randBytes; int bs = blockSize() + headerSize; - int res = BlockFileIO::truncateBase(size, 0); + int res = BlockFileIO::truncateBase(size, nullptr); - if (!(res < 0)) res = base->truncate(locWithHeader(size, bs, headerSize)); + if (!(res < 0)) { + res = base->truncate(locWithHeader(size, bs, headerSize)); + } return res; } diff --git a/encfs/MACFileIO.h b/encfs/MACFileIO.h index 07f41b6..eb80013 100644 --- a/encfs/MACFileIO.h +++ b/encfs/MACFileIO.h @@ -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 &base, const FSConfigPtr &cfg); + MACFileIO(std::shared_ptr base, const FSConfigPtr &cfg); MACFileIO(); virtual ~MACFileIO(); diff --git a/encfs/MemoryPool.cpp b/encfs/MemoryPool.cpp index 532ac8c..ff28056 100644 --- a/encfs/MemoryPool.cpp +++ b/encfs/MemoryPool.cpp @@ -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); diff --git a/encfs/NameIO.cpp b/encfs/NameIO.cpp index 6495586..99c563c 100644 --- a/encfs/NameIO.cpp +++ b/encfs/NameIO.cpp @@ -20,7 +20,7 @@ #include "NameIO.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #include // 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 NameIOMap_t; -static NameIOMap_t *gNameIOMap = 0; +using NameIOMap_t = multimap; +static NameIOMap_t *gNameIOMap = nullptr; list NameIO::GetAlgorithmList(bool includeHidden) { AddSymbolReferences(); list 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::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::New(const string &name, const std::shared_ptr &cipher, const CipherKey &key) { std::shared_ptr 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::New(const Interface &iface, const std::shared_ptr &cipher, const CipherKey &key) { std::shared_ptr 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::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'); diff --git a/encfs/NameIO.h b/encfs/NameIO.h index 2264a64..3129dc5 100644 --- a/encfs/NameIO.h +++ b/encfs/NameIO.h @@ -37,7 +37,7 @@ class Cipher; class NameIO { public: - typedef std::shared_ptr (*Constructor)( + using Constructor = std::shared_ptr (*)( const Interface &iface, const std::shared_ptr &cipher, const CipherKey &key); @@ -47,7 +47,7 @@ class NameIO { Interface iface; }; - typedef std::list AlgorithmList; + using AlgorithmList = std::list; static AlgorithmList GetAlgorithmList(bool includeHidden = false); static std::shared_ptr New(const Interface &iface, @@ -139,7 +139,7 @@ class NameIO { delete[] Name; \ Name = Name##_Raw; \ } \ - } while (0); + } while (false); } // namespace encfs diff --git a/encfs/NullCipher.cpp b/encfs/NullCipher.cpp index 4c787d6..4e916ca 100644 --- a/encfs/NullCipher.cpp +++ b/encfs/NullCipher.cpp @@ -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 gNullKey(new NullKey(), NullDestructor()); NullCipher::NullCipher(const Interface &iface_) { this->iface = iface_; } -NullCipher::~NullCipher() {} +NullCipher::~NullCipher() = default; Interface NullCipher::interface() const { return iface; } diff --git a/encfs/NullNameIO.cpp b/encfs/NullNameIO.cpp index a2f6e34..26b0251 100644 --- a/encfs/NullNameIO.cpp +++ b/encfs/NullNameIO.cpp @@ -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; } diff --git a/encfs/RawFileIO.cpp b/encfs/RawFileIO.cpp index 231970d..6c27299 100644 --- a/encfs/RawFileIO.cpp +++ b/encfs/RawFileIO.cpp @@ -21,13 +21,14 @@ #ifdef linux #define _XOPEN_SOURCE 500 // pick up pread , pwrite #endif -#include "internal/easylogging++.h" +#include "easylogging++.h" #include +#include #include #include -#include #include #include +#include #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(this)->fileSize = stbuf.st_size; const_cast(this)->knownSize = true; return fileSize; - } else { - int eno = errno; - RLOG(ERROR) << "getSize on " << name << " failed: " << strerror(eno); - return -eno; } - } else { - return fileSize; + int eno = errno; + RLOG(ERROR) << "getSize on " << name << " failed: " << strerror(eno); + return -eno; } + return fileSize; } ssize_t RawFileIO::read(const IORequest &req) const { @@ -209,7 +214,7 @@ ssize_t RawFileIO::read(const IORequest &req) const { int RawFileIO::write(const IORequest &req) { rAssert(fd >= 0); - rAssert(true == canWrite); + rAssert(canWrite); int retrys = 10; void *buf = req.data; @@ -217,7 +222,7 @@ int RawFileIO::write(const IORequest &req) { off_t offset = req.offset; int eno = 0; - while (bytes && retrys > 0) { + while ((bytes != 0) && retrys > 0) { errno = 0; ssize_t writeSize = ::pwrite(fd, buf, bytes, offset); eno = errno; @@ -243,11 +248,15 @@ int RawFileIO::write(const IORequest &req) { } else { if (knownSize) { off_t last = req.offset + req.dataLen; - if (last > fileSize) fileSize = last; + if (last > fileSize) { + fileSize = last; + } } return 0; //No matter how many bytes we wrote, we of course already know this. } + + return true; } int RawFileIO::truncate(off_t size) { @@ -255,8 +264,9 @@ int RawFileIO::truncate(off_t size) { if (fd >= 0 && canWrite) { res = ::ftruncate(fd, size); - } else + } else { res = ::truncate(name.c_str(), size); + } if (res < 0) { int eno = errno; @@ -271,10 +281,10 @@ int RawFileIO::truncate(off_t size) { } if (fd >= 0 && canWrite) { -#ifdef FDATASYNC +#if defined(HAVE_FDATASYNC) ::fdatasync(fd); #else - ::fsync(fd); + ::fsync(fd); #endif } diff --git a/encfs/RawFileIO.h b/encfs/RawFileIO.h index 9539b01..be69313 100644 --- a/encfs/RawFileIO.h +++ b/encfs/RawFileIO.h @@ -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; diff --git a/encfs/SSL_Cipher.cpp b/encfs/SSL_Cipher.cpp index d5af102..fd2061e 100644 --- a/encfs/SSL_Cipher.cpp +++ b/encfs/SSL_Cipher.cpp @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include #include @@ -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(salt), saltlen, iter, keylen, out); - if (res != 1) return -1; + if (res != 1) { + return -1; + } - gettimeofday(&end, 0); + gettimeofday(&end, nullptr); long delta = time_diff(end, start); if (delta < desiredPDFTime / 8) { @@ -139,8 +146,9 @@ int TimedPBKDF2(const char *pass, int passlen, const unsigned char *salt, } else if (delta < (5 * desiredPDFTime / 6)) { // estimate number of iterations to get close to desired time iter = (int)((double)iter * (double)desiredPDFTime / (double)delta); - } else + } else { return iter; + } } } @@ -153,6 +161,47 @@ int TimedPBKDF2(const char *pass, int passlen, const unsigned char *salt, // - Version 3:0 adds a new IV mechanism static Interface BlowfishInterface("ssl/blowfish", 3, 0, 2); static Interface AESInterface("ssl/aes", 3, 0, 2); +static Interface CAMELLIAInterface("ssl/camellia",3, 0, 2); + +#ifndef OPENSSL_NO_CAMELLIA + +static Range CAMELLIAKeyRange(128, 256, 64); +static Range CAMELLIABlockRange(64, 4096, 16); + +static std::shared_ptr 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(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 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 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 &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 &key, const EVP_CIPHER *_blockCipher, EVP_CIPHER_CTX_set_padding(key->stream_enc, 0); EVP_CIPHER_CTX_set_padding(key->stream_dec, 0); - EVP_EncryptInit_ex(key->block_enc, NULL, NULL, KeyData(key), NULL); - EVP_DecryptInit_ex(key->block_dec, NULL, NULL, KeyData(key), NULL); - EVP_EncryptInit_ex(key->stream_enc, NULL, NULL, KeyData(key), NULL); - EVP_DecryptInit_ex(key->stream_dec, NULL, NULL, KeyData(key), NULL); + EVP_EncryptInit_ex(key->block_enc, nullptr, nullptr, KeyData(key), nullptr); + EVP_DecryptInit_ex(key->block_dec, nullptr, nullptr, KeyData(key), nullptr); + EVP_EncryptInit_ex(key->stream_enc, nullptr, nullptr, KeyData(key), nullptr); + EVP_DecryptInit_ex(key->stream_dec, nullptr, nullptr, KeyData(key), nullptr); - HMAC_Init_ex(key->mac_ctx, KeyData(key), _keySize, EVP_sha1(), 0); + HMAC_Init_ex(key->mac_ctx, KeyData(key), _keySize, EVP_sha1(), nullptr); } SSL_Cipher::SSL_Cipher(const Interface &iface_, const Interface &realIface_, @@ -342,7 +395,7 @@ SSL_Cipher::SSL_Cipher(const Interface &iface_, const Interface &realIface_, } } -SSL_Cipher::~SSL_Cipher() {} +SSL_Cipher::~SSL_Cipher() = default; Interface SSL_Cipher::interface() const { return realIface; } @@ -366,8 +419,9 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength, if (res <= 0) { RLOG(WARNING) << "openssl error, PBKDF2 failed"; return CipherKey(); - } else - iterationCount = res; + } + iterationCount = res; + } else { // known iteration length if (PKCS5_PBKDF2_HMAC_SHA1( @@ -401,9 +455,8 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) { } } else { // for backward compatibility with filesystems created with 1:0 - bytes = EVP_BytesToKey(_blockCipher, EVP_sha1(), NULL, - (unsigned char *)password, passwdLength, 16, - KeyData(key), IVData(key)); + EVP_BytesToKey(_blockCipher, EVP_sha1(), nullptr, (unsigned char *)password, + passwdLength, 16, KeyData(key), IVData(key)); } initKey(key, _blockCipher, _streamCipher, _keySize); @@ -425,8 +478,9 @@ CipherKey SSL_Cipher::newRandomKey() { int saltLen = 20; unsigned char saltBuf[saltLen]; - if (!randomize(tmpBuf, bufLen, true) || !randomize(saltBuf, saltLen, true)) + if (!randomize(tmpBuf, bufLen, true) || !randomize(saltBuf, saltLen, true)) { return CipherKey(); + } std::shared_ptr 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 mk = dynamic_pointer_cast(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; diff --git a/encfs/SSL_Cipher.h b/encfs/SSL_Cipher.h index f9613ff..007ed2e 100644 --- a/encfs/SSL_Cipher.h +++ b/encfs/SSL_Cipher.h @@ -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 { diff --git a/encfs/SSL_Compat.h b/encfs/SSL_Compat.h index f7b1629..276bf26 100644 --- a/encfs/SSL_Compat.h +++ b/encfs/SSL_Compat.h @@ -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); diff --git a/encfs/StreamNameIO.cpp b/encfs/StreamNameIO.cpp index e07c4e5..5b6a6c5 100644 --- a/encfs/StreamNameIO.cpp +++ b/encfs/StreamNameIO.cpp @@ -20,8 +20,9 @@ #include "StreamNameIO.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #include +#include #include "Cipher.h" #include "CipherKey.h" @@ -72,11 +73,12 @@ Interface StreamNameIO::CurrentInterface() { } StreamNameIO::StreamNameIO(const Interface &iface, - const std::shared_ptr &cipher, - const CipherKey &key) - : _interface(iface.current()), _cipher(cipher), _key(key) {} + std::shared_ptr 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 { diff --git a/encfs/StreamNameIO.h b/encfs/StreamNameIO.h index 5bb3134..43a417e 100644 --- a/encfs/StreamNameIO.h +++ b/encfs/StreamNameIO.h @@ -36,8 +36,8 @@ class StreamNameIO : public NameIO { public: static Interface CurrentInterface(); - StreamNameIO(const Interface &iface, const std::shared_ptr &cipher, - const CipherKey &key); + StreamNameIO(const Interface &iface, std::shared_ptr cipher, + CipherKey key); virtual ~StreamNameIO(); virtual Interface interface() const; diff --git a/encfs/XmlReader.cpp b/encfs/XmlReader.cpp index c0aaf9b..1e4cd20 100644 --- a/encfs/XmlReader.cpp +++ b/encfs/XmlReader.cpp @@ -22,7 +22,9 @@ #include // for remove_if #include // for NULL +#include // for ifstream #include // for shared_ptr +#include // for ostringstream #include // for XMLElement, XMLNode, XMLDocument (ptr only) @@ -32,7 +34,7 @@ namespace encfs { -XmlValue::~XmlValue() {} +XmlValue::~XmlValue() = default; XmlValuePtr XmlValue::operator[](const char *path) const { return find(path); } @@ -44,7 +46,9 @@ XmlValuePtr XmlValue::find(const char *path) const { bool XmlValue::read(const char *path, std::string *out) const { XmlValuePtr value = find(path); - if (!value) return false; + if (!value) { + return false; + } *out = value->text(); return true; @@ -52,7 +56,9 @@ bool XmlValue::read(const char *path, std::string *out) const { bool XmlValue::read(const char *path, int *out) const { XmlValuePtr value = find(path); - if (!value) return false; + if (!value) { + return false; + } *out = atoi(value->text().c_str()); return true; @@ -60,7 +66,9 @@ bool XmlValue::read(const char *path, int *out) const { bool XmlValue::read(const char *path, long *out) const { XmlValuePtr value = find(path); - if (!value) return false; + if (!value) { + return false; + } *out = atol(value->text().c_str()); return true; @@ -68,7 +76,9 @@ bool XmlValue::read(const char *path, long *out) const { bool XmlValue::read(const char *path, double *out) const { XmlValuePtr value = find(path); - if (!value) return false; + if (!value) { + return false; + } *out = atof(value->text().c_str()); return true; @@ -76,16 +86,20 @@ bool XmlValue::read(const char *path, double *out) const { bool XmlValue::read(const char *path, bool *out) const { XmlValuePtr value = find(path); - if (!value) return false; + if (!value) { + return false; + } - *out = atoi(value->text().c_str()); + *out = (atoi(value->text().c_str()) != 0); return true; } bool XmlValue::readB64(const char *path, unsigned char *data, int length) const { XmlValuePtr value = find(path); - if (!value) return false; + if (!value) { + return false; + } std::string s = value->text(); s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end()); @@ -99,7 +113,7 @@ bool XmlValue::readB64(const char *path, unsigned char *data, return false; } if (!B64StandardDecode(data, (unsigned char *)s.data(), s.size())) { - RLOG(ERROR) << "B64 decode failure on \"" << s << "\""; + RLOG(ERROR) << R"(B64 decode failure on ")" << s << R"(")"; return false; } @@ -108,7 +122,9 @@ bool XmlValue::readB64(const char *path, unsigned char *data, bool XmlValue::read(const char *path, Interface *out) const { XmlValuePtr node = find(path); - if (!node) return false; + if (!node) { + return false; + } bool ok = node->read("name", &out->name()) && node->read("major", &out->current()) && @@ -119,12 +135,16 @@ bool XmlValue::read(const char *path, Interface *out) const { std::string safeValueForNode(const tinyxml2::XMLElement *element) { std::string value; - if (element == NULL) return value; + if (element == nullptr) { + return value; + } const tinyxml2::XMLNode *child = element->FirstChild(); - if (child) { + if (child != nullptr) { const tinyxml2::XMLText *childText = child->ToText(); - if (childText) value = childText->Value(); + if (childText != nullptr) { + value = childText->Value(); + } } return value; @@ -137,22 +157,21 @@ class XmlNode : virtual public XmlValue { XmlNode(const tinyxml2::XMLElement *element_) : XmlValue(safeValueForNode(element_)), element(element_) {} - virtual ~XmlNode() {} + ~XmlNode() override = default; - virtual XmlValuePtr find(const char *name) const { + XmlValuePtr find(const char *name) const override { if (name[0] == '@') { const char *value = element->Attribute(name + 1); - if (value) - return XmlValuePtr(new XmlValue(value)); - else - return XmlValuePtr(); - } else { - const tinyxml2::XMLElement *el = element->FirstChildElement(name); - if (el) - return XmlValuePtr(new XmlNode(el)); - else - return XmlValuePtr(); + if (value != nullptr) { + return std::make_shared(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(); } 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(); } return XmlValuePtr(new XmlNode(element)); diff --git a/encfs/XmlReader.h b/encfs/XmlReader.h index 4a56b16..cf1d3e4 100644 --- a/encfs/XmlReader.h +++ b/encfs/XmlReader.h @@ -29,7 +29,7 @@ namespace encfs { class XmlValue; -typedef std::shared_ptr XmlValuePtr; +using XmlValuePtr = std::shared_ptr; class XmlValue { std::string value; diff --git a/encfs/autosprintf.cpp b/encfs/autosprintf.cpp index c32aa8f..26a27a8 100644 --- a/encfs/autosprintf.cpp +++ b/encfs/autosprintf.cpp @@ -27,10 +27,10 @@ /* Specification. */ #include "autosprintf.h" -#include // for va_list -#include // for NULL, vasprintf -#include // for free -#include // for strdup +#include // for va_list +#include // for NULL, vasprintf +#include // for free +#include // 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 diff --git a/encfs/base64.cpp b/encfs/base64.cpp index 1c69164..37b6d6c 100644 --- a/encfs/base64.cpp +++ b/encfs/base64.cpp @@ -20,7 +20,7 @@ #include "base64.h" -#include // for toupper +#include // 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 inputBuffer) { std::string encodedString; encodedString.reserve(B256ToB64Bytes(inputBuffer.size())); long temp; - std::vector::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; diff --git a/encfs/encfs.cpp b/encfs/encfs.cpp index 64a47b0..c7dabbb 100644 --- a/encfs/encfs.cpp +++ b/encfs/encfs.cpp @@ -18,17 +18,17 @@ #include "encfs.h" #include +#include #include +#include #include #include +#include #include -#include #include -#include #include #include #include -#include #include #include #ifdef linux @@ -41,7 +41,7 @@ #include #endif -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include #include @@ -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 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 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 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 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(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 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 FSRoot = ctx->getRoot(&res); - if (!FSRoot) return res; + if (!FSRoot) { + return res; + } try { std::shared_ptr fnode = FSRoot->lookupNode(path, "mknod"); @@ -272,8 +314,9 @@ int encfs_mknod(const char *path, mode_t mode, dev_t rdev) { FSRoot->lookupNode(parent.c_str(), "mknod"); struct stat st; - if (dnode->getAttr(&st) == 0) + if (dnode->getAttr(&st) == 0) { res = fnode->mknod(mode, rdev, uid, st.st_gid); + } } } catch (encfs::Error &err) { RLOG(ERROR) << "error caught in mknod: " << err.what(); @@ -285,11 +328,15 @@ int encfs_mkdir(const char *path, mode_t mode) { fuse_context *fctx = fuse_get_context(); EncFS_Context *ctx = context(); - if (isReadOnly(ctx)) return -EROFS; + if (isReadOnly(ctx)) { + return -EROFS; + } int res = -EIO; std::shared_ptr FSRoot = ctx->getRoot(&res); - if (!FSRoot) return res; + if (!FSRoot) { + return res; + } try { uid_t uid = 0; @@ -307,8 +354,9 @@ int encfs_mkdir(const char *path, mode_t mode) { FSRoot->lookupNode(parent.c_str(), "mkdir"); struct stat st; - if (dnode->getAttr(&st) == 0) + if (dnode->getAttr(&st) == 0) { res = FSRoot->mkdir(path, mode, uid, st.st_gid); + } } } catch (encfs::Error &err) { RLOG(ERROR) << "error caught in mkdir: " << err.what(); @@ -319,11 +367,15 @@ int encfs_mkdir(const char *path, mode_t mode) { int encfs_unlink(const char *path) { EncFS_Context *ctx = context(); - if (isReadOnly(ctx)) return -EROFS; + if (isReadOnly(ctx)) { + return -EROFS; + } int res = -EIO; std::shared_ptr 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 FSRoot = ctx->getRoot(&res); - if (!FSRoot) return res; + if (!FSRoot) { + return res; + } res = ::readlink(cyName.c_str(), buf, size - 1); - if (res == -1) return -errno; + if (res == -1) { + return -errno; + } buf[res] = '\0'; // ensure null termination string decodedName; @@ -363,10 +421,9 @@ int _do_readlink(EncFS_Context *ctx, const string &cyName, char *buf, buf[size - 1] = '\0'; return ESUCCESS; - } else { - RLOG(WARNING) << "Error decoding link"; - return -1; } + RLOG(WARNING) << "Error decoding link"; + return -1; } int encfs_readlink(const char *path, char *buf, size_t size) { @@ -380,11 +437,15 @@ int encfs_readlink(const char *path, char *buf, size_t size) { int encfs_symlink(const char *to, const char *from) { EncFS_Context *ctx = context(); - if (isReadOnly(ctx)) return -EROFS; + if (isReadOnly(ctx)) { + return -EROFS; + } int res = -EIO; std::shared_ptr 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 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 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 FSRoot = ctx->getRoot(&res); - if (!FSRoot) return res; + if (!FSRoot) { + return res; + } try { std::shared_ptr 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(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(finfo->fh)); + auto fnode = ctx->lookupFuseFh(finfo->fh); + ctx->eraseNode(path, fnode); return ESUCCESS; } catch (encfs::Error &err) { RLOG(ERROR) << "error caught in release: " << err.what(); @@ -610,21 +701,25 @@ int _do_fsync(FileNode *fnode, int dataSync) { } int encfs_fsync(const char *path, int dataSync, struct fuse_file_info *file) { - if (isReadOnly(NULL)) return -EROFS; + if (isReadOnly(nullptr)) { + return -EROFS; + } return withFileNode("fsync", path, file, bind(_do_fsync, _1, dataSync)); } int _do_write(FileNode *fnode, unsigned char *ptr, size_t size, off_t offset) { int res = fnode->write(offset, ptr, size); - if (res < 0) + if (res < 0) { return res; - else - return size; + } + return size; } int encfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *file) { - if (isReadOnly(NULL)) return -EROFS; + if (isReadOnly(nullptr)) { + return -EROFS; + } return withFileNode("write", path, file, bind(_do_write, _1, (unsigned char *)buf, size, offset)); } @@ -636,16 +731,18 @@ int encfs_statfs(const char *path, struct statvfs *st) { int res = -EIO; try { (void)path; // path should always be '/' for now.. - rAssert(st != NULL); + rAssert(st != nullptr); string cyName = ctx->rootCipherDir; VLOG(1) << "doing statfs of " << cyName; res = statvfs(cyName.c_str(), st); - if (!res) { + if (res == 0) { // adjust maximum name length.. st->f_namemax = 6 * (st->f_namemax - 2) / 8; // approx.. } - if (res == -1) res = -errno; + if (res == -1) { + res = -errno; + } } catch (encfs::Error &err) { RLOG(ERROR) << "error caught in statfs: " << err.what(); } @@ -657,7 +754,7 @@ int encfs_statfs(const char *path, struct statvfs *st) { #ifdef XATTR_ADD_OPT int _do_setxattr(EncFS_Context *, const string &cyName, const char *name, const char *value, size_t size, uint32_t pos) { - int options = 0; + int options = XATTR_NOFOLLOW; return ::setxattr(cyName.c_str(), name, value, size, pos, options); } int encfs_setxattr(const char *path, const char *name, const char *value, @@ -670,11 +767,13 @@ int encfs_setxattr(const char *path, const char *name, const char *value, #else int _do_setxattr(EncFS_Context *, const string &cyName, const char *name, const char *value, size_t size, int flags) { - return ::setxattr(cyName.c_str(), name, value, size, flags); + return ::lsetxattr(cyName.c_str(), name, value, size, flags); } int encfs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) { - if (isReadOnly(NULL)) return -EROFS; + if (isReadOnly(nullptr)) { + return -EROFS; + } return withCipherPath("setxattr", path, bind(_do_setxattr, _1, _2, name, value, size, flags)); } @@ -683,7 +782,7 @@ int encfs_setxattr(const char *path, const char *name, const char *value, #ifdef XATTR_ADD_OPT int _do_getxattr(EncFS_Context *, const string &cyName, const char *name, void *value, size_t size, uint32_t pos) { - int options = 0; + int options = XATTR_NOFOLLOW; return ::getxattr(cyName.c_str(), name, value, size, pos, options); } int encfs_getxattr(const char *path, const char *name, char *value, size_t size, @@ -695,7 +794,7 @@ int encfs_getxattr(const char *path, const char *name, char *value, size_t size, #else int _do_getxattr(EncFS_Context *, const string &cyName, const char *name, void *value, size_t size) { - return ::getxattr(cyName.c_str(), name, value, size); + return ::lgetxattr(cyName.c_str(), name, value, size); } int encfs_getxattr(const char *path, const char *name, char *value, size_t size) { @@ -708,10 +807,10 @@ int encfs_getxattr(const char *path, const char *name, char *value, int _do_listxattr(EncFS_Context *, const string &cyName, char *list, size_t size) { #ifdef XATTR_ADD_OPT - int options = 0; + int options = XATTR_NOFOLLOW; int res = ::listxattr(cyName.c_str(), list, size, options); #else - int res = ::listxattr(cyName.c_str(), list, size); + int res = ::llistxattr(cyName.c_str(), list, size); #endif return (res == -1) ? -errno : res; } @@ -723,16 +822,18 @@ int encfs_listxattr(const char *path, char *list, size_t size) { int _do_removexattr(EncFS_Context *, const string &cyName, const char *name) { #ifdef XATTR_ADD_OPT - int options = 0; + int options = XATTR_NOFOLLOW; int res = ::removexattr(cyName.c_str(), name, options); #else - int res = ::removexattr(cyName.c_str(), name); + int res = ::lremovexattr(cyName.c_str(), name); #endif return (res == -1) ? -errno : res; } int encfs_removexattr(const char *path, const char *name) { - if (isReadOnly(NULL)) return -EROFS; + if (isReadOnly(nullptr)) { + return -EROFS; + } return withCipherPath("removexattr", path, bind(_do_removexattr, _1, _2, name)); diff --git a/encfs/encfs.h b/encfs/encfs.h index 05c4fea..0d6b7d1 100644 --- a/encfs/encfs.h +++ b/encfs/encfs.h @@ -21,7 +21,7 @@ #ifndef _encfs_incl_ #define _encfs_incl_ -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include #include diff --git a/encfs/encfs.pod b/encfs/encfs.pod index 982f9b5..c216169 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -16,12 +16,13 @@ encfs - mounts or creates an encrypted virtual filesystem =head1 SYNOPSIS -B [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 [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 I [B<--> [I]] @@ -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 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 version. Using B<--verbose> before B<--version> may display +additional information. + +=item B<-v>, B<--verbose> + +Causes B to enable logging of various debug channels within B. +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. + +=item B<-s> + +The B<-s> (I) option causes B to run in single threaded +mode. By default, B runs in multi-threaded mode. This option is used +during B 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 to enable logging of various debug channels within B. -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) option causes B to run in single threaded -mode. By default, B runs in multi-threaded mode. This option is used -during B 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 library. This should only be used if you -suspect a problem within B itself (not B), as it generates a lot -of low-level data and is not likely to be very helpful in general problem -tracking. Try I mode (B<-v>) first, which gives a higher level view -of what is happening within B. +=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: 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 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 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 args to the underlying library. This makes it easy to -pass FUSE options when mounting B 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 to send any remaining arguments directly to -B. In turn, B passes the arguments to B. See -the B help page for information on available commands. - -=item B<--no-default-flags> - -B 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: 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 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 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: 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 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 args to the underlying library. This makes it easy to +pass FUSE options when mounting B 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 library. This should only be used if you +suspect a problem within B itself (not B), as it generates a lot +of low-level data and is not likely to be very helpful in general problem +tracking. Try I mode (B<-v>) first, which gives a higher level view +of what is happening within B. + +=item B<-H>, B<--fuse-help> + +Shows B help. + +=item B<--> + +The B<--> option tells B to send any remaining arguments directly to +B. In turn, B passes the arguments to B. See +the B help page for information on available commands. + =back =head1 ENVIRONMENT VARIABLES diff --git a/encfs/encfsctl.cpp b/encfs/encfsctl.cpp index 6a5d17e..26b82da 100644 --- a/encfs/encfsctl.cpp +++ b/encfs/encfsctl.cpp @@ -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); diff --git a/encfs/encfssh b/encfs/encfssh index 679aa25..fe7b502 100755 --- a/encfs/encfssh +++ b/encfs/encfssh @@ -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" diff --git a/encfs/main.cpp b/encfs/main.cpp index ebb96bd..3ae55d6 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -18,18 +18,18 @@ #include #include +#include #include +#include #include #include #include #include #include #include -#include #include #include #include -#include #include #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 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(argv), (fuse_operations *)NULL, NULL); + fuse_main(argc, const_cast(argv), (fuse_operations *)nullptr, + nullptr); } #define PUSHARG(ARG) \ do { \ rAssert(out->fuseArgc < MaxFuseArgs); \ out->fuseArgv[out->fuseArgc++] = (ARG); \ - } while (0) + } while (false) static string slashTerminate(const string &src) { string result = src; - if (result[result.length() - 1] != '/') result.append("/"); + if (result[result.length() - 1] != '/') { + result.append("/"); + } return result; } @@ -190,6 +206,7 @@ static bool processArgs(int argc, char *argv[], out->isVerbose = false; out->idleTimeout = 0; out->fuseArgc = 0; + out->syslogTag = "encfs"; out->opts->idleTracking = false; out->opts->checkKey = true; out->opts->forceDecode = false; @@ -207,36 +224,37 @@ static bool processArgs(int argc, char *argv[], // leave a space for mount point, as FUSE expects the mount point before // any flags - out->fuseArgv[1] = NULL; + out->fuseArgv[1] = nullptr; ++out->fuseArgc; // TODO: can flags be internationalized? static struct option long_options[] = { - {"fuse-debug", 0, 0, 'd'}, // Fuse debug mode - {"forcedecode", 0, 0, 'D'}, // force decode + {"fuse-debug", 0, nullptr, 'd'}, // Fuse debug mode + {"forcedecode", 0, nullptr, 'D'}, // force decode // {"foreground", 0, 0, 'f'}, // foreground mode (no daemon) - {"fuse-help", 0, 0, 'H'}, // fuse_mount usage - {"idle", 1, 0, 'i'}, // idle timeout - {"anykey", 0, 0, 'k'}, // skip key checks - {"no-default-flags", 0, 0, 'N'}, // don't use default fuse flags - {"ondemand", 0, 0, 'm'}, // mount on-demand - {"delaymount", 0, 0, 'M'}, // delay initial mount until use - {"public", 0, 0, 'P'}, // public mode - {"extpass", 1, 0, 'p'}, // external password program + {"fuse-help", 0, nullptr, 'H'}, // fuse_mount usage + {"idle", 1, nullptr, 'i'}, // idle timeout + {"anykey", 0, nullptr, 'k'}, // skip key checks + {"no-default-flags", 0, nullptr, 'N'}, // don't use default fuse flags + {"ondemand", 0, nullptr, 'm'}, // mount on-demand + {"delaymount", 0, nullptr, 'M'}, // delay initial mount until use + {"public", 0, nullptr, 'P'}, // public mode + {"extpass", 1, nullptr, 'p'}, // external password program // {"single-thread", 0, 0, 's'}, // single-threaded mode - {"stdinpass", 0, 0, 'S'}, // read password from stdin - {"annotate", 0, 0, - LONG_OPT_ANNOTATE}, // Print annotation lines to stderr - {"nocache", 0, 0, LONG_OPT_NOCACHE}, // disable caching - {"verbose", 0, 0, 'v'}, // verbose mode - {"version", 0, 0, 'V'}, // version - {"reverse", 0, 0, 'r'}, // reverse encryption - {"standard", 0, 0, '1'}, // standard configuration - {"paranoia", 0, 0, '2'}, // standard configuration - {"require-macs", 0, 0, LONG_OPT_REQUIRE_MAC}, // require MACs - {0, 0, 0, 0}}; + {"stdinpass", 0, nullptr, 'S'}, // read password from stdin + {"syslogtag", 1, nullptr, 't'}, // syslog tag + {"annotate", 0, nullptr, + LONG_OPT_ANNOTATE}, // Print annotation lines to stderr + {"nocache", 0, nullptr, LONG_OPT_NOCACHE}, // disable caching + {"verbose", 0, nullptr, 'v'}, // verbose mode + {"version", 0, nullptr, 'V'}, // version + {"reverse", 0, nullptr, 'r'}, // reverse encryption + {"standard", 0, nullptr, '1'}, // standard configuration + {"paranoia", 0, nullptr, '2'}, // standard configuration + {"require-macs", 0, nullptr, LONG_OPT_REQUIRE_MAC}, // require MACs + {nullptr, 0, nullptr, 0}}; - while (1) { + while (true) { int option_index = 0; // 's' : single-threaded mode @@ -247,10 +265,13 @@ static bool processArgs(int argc, char *argv[], // 'm' : mount-on-demand // 'S' : password from stdin // 'o' : arguments meant for fuse + // 't' : syslog tag int res = - getopt_long(argc, argv, "HsSfvdmi:o:", long_options, &option_index); + getopt_long(argc, argv, "HsSfvdmi:o:t:", long_options, &option_index); - if (res == -1) break; + if (res == -1) { + break; + } switch (res) { case '1': @@ -265,6 +286,9 @@ static bool processArgs(int argc, char *argv[], case 'S': out->opts->useStdin = true; break; + case 't': + out->syslogTag = optarg; + break; case LONG_OPT_ANNOTATE: out->opts->annotate = true; break; @@ -283,7 +307,7 @@ static bool processArgs(int argc, char *argv[], PUSHARG("-d"); break; case 'i': - out->idleTimeout = strtol(optarg, (char **)NULL, 10); + out->idleTimeout = strtol(optarg, (char **)nullptr, 10); out->opts->idleTracking = true; break; case 'k': @@ -342,9 +366,9 @@ static bool processArgs(int argc, char *argv[], out->opts->passwordProgram.assign(optarg); break; case 'P': - if (geteuid() != 0) + if (geteuid() != 0) { RLOG(WARNING) << "option '--public' ignored for non-root user"; - else { + } else { out->opts->ownerCreate = true; // add 'allow_other' option // add 'default_permissions' option (default) @@ -355,6 +379,12 @@ static bool processArgs(int argc, char *argv[], case 'V': // xgroup(usage) cerr << autosprintf(_("encfs version %s"), VERSION) << endl; +#if defined(HAVE_XATTR) + // "--verbose" has to be passed before "--version" for this to work. + if (out->isVerbose) { + cerr << "Compiled with : HAVE_XATTR" << endl; + } +#endif exit(EXIT_SUCCESS); break; case 'H': @@ -373,7 +403,9 @@ static bool processArgs(int argc, char *argv[], } } - if (!out->isThreaded) PUSHARG("-s"); + if (!out->isThreaded) { + PUSHARG("-s"); + } // we should have at least 2 arguments left over - the source directory and // the mount point. @@ -486,15 +518,10 @@ static bool processArgs(int argc, char *argv[], static void *idleMonitor(void *); void *encfs_init(fuse_conn_info *conn) { - EncFS_Context *ctx = (EncFS_Context *)fuse_get_context()->private_data; + auto *ctx = (EncFS_Context *)fuse_get_context()->private_data; // set fuse connection options - conn->async_read = true; - - if (ctx->args->isDaemon) { - // Switch to using syslog. - encfs::rlogAction = el::base::DispatchAction::SysLog; - } + conn->async_read = 1u; // if an idle timeout is specified, then setup a thread to monitor the // filesystem. @@ -502,7 +529,8 @@ void *encfs_init(fuse_conn_info *conn) { VLOG(1) << "starting idle monitoring thread"; ctx->running = true; - int res = pthread_create(&ctx->monitorThread, 0, idleMonitor, (void *)ctx); + int res = + pthread_create(&ctx->monitorThread, nullptr, idleMonitor, (void *)ctx); if (res != 0) { int eno = errno; RLOG(ERROR) << "error starting idle monitor thread, " @@ -532,19 +560,17 @@ int main(int argc, char *argv[]) { // anything that comes from the user should be considered tainted until // we've processed it and only allowed through what we support. std::shared_ptr 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(new EncFS_Context); + auto ctx = std::make_shared(); 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 arg = ctx->args; const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval; int idleCycles = -1; + bool unmountres = false; + + // We will notify when FS will be unmounted, so notify that it has just been + // mounted + RLOG(INFO) << "Filesystem mounted: " << arg->opts->mountPoint; + pthread_mutex_lock(&ctx->wakeupMutex); while (ctx->running) { - int usage = ctx->getAndResetUsageCounter(); + int usage, openCount; + ctx->getAndResetUsageCounter(&usage, &openCount); - if (usage == 0 && ctx->isMounted()) + if (usage == 0 && ctx->isMounted()) { ++idleCycles; - else + } else { + if (idleCycles >= timeoutCycles) { + RLOG(INFO) << "Filesystem no longer inactive: " + << arg->opts->mountPoint; + } idleCycles = 0; + } if (idleCycles >= timeoutCycles) { - int openCount = ctx->openFileCount(); if (openCount == 0) { - if (unmountFS(ctx)) { + unmountres = unmountFS(ctx); + if (unmountres) { // wait for main thread to wake us up pthread_cond_wait(&ctx->wakeupCond, &ctx->wakeupMutex); break; } } else { - RLOG(WARNING) << "Filesystem " << arg->opts->mountPoint - << " inactivity detected, but still " << openCount - << " opened files"; + RLOG(WARNING) << "Filesystem inactive, but " << openCount + << " files opened: " << arg->opts->mountPoint; } } @@ -745,7 +788,7 @@ static void *idleMonitor(void *_arg) { << timeoutCycles; struct timeval currentTime; - gettimeofday(¤tTime, 0); + gettimeofday(¤tTime, nullptr); struct timespec wakeupTime; wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval; wakeupTime.tv_nsec = currentTime.tv_usec * 1000; @@ -754,9 +797,15 @@ static void *idleMonitor(void *_arg) { pthread_mutex_unlock(&ctx->wakeupMutex); + // If we are here FS has been unmounted, so if we did not unmount ourselves + // (manual, kill...), notify + if (!unmountres) { + RLOG(INFO) << "Filesystem unmounted: " << arg->opts->mountPoint; + } + VLOG(1) << "Idle monitoring thread exiting"; - return 0; + return nullptr; } static bool unmountFS(EncFS_Context *ctx) { @@ -767,11 +816,14 @@ static bool unmountFS(EncFS_Context *ctx) { ctx->setRoot(std::shared_ptr()); 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; } diff --git a/encfs/makeKey.cpp b/encfs/makeKey.cpp index d0a14d2..1e69eda 100644 --- a/encfs/makeKey.cpp +++ b/encfs/makeKey.cpp @@ -31,8 +31,6 @@ using namespace std; using namespace encfs; -INITIALIZE_EASYLOGGINGPP - void genKey(const std::shared_ptr &cipher) { CipherKey key = cipher->newRandomKey(); diff --git a/encfs/openssl.cpp b/encfs/openssl.cpp index 801a105..3b0f1b3 100644 --- a/encfs/openssl.cpp +++ b/encfs/openssl.cpp @@ -20,9 +20,9 @@ #include "openssl.h" +#include #include #include -#include #define NO_DES #include @@ -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 diff --git a/encfs/readpassphrase.cpp b/encfs/readpassphrase.cpp index daf4a56..59a8abd 100644 --- a/encfs/readpassphrase.cpp +++ b/encfs/readpassphrase.cpp @@ -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 */ diff --git a/encfs/test.cpp b/encfs/test.cpp index ee66469..8da058e 100644 --- a/encfs/test.cpp +++ b/encfs/test.cpp @@ -38,7 +38,7 @@ #include "NameIO.h" #include "Range.h" #include "StreamNameIO.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #define NO_DES #include @@ -49,8 +49,6 @@ using namespace std; using namespace encfs; -INITIALIZE_EASYLOGGINGPP - const int FSBlockSize = 256; static int checkErrorPropogation(const std::shared_ptr &cipher, @@ -175,11 +173,12 @@ bool runTests(const std::shared_ptr &cipher, bool verbose) { cfg.assignKeyData(keyBuf, encodedKeySize); // save config - //Creation of a temporary file should be more platform independent. On c++17 we could use std::filesystem. + // Creation of a temporary file should be more platform independent. On + // c++17 we could use std::filesystem. string name = "/tmp/encfstestXXXXXX"; int tmpFd = mkstemp(&name[0]); rAssert(-1 != tmpFd); - //mkstemp opens the temporary file, but we only need its name -> close it + // mkstemp opens the temporary file, but we only need its name -> close it rAssert(0 == close(tmpFd)); { auto ok = writeV6Config(name.c_str(), &cfg); @@ -192,9 +191,9 @@ bool runTests(const std::shared_ptr &cipher, bool verbose) { auto ok = readV6Config(name.c_str(), &cfg2, nullptr); rAssert(ok == true); } - //delete the temporary file where we stored the config + // delete the temporary file where we stored the config rAssert(0 == unlink(name.c_str())); - + // check.. rAssert(cfg.cipherIface.implements(cfg2.cipherIface)); rAssert(cfg.keySize == cfg2.keySize); diff --git a/internal/easylogging++.h b/internal/easylogging++.h deleted file mode 100644 index 054b2ae..0000000 --- a/internal/easylogging++.h +++ /dev/null @@ -1,6695 +0,0 @@ -// -// Bismillah ar-Rahmaan ar-Raheem -// -// Easylogging++ v9.83 -// Single-header only, cross-platform logging library for C++ applications -// -// Copyright (c) 2016 muflihun.com -// -// This library is released under the MIT Licence. -// http://easylogging.muflihun.com/licence.php -// -// easylogging@muflihun.com -// -// https://github.com/easylogging/easyloggingpp -// http://easylogging.muflihun.com -// http://muflihun.com -// -#ifndef EASYLOGGINGPP_H -#define EASYLOGGINGPP_H -// Compilers and C++0x/C++11 Evaluation -#if (defined(__GNUC__)) -# define ELPP_COMPILER_GCC 1 -#else -# define ELPP_COMPILER_GCC 0 -#endif -#if ELPP_COMPILER_GCC -# define ELPP_GCC_VERSION (__GNUC__ * 10000 \ -+ __GNUC_MINOR__ * 100 \ -+ __GNUC_PATCHLEVEL__) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ELPP_CXX0X 1 -# elif(ELPP_GCC_VERSION >= 40801) -# define ELPP_CXX11 1 -# endif -#endif -// Visual C++ -#if defined(_MSC_VER) -# define ELPP_COMPILER_MSVC 1 -#else -# define ELPP_COMPILER_MSVC 0 -#endif -#define ELPP_CRT_DBG_WARNINGS ELPP_COMPILER_MSVC -#if ELPP_COMPILER_MSVC -# if (_MSC_VER == 1600) -# define ELPP_CXX0X 1 -# elif(_MSC_VER >= 1700) -# define ELPP_CXX11 1 -# endif -#endif -// Clang++ -#if (defined(__clang__) && (__clang__ == 1)) -# define ELPP_COMPILER_CLANG 1 -#else -# define ELPP_COMPILER_CLANG 0 -#endif -#if ELPP_COMPILER_CLANG -# define ELPP_CLANG_VERSION (__clang_major__ * 10000 \ -+ __clang_minor__ * 100 \ -+ __clang_patchlevel__) -# if (ELPP_CLANG_VERSION >= 30300) -# define ELPP_CXX11 1 -# endif // (ELPP_CLANG_VERSION >= 30300) -#endif -#if (defined(__MINGW32__) || defined(__MINGW64__)) -# define ELPP_MINGW 1 -#else -# define ELPP_MINGW 0 -#endif -#if (defined(__CYGWIN__) && (__CYGWIN__ == 1)) -# define ELPP_CYGWIN 1 -#else -# define ELPP_CYGWIN 0 -#endif -#if (defined(__INTEL_COMPILER)) -# define ELPP_COMPILER_INTEL 1 -#else -# define ELPP_COMPILER_INTEL 0 -#endif -// Operating System Evaluation -// Windows -#if (defined(_WIN32) || defined(_WIN64)) -# define ELPP_OS_WINDOWS 1 -#else -# define ELPP_OS_WINDOWS 0 -#endif -// Linux -#if (defined(__linux) || defined(__linux__)) -# define ELPP_OS_LINUX 1 -#else -# define ELPP_OS_LINUX 0 -#endif -#if (defined(__APPLE__)) -# define ELPP_OS_MAC 1 -#else -# define ELPP_OS_MAC 0 -#endif -#if (defined(__FreeBSD__)) -# define ELPP_OS_FREEBSD 1 -#else -# define ELPP_OS_FREEBSD 0 -#endif -#if (defined(__sun)) -# define ELPP_OS_SOLARIS 1 -#else -# define ELPP_OS_SOLARIS 0 -#endif -// Unix -#if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_SOLARIS) && (!ELPP_OS_WINDOWS)) -# define ELPP_OS_UNIX 1 -#else -# define ELPP_OS_UNIX 0 -#endif -#if (defined(__ANDROID__)) -# define ELPP_OS_ANDROID 1 -#else -# define ELPP_OS_ANDROID 0 -#endif -// Evaluating Cygwin as *nix OS -#if !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN -# undef ELPP_OS_UNIX -# undef ELPP_OS_LINUX -# define ELPP_OS_UNIX 1 -# define ELPP_OS_LINUX 1 -#endif // !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN -#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_INFO) -# define ELPP_INTERNAL_DEBUGGING_OUT_INFO std::cout -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_ERROR) -# define ELPP_INTERNAL_DEBUGGING_OUT_ERROR std::cerr -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -#if !defined(ELPP_INTERNAL_DEBUGGING_ENDL) -# define ELPP_INTERNAL_DEBUGGING_ENDL std::endl -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -#if !defined(ELPP_INTERNAL_DEBUGGING_MSG) -# define ELPP_INTERNAL_DEBUGGING_MSG(msg) msg -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -// Internal Assertions and errors -#if !defined(ELPP_DISABLE_ASSERT) -# if (defined(ELPP_DEBUG_ASSERT_FAILURE)) -# define ELPP_ASSERT(expr, msg) if (!(expr)) { \ -std::stringstream internalInfoStream; internalInfoStream << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR \ -<< "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" \ -<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" << ELPP_INTERNAL_DEBUGGING_ENDL; base::utils::abort(1, \ -"ELPP Assertion failure, please define ELPP_DEBUG_ASSERT_FAILURE"); } -# else -# define ELPP_ASSERT(expr, msg) if (!(expr)) { \ -std::stringstream internalInfoStream; internalInfoStream << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR\ -<< "ASSERTION FAILURE FROM EASYLOGGING++ (LINE: " \ -<< __LINE__ << ") [" #expr << "] WITH MESSAGE \"" << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" \ -<< ELPP_INTERNAL_DEBUGGING_ENDL; } -# endif // (defined(ELPP_DEBUG_ASSERT_FAILURE)) -#else -# define ELPP_ASSERT(x, y) -#endif //(!defined(ELPP_DISABLE_ASSERT) -#if ELPP_COMPILER_MSVC -# define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \ -{ char buff[256]; strerror_s(buff, 256, errno); \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << buff << " [" << errno << "]";} (void)0 -#else -# define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << strerror(errno) << " [" << errno << "]"; (void)0 -#endif // ELPP_COMPILER_MSVC -#if defined(ELPP_DEBUG_ERRORS) -# if !defined(ELPP_INTERNAL_ERROR) -# define ELPP_INTERNAL_ERROR(msg, pe) { \ -std::stringstream internalInfoStream; internalInfoStream << " " << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR \ -<< "ERROR FROM EASYLOGGING++ (LINE: " << __LINE__ << ") " \ -<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << ELPP_INTERNAL_DEBUGGING_ENDL; \ -if (pe) { ELPP_INTERNAL_DEBUGGING_OUT_ERROR << " "; ELPP_INTERNAL_DEBUGGING_WRITE_PERROR; }} (void)0 -# endif -#else -# undef ELPP_INTERNAL_INFO -# define ELPP_INTERNAL_ERROR(msg, pe) -#endif // defined(ELPP_DEBUG_ERRORS) -#if (defined(ELPP_DEBUG_INFO)) -# if !(defined(ELPP_INTERNAL_INFO_LEVEL)) -# define ELPP_INTERNAL_INFO_LEVEL 9 -# endif // !(defined(ELPP_INTERNAL_INFO_LEVEL)) -# if !defined(ELPP_INTERNAL_INFO) -# define ELPP_INTERNAL_INFO(lvl, msg) { if (lvl <= ELPP_INTERNAL_INFO_LEVEL) { \ -std::stringstream internalInfoStream; internalInfoStream << " " << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) \ -<< ELPP_INTERNAL_DEBUGGING_ENDL; }} -# endif -#else -# undef ELPP_INTERNAL_INFO -# define ELPP_INTERNAL_INFO(lvl, msg) -#endif // (defined(ELPP_DEBUG_INFO)) -#if defined(ELPP_STACKTRACE_ON_CRASH) -# if (ELPP_COMPILER_GCC && !ELPP_MINGW) -# define ELPP_STACKTRACE 1 -# else -# if ELPP_COMPILER_MSVC -# pragma message("Stack trace not available for this compiler") -# else -# warning "Stack trace not available for this compiler"; -# endif // ELPP_COMPILER_MSVC -# endif // ELPP_COMPILER_GCC -#endif // (defined(ELPP_STACKTRACE_ON_CRASH)) -// Miscellaneous macros -#define ELPP_UNUSED(x) (void)x -#if ELPP_OS_UNIX -// Log file permissions for unix-based systems -# define ELPP_LOG_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH -#endif // ELPP_OS_UNIX -#if defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC -# if defined(ELPP_EXPORT_SYMBOLS) -# define ELPP_EXPORT __declspec(dllexport) -# else -# define ELPP_EXPORT __declspec(dllimport) -# endif // defined(ELPP_EXPORT_SYMBOLS) -#else -# define ELPP_EXPORT -#endif // defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC -// Some special functions that are VC++ specific -#undef STRTOK -#undef STRERROR -#undef STRCAT -#undef STRCPY -#if ELPP_CRT_DBG_WARNINGS -# define STRTOK(a, b, c) strtok_s(a, b, c) -# define STRERROR(a, b, c) strerror_s(a, b, c) -# define STRCAT(a, b, len) strcat_s(a, len, b) -# define STRCPY(a, b, len) strcpy_s(a, len, b) -#else -# define STRTOK(a, b, c) strtok(a, b) -# define STRERROR(a, b, c) strerror(c) -# define STRCAT(a, b, len) strcat(a, b) -# define STRCPY(a, b, len) strcpy(a, b) -#endif -// Compiler specific support evaluations -#if ((!ELPP_MINGW && !ELPP_COMPILER_CLANG) || defined(ELPP_FORCE_USE_STD_THREAD)) -# define ELPP_USE_STD_THREADING 1 -#else -# define ELPP_USE_STD_THREADING 0 -#endif -#undef ELPP_FINAL -#if ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702) -# define ELPP_FINAL -#else -# define ELPP_FINAL final -#endif // ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702) -#if defined(ELPP_EXPERIMENTAL_ASYNC) -# define ELPP_ASYNC_LOGGING 1 -#else -# define ELPP_ASYNC_LOGGING 0 -#endif // defined(ELPP_EXPERIMENTAL_ASYNC) -#if defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING -# define ELPP_THREADING_ENABLED 1 -#else -# define ELPP_THREADING_ENABLED 0 -#endif // defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING -// Function macro ELPP_FUNC -#undef ELPP_FUNC -#if ELPP_COMPILER_MSVC // Visual C++ -# define ELPP_FUNC __FUNCSIG__ -#elif ELPP_COMPILER_GCC // GCC -# define ELPP_FUNC __PRETTY_FUNCTION__ -#elif ELPP_COMPILER_INTEL // Intel C++ -# define ELPP_FUNC __PRETTY_FUNCTION__ -#elif ELPP_COMPILER_CLANG // Clang++ -# define ELPP_FUNC __PRETTY_FUNCTION__ -#else -# if defined(__func__) -# define ELPP_FUNC __func__ -# else -# define ELPP_FUNC "" -# endif // defined(__func__) -#endif // defined(_MSC_VER) -#undef ELPP_VARIADIC_TEMPLATES_SUPPORTED -// Keep following line commented until features are fixed -#define ELPP_VARIADIC_TEMPLATES_SUPPORTED \ -(ELPP_COMPILER_GCC || ELPP_COMPILER_CLANG || ELPP_COMPILER_INTEL || (ELPP_COMPILER_MSVC && _MSC_VER >= 1800)) -// Logging Enable/Disable macros -#define ELPP_LOGGING_ENABLED (!defined(ELPP_DISABLE_LOGS)) -#if (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED) && ((defined(_DEBUG)) || (!defined(NDEBUG)))) -# define ELPP_DEBUG_LOG 1 -#else -# define ELPP_DEBUG_LOG 0 -#endif // (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED) && ((defined(_DEBUG)) || (!defined(NDEBUG)))) -#if (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_INFO_LOG 1 -#else -# define ELPP_INFO_LOG 0 -#endif // (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_WARNING_LOG 1 -#else -# define ELPP_WARNING_LOG 0 -#endif // (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_ERROR_LOG 1 -#else -# define ELPP_ERROR_LOG 0 -#endif // (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_FATAL_LOG 1 -#else -# define ELPP_FATAL_LOG 0 -#endif // (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_TRACE_LOG 1 -#else -# define ELPP_TRACE_LOG 0 -#endif // (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_VERBOSE_LOG 1 -#else -# define ELPP_VERBOSE_LOG 0 -#endif // (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!(ELPP_CXX0X || ELPP_CXX11)) -# error "Easylogging++ 9.0+ is only compatible with C++0x (or higher) compliant compiler" -#endif // (!(ELPP_CXX0X || ELPP_CXX11)) -// Headers -#if defined(ELPP_SYSLOG) -# include -#endif // defined(ELPP_SYSLOG) -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(ELPP_UNICODE) -# include -# if ELPP_OS_WINDOWS -# include -# endif // ELPP_OS_WINDOWS -#endif // defined(ELPP_UNICODE) -#if ELPP_STACKTRACE -# include -# include -#endif // ELPP_STACKTRACE -#if ELPP_OS_ANDROID -# include -#endif // ELPP_OS_ANDROID -#if ELPP_OS_UNIX -# include -# include -#elif ELPP_OS_WINDOWS -# include -# include -# if defined(WIN32_LEAN_AND_MEAN) -# if defined(ELPP_WINSOCK2) -# include -# else -# include -# endif // defined(ELPP_WINSOCK2) -# endif // defined(WIN32_LEAN_AND_MEAN) -#endif // ELPP_OS_UNIX -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if ELPP_THREADING_ENABLED -# if ELPP_USE_STD_THREADING -# include -# include -# else -# if ELPP_OS_UNIX -# include -# endif // ELPP_OS_UNIX -# endif // ELPP_USE_STD_THREADING -#endif // ELPP_THREADING_ENABLED -#if ELPP_ASYNC_LOGGING -# if defined(ELPP_NO_SLEEP_FOR) -# include -# endif // defined(ELPP_NO_SLEEP_FOR) -# include -# include -# include -#endif // ELPP_ASYNC_LOGGING -#if defined(ELPP_STL_LOGGING) -// For logging STL based templates -# include -# include -# include -# include -# include -# include -# if defined(ELPP_LOG_STD_ARRAY) -# include -# endif // defined(ELPP_LOG_STD_ARRAY) -# if defined(ELPP_LOG_UNORDERED_MAP) -# include -# endif // defined(ELPP_LOG_UNORDERED_MAP) -# if defined(ELPP_LOG_UNORDERED_SET) -# include -# endif // defined(ELPP_UNORDERED_SET) -#endif // defined(ELPP_STL_LOGGING) -#if defined(ELPP_QT_LOGGING) -// For logging Qt based classes & templates -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif // defined(ELPP_QT_LOGGING) -#if defined(ELPP_BOOST_LOGGING) -// For logging boost based classes & templates -# include -# include -# include -# include -# include -# include -# include -# include -#endif // defined(ELPP_BOOST_LOGGING) -#if defined(ELPP_WXWIDGETS_LOGGING) -// For logging wxWidgets based classes & templates -# include -#endif // defined(ELPP_WXWIDGETS_LOGGING) -// Forward declarations -namespace el { - class Logger; - class LogMessage; - class PerformanceTrackingData; - class Loggers; - class Helpers; - template class Callback; - class LogDispatchCallback; - class PerformanceTrackingCallback; - class LogDispatchData; - namespace base { - class Storage; - class RegisteredLoggers; - class PerformanceTracker; - class MessageBuilder; - class Writer; - class PErrorWriter; - class LogDispatcher; - class DefaultLogBuilder; - class DefaultLogDispatchCallback; -#if ELPP_ASYNC_LOGGING - class AsyncLogDispatchCallback; - class AsyncDispatchWorker; -#endif // ELPP_ASYNC_LOGGING - class DefaultPerformanceTrackingCallback; - } // namespace base -} // namespace el -/// @brief Easylogging++ entry namespace -namespace el { - /// @brief Namespace containing base/internal functionality used by Easylogging++ - namespace base { - /// @brief Data types used by Easylogging++ - namespace type { -#undef ELPP_LITERAL -#undef ELPP_STRLEN -#undef ELPP_COUT -#if defined(ELPP_UNICODE) -# define ELPP_LITERAL(txt) L##txt -# define ELPP_STRLEN wcslen -# if defined ELPP_CUSTOM_COUT -# define ELPP_COUT ELPP_CUSTOM_COUT -# else -# define ELPP_COUT std::wcout -# endif // defined ELPP_CUSTOM_COUT - typedef wchar_t char_t; - typedef std::wstring string_t; - typedef std::wstringstream stringstream_t; - typedef std::wfstream fstream_t; - typedef std::wostream ostream_t; -#else -# define ELPP_LITERAL(txt) txt -# define ELPP_STRLEN strlen -# if defined ELPP_CUSTOM_COUT -# define ELPP_COUT ELPP_CUSTOM_COUT -# else -# define ELPP_COUT std::cout -# endif // defined ELPP_CUSTOM_COUT - typedef char char_t; - typedef std::string string_t; - typedef std::stringstream stringstream_t; - typedef std::fstream fstream_t; - typedef std::ostream ostream_t; -#endif // defined(ELPP_UNICODE) -#if defined(ELPP_CUSTOM_COUT_LINE) -# define ELPP_COUT_LINE(logLine) ELPP_CUSTOM_COUT_LINE(logLine) -#else -# define ELPP_COUT_LINE(logLine) logLine << std::flush -#endif // defined(ELPP_CUSTOM_COUT_LINE) - typedef unsigned short EnumType; - typedef std::shared_ptr StoragePointer; - typedef int VerboseLevel; - typedef std::shared_ptr LogDispatchCallbackPtr; - typedef std::shared_ptr PerformanceTrackingCallbackPtr; - } // namespace type - /// @brief Internal helper class that prevent copy constructor for class - /// - /// @detail When using this class simply inherit it privately - class NoCopy { - protected: - NoCopy(void) {} - private: - NoCopy(const NoCopy&); - NoCopy& operator=(const NoCopy&); - }; - /// @brief Internal helper class that makes all default constructors private. - /// - /// @detail This prevents initializing class making it static unless an explicit constructor is declared. - /// When using this class simply inherit it privately - class StaticClass { - private: - StaticClass(void); - StaticClass(const StaticClass&); - StaticClass& operator=(const StaticClass&); - }; - } // namespace base - /// @brief Represents enumeration for severity level used to determine level of logging - /// - /// @detail With Easylogging++, developers may disable or enable any level regardless of - /// what the severity is. Or they can choose to log using hierarchical logging flag - enum class Level : base::type::EnumType { - /// @brief Generic level that represents all the levels. Useful when setting global configuration for all levels - Global = 1, - /// @brief Information that can be useful to back-trace certain events - mostly useful than debug logs. - Trace = 2, - /// @brief Informational events most useful for developers to debug application - Debug = 4, - /// @brief Severe error information that will presumably abort application - Fatal = 8, - /// @brief Information representing errors in application but application will keep running - Error = 16, - /// @brief Useful when application has potentially harmful situtaions - Warning = 32, - /// @brief Information that can be highly useful and vary with verbose logging level. - Verbose = 64, - /// @brief Mainly useful to represent current progress of application - Info = 128, - /// @brief Represents unknown level - Unknown = 1010 - }; - /// @brief Static class that contains helper functions for el::Level - class LevelHelper : base::StaticClass { - public: - /// @brief Represents minimum valid level. Useful when iterating through enum. - static const base::type::EnumType kMinValid = static_cast(Level::Trace); - /// @brief Represents maximum valid level. This is used internally and you should not need it. - static const base::type::EnumType kMaxValid = static_cast(Level::Info); - /// @brief Casts level to int, useful for iterating through enum. - static base::type::EnumType castToInt(Level level) { - return static_cast(level); - } - /// @brief Casts int(ushort) to level, useful for iterating through enum. - static Level castFromInt(base::type::EnumType l) { - return static_cast(l); - } - /// @brief Converts level to associated const char* - /// @return Upper case string based level. - static const char* convertToString(Level level) { - // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. - if (level == Level::Global) return "GLOBAL"; - if (level == Level::Debug) return "DEBUG"; - if (level == Level::Info) return "INFO"; - if (level == Level::Warning) return "WARNING"; - if (level == Level::Error) return "ERROR"; - if (level == Level::Fatal) return "FATAL"; - if (level == Level::Verbose) return "VERBOSE"; - if (level == Level::Trace) return "TRACE"; - return "UNKNOWN"; - } - /// @brief Converts from levelStr to Level - /// @param levelStr Upper case string based level. - /// Lower case is also valid but providing upper case is recommended. - static Level convertFromString(const char* levelStr) { - if ((strcmp(levelStr, "GLOBAL") == 0) || (strcmp(levelStr, "global") == 0)) - return Level::Global; - if ((strcmp(levelStr, "DEBUG") == 0) || (strcmp(levelStr, "debug") == 0)) - return Level::Debug; - if ((strcmp(levelStr, "INFO") == 0) || (strcmp(levelStr, "info") == 0)) - return Level::Info; - if ((strcmp(levelStr, "WARNING") == 0) || (strcmp(levelStr, "warning") == 0)) - return Level::Warning; - if ((strcmp(levelStr, "ERROR") == 0) || (strcmp(levelStr, "error") == 0)) - return Level::Error; - if ((strcmp(levelStr, "FATAL") == 0) || (strcmp(levelStr, "fatal") == 0)) - return Level::Fatal; - if ((strcmp(levelStr, "VERBOSE") == 0) || (strcmp(levelStr, "verbose") == 0)) - return Level::Verbose; - if ((strcmp(levelStr, "TRACE") == 0) || (strcmp(levelStr, "trace") == 0)) - return Level::Trace; - return Level::Unknown; - } - /// @brief Applies specified function to each level starting from startIndex - /// @param startIndex initial value to start the iteration from. This is passed as pointer and - /// is left-shifted so this can be used inside function (fn) to represent current level. - /// @param fn function to apply with each level. This bool represent whether or not to stop iterating through levels. - static inline void forEachLevel(base::type::EnumType* startIndex, const std::function& fn) { - base::type::EnumType lIndexMax = LevelHelper::kMaxValid; - do { - if (fn()) { - break; - } - *startIndex = static_cast(*startIndex << 1); - } while (*startIndex <= lIndexMax); - } - }; - /// @brief Represents enumeration of ConfigurationType used to configure or access certain aspect - /// of logging - enum class ConfigurationType : base::type::EnumType { - /// @brief Determines whether or not corresponding level and logger of logging is enabled - /// You may disable all logs by using el::Level::Global - Enabled = 1, - /// @brief Whether or not to write corresponding log to log file - ToFile = 2, - /// @brief Whether or not to write corresponding level and logger log to standard output. - /// By standard output meaning termnal, command prompt etc - ToStandardOutput = 4, - /// @brief Determines format of logging corresponding level and logger. - Format = 8, - /// @brief Determines log file (full path) to write logs to for correponding level and logger - Filename = 16, - /// @brief Specifies milliseconds width. Width can be within range (1-6) - MillisecondsWidth = 32, - /// @brief Determines whether or not performance tracking is enabled. - /// - /// @detail This does not depend on logger or level. Performance tracking always uses 'performance' logger - PerformanceTracking = 64, - /// @brief Specifies log file max size. - /// - /// @detail If file size of corresponding log file (for corresponding level) is >= specified size, log file will - /// be truncated and re-initiated. - MaxLogFileSize = 128, - /// @brief Specifies number of log entries to hold until we flush pending log data - LogFlushThreshold = 256, - /// @brief Represents unknown configuration - Unknown = 1010 - }; - /// @brief Static class that contains helper functions for el::ConfigurationType - class ConfigurationTypeHelper : base::StaticClass { - public: - /// @brief Represents minimum valid configuration type. Useful when iterating through enum. - static const base::type::EnumType kMinValid = static_cast(ConfigurationType::Enabled); - /// @brief Represents maximum valid configuration type. This is used internally and you should not need it. - static const base::type::EnumType kMaxValid = static_cast(ConfigurationType::MaxLogFileSize); - /// @brief Casts configuration type to int, useful for iterating through enum. - static base::type::EnumType castToInt(ConfigurationType configurationType) { - return static_cast(configurationType); - } - /// @brief Casts int(ushort) to configurationt type, useful for iterating through enum. - static ConfigurationType castFromInt(base::type::EnumType c) { - return static_cast(c); - } - /// @brief Converts configuration type to associated const char* - /// @returns Upper case string based configuration type. - static const char* convertToString(ConfigurationType configurationType) { - // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. - if (configurationType == ConfigurationType::Enabled) return "ENABLED"; - if (configurationType == ConfigurationType::Filename) return "FILENAME"; - if (configurationType == ConfigurationType::Format) return "FORMAT"; - if (configurationType == ConfigurationType::ToFile) return "TO_FILE"; - if (configurationType == ConfigurationType::ToStandardOutput) return "TO_STANDARD_OUTPUT"; - if (configurationType == ConfigurationType::MillisecondsWidth) return "MILLISECONDS_WIDTH"; - if (configurationType == ConfigurationType::PerformanceTracking) return "PERFORMANCE_TRACKING"; - if (configurationType == ConfigurationType::MaxLogFileSize) return "MAX_LOG_FILE_SIZE"; - if (configurationType == ConfigurationType::LogFlushThreshold) return "LOG_FLUSH_THRESHOLD"; - return "UNKNOWN"; - } - /// @brief Converts from configStr to ConfigurationType - /// @param configStr Upper case string based configuration type. - /// Lower case is also valid but providing upper case is recommended. - static ConfigurationType convertFromString(const char* configStr) { - if ((strcmp(configStr, "ENABLED") == 0) || (strcmp(configStr, "enabled") == 0)) - return ConfigurationType::Enabled; - if ((strcmp(configStr, "TO_FILE") == 0) || (strcmp(configStr, "to_file") == 0)) - return ConfigurationType::ToFile; - if ((strcmp(configStr, "TO_STANDARD_OUTPUT") == 0) || (strcmp(configStr, "to_standard_output") == 0)) - return ConfigurationType::ToStandardOutput; - if ((strcmp(configStr, "FORMAT") == 0) || (strcmp(configStr, "format") == 0)) - return ConfigurationType::Format; - if ((strcmp(configStr, "FILENAME") == 0) || (strcmp(configStr, "filename") == 0)) - return ConfigurationType::Filename; - if ((strcmp(configStr, "MILLISECONDS_WIDTH") == 0) || (strcmp(configStr, "milliseconds_width") == 0)) - return ConfigurationType::MillisecondsWidth; - if ((strcmp(configStr, "PERFORMANCE_TRACKING") == 0) || (strcmp(configStr, "performance_tracking") == 0)) - return ConfigurationType::PerformanceTracking; - if ((strcmp(configStr, "MAX_LOG_FILE_SIZE") == 0) || (strcmp(configStr, "max_log_file_size") == 0)) - return ConfigurationType::MaxLogFileSize; - if ((strcmp(configStr, "LOG_FLUSH_THRESHOLD") == 0) || (strcmp(configStr, "log_flush_threshold") == 0)) - return ConfigurationType::LogFlushThreshold; - return ConfigurationType::Unknown; - } - /// @brief Applies specified function to each configuration type starting from startIndex - /// @param startIndex initial value to start the iteration from. This is passed by pointer and is left-shifted - /// so this can be used inside function (fn) to represent current configuration type. - /// @param fn function to apply with each configuration type. - /// This bool represent whether or not to stop iterating through configurations. - static inline void forEachConfigType(base::type::EnumType* startIndex, const std::function& fn) { - base::type::EnumType cIndexMax = ConfigurationTypeHelper::kMaxValid; - do { - if (fn()) { - break; - } - *startIndex = static_cast(*startIndex << 1); - } while (*startIndex <= cIndexMax); - } - }; - /// @brief Flags used while writing logs. This flags are set by user - enum class LoggingFlag : base::type::EnumType { - /// @brief Makes sure we have new line for each container log entry - NewLineForContainer = 1, - /// @brief Makes sure if -vmodule is used and does not specifies a module, then verbose - /// logging is allowed via that module. - AllowVerboseIfModuleNotSpecified = 2, - /// @brief When handling crashes by default, detailed crash reason will be logged as well - LogDetailedCrashReason = 4, - /// @brief Allows to disable application abortion when logged using FATAL level - DisableApplicationAbortOnFatalLog = 8, - /// @brief Flushes log with every log-entry (performance sensative) - Disabled by default - ImmediateFlush = 16, - /// @brief Enables strict file rolling - StrictLogFileSizeCheck = 32, - /// @brief Make terminal output colorful for supported terminals - ColoredTerminalOutput = 64, - /// @brief Supports use of multiple logging in same macro, e.g, CLOG(INFO, "default", "network") - MultiLoggerSupport = 128, - /// @brief Disables comparing performance tracker's checkpoints - DisablePerformanceTrackingCheckpointComparison = 256, - /// @brief Disable VModules - DisableVModules = 512, - /// @brief Disable VModules extensions - DisableVModulesExtensions = 1024, - /// @brief Enables hierarchical logging - HierarchicalLogging = 2048, - /// @brief Creates logger automatically when not available - CreateLoggerAutomatically = 4096, - /// @brief Adds spaces b/w logs that separated by left-shift operator - AutoSpacing = 8192, - /// @brief Preserves time format and does not convert it to sec, hour etc (performance tracking only) - FixedTimeFormat = 16384 - }; - namespace base { - /// @brief Namespace containing constants used internally. - namespace consts { - // Level log values - These are values that are replaced in place of %level format specifier - static const base::type::char_t* kInfoLevelLogValue = ELPP_LITERAL("INFO "); - static const base::type::char_t* kDebugLevelLogValue = ELPP_LITERAL("DEBUG"); - static const base::type::char_t* kWarningLevelLogValue = ELPP_LITERAL("WARN "); - static const base::type::char_t* kErrorLevelLogValue = ELPP_LITERAL("ERROR"); - static const base::type::char_t* kFatalLevelLogValue = ELPP_LITERAL("FATAL"); - static const base::type::char_t* kVerboseLevelLogValue = ELPP_LITERAL("VER"); - static const base::type::char_t* kTraceLevelLogValue = ELPP_LITERAL("TRACE"); - static const base::type::char_t* kInfoLevelShortLogValue = ELPP_LITERAL("I"); - static const base::type::char_t* kDebugLevelShortLogValue = ELPP_LITERAL("D"); - static const base::type::char_t* kWarningLevelShortLogValue = ELPP_LITERAL("W"); - static const base::type::char_t* kErrorLevelShortLogValue = ELPP_LITERAL("E"); - static const base::type::char_t* kFatalLevelShortLogValue = ELPP_LITERAL("F"); - static const base::type::char_t* kVerboseLevelShortLogValue = ELPP_LITERAL("V"); - static const base::type::char_t* kTraceLevelShortLogValue = ELPP_LITERAL("T"); - // Format specifiers - These are used to define log format - static const base::type::char_t* kAppNameFormatSpecifier = ELPP_LITERAL("%app"); - static const base::type::char_t* kLoggerIdFormatSpecifier = ELPP_LITERAL("%logger"); - static const base::type::char_t* kThreadIdFormatSpecifier = ELPP_LITERAL("%thread"); - static const base::type::char_t* kSeverityLevelFormatSpecifier = ELPP_LITERAL("%level"); - static const base::type::char_t* kSeverityLevelShortFormatSpecifier = ELPP_LITERAL("%levshort"); - static const base::type::char_t* kDateTimeFormatSpecifier = ELPP_LITERAL("%datetime"); - static const base::type::char_t* kLogFileFormatSpecifier = ELPP_LITERAL("%file"); - static const base::type::char_t* kLogFileBaseFormatSpecifier = ELPP_LITERAL("%fbase"); - static const base::type::char_t* kLogLineFormatSpecifier = ELPP_LITERAL("%line"); - static const base::type::char_t* kLogLocationFormatSpecifier = ELPP_LITERAL("%loc"); - static const base::type::char_t* kLogFunctionFormatSpecifier = ELPP_LITERAL("%func"); - static const base::type::char_t* kCurrentUserFormatSpecifier = ELPP_LITERAL("%user"); - static const base::type::char_t* kCurrentHostFormatSpecifier = ELPP_LITERAL("%host"); - static const base::type::char_t* kMessageFormatSpecifier = ELPP_LITERAL("%msg"); - static const base::type::char_t* kVerboseLevelFormatSpecifier = ELPP_LITERAL("%vlevel"); - static const char* kDateTimeFormatSpecifierForFilename = "%datetime"; - // Date/time - static const char* kDays[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; - static const char* kDaysAbbrev[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; - static const char* kMonths[12] = { "January", "February", "March", "Apri", "May", "June", "July", "August", - "September", "October", "November", "December" }; - static const char* kMonthsAbbrev[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - static const char* kDefaultDateTimeFormat = "%Y-%M-%d %H:%m:%s,%g"; - static const char* kDefaultDateTimeFormatInFilename = "%Y-%M-%d_%H-%m"; - static const int kYearBase = 1900; - static const char* kAm = "AM"; - static const char* kPm = "PM"; - // Miscellaneous constants - static const char* kDefaultLoggerId = "default"; - static const char* kPerformanceLoggerId = "performance"; -#if defined(ELPP_SYSLOG) - static const char* kSysLogLoggerId = "syslog"; -#endif // defined(ELPP_SYSLOG) - static const char* kNullPointer = "nullptr"; - static const char kFormatSpecifierChar = '%'; -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED - static const char kFormatSpecifierCharValue = 'v'; -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED - static const unsigned int kMaxLogPerContainer = 100; - static const unsigned int kMaxLogPerCounter = 100000; - static const unsigned int kDefaultMillisecondsWidth = 3; - static const base::type::VerboseLevel kMaxVerboseLevel = 9; - static const char* kUnknownUser = "user"; - static const char* kUnknownHost = "unknown-host"; -#if defined(ELPP_DEFAULT_LOG_FILE) - static const char* kDefaultLogFile = ELPP_DEFAULT_LOG_FILE; -#else -# if ELPP_OS_UNIX -# if ELPP_OS_ANDROID - static const char* kDefaultLogFile = "logs/myeasylog.log"; -# else - static const char* kDefaultLogFile = "logs/myeasylog.log"; -# endif // ELPP_OS_ANDROID -# elif ELPP_OS_WINDOWS - static const char* kDefaultLogFile = "logs\\myeasylog.log"; -# endif // ELPP_OS_UNIX -#endif // defined(ELPP_DEFAULT_LOG_FILE) -#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) - static const char* kDefaultLogFileParam = "--default-log-file"; -#endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) -#if defined(ELPP_LOGGING_FLAGS_FROM_ARG) - static const char* kLoggingFlagsParam = "--logging-flags"; -#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) -#if ELPP_OS_WINDOWS - static const char* kFilePathSeperator = "\\"; -#else - static const char* kFilePathSeperator = "/"; -#endif // ELPP_OS_WINDOWS - static const char* kValidLoggerIdSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._"; - static const char* kConfigurationComment = "##"; - static const char* kConfigurationLevel = "*"; - static const char* kConfigurationLoggerId = "--"; - static const std::size_t kSourceFilenameMaxLength = 100; - static const std::size_t kSourceLineMaxLength = 10; - static const Level kPerformanceTrackerDefaultLevel = Level::Info; - const struct { - double value; - const base::type::char_t* unit; - } kTimeFormats[] = { - { 1000.0f, ELPP_LITERAL("mis") }, - { 1000.0f, ELPP_LITERAL("ms") }, - { 60.0f, ELPP_LITERAL("seconds") }, - { 60.0f, ELPP_LITERAL("minutes") }, - { 24.0f, ELPP_LITERAL("hours") }, - { 7.0f, ELPP_LITERAL("days") } - }; - static const int kTimeFormatsCount = sizeof(kTimeFormats) / sizeof(kTimeFormats[0]); - const struct { - int numb; - const char* name; - const char* brief; - const char* detail; - } kCrashSignals[] = { - // NOTE: Do not re-order, if you do please check CrashHandler(bool) constructor and CrashHandler::setHandler(..) - { SIGABRT, "SIGABRT", "Abnormal termination", - "Program was abnormally terminated." }, - { SIGFPE, "SIGFPE", "Erroneous arithmetic operation", - "Arithemetic operation issue such as division by zero or operation resulting in overflow." }, - { SIGILL, "SIGILL", "Illegal instruction", - "Generally due to a corruption in the code or to an attempt to execute data."}, - { SIGSEGV, "SIGSEGV", "Invalid access to memory", - "Program is trying to read an invalid (unallocated, deleted or corrupted) or inaccessible memory." }, - { SIGINT, "SIGINT", "Interactive attention signal", - "Interruption generated (generally) by user or operating system." }, - }; - static const int kCrashSignalsCount = sizeof(kCrashSignals) / sizeof(kCrashSignals[0]); - } // namespace consts - } // namespace base - typedef std::function PreRollOutCallback; - namespace base { - static inline void defaultPreRollOutCallback(const char*, std::size_t) {} - /// @brief Enum to represent timestamp unit - enum class TimestampUnit : base::type::EnumType { - Microsecond = 0, Millisecond = 1, Second = 2, Minute = 3, Hour = 4, Day = 5 - }; - /// @brief Format flags used to determine specifiers that are active for performance improvements. - enum class FormatFlags : base::type::EnumType { - DateTime = 1<<1, LoggerId = 1<<2, File = 1<<3, Line = 1<<4, Location = 1<<5, Function = 1<<6, - User = 1<<7, Host = 1<<8, LogMessage = 1<<9, VerboseLevel = 1<<10, AppName = 1<<11, ThreadId = 1<<12, - Level = 1<<13, FileBase = 1<<14, LevelShort = 1<<15 - }; - /// @brief A milliseconds width class containing actual width and offset for date/time - class MillisecondsWidth { - public: - MillisecondsWidth(void) { init(base::consts::kDefaultMillisecondsWidth); } - explicit MillisecondsWidth(int width) { init(width); } - bool operator==(const MillisecondsWidth& msWidth) { return m_width == msWidth.m_width && m_offset == msWidth.m_offset; } - int m_width; unsigned int m_offset; - private: - void init(int width) { - if (width < 1 || width > 6) { - width = base::consts::kDefaultMillisecondsWidth; - } - m_width = width; - switch (m_width) { - case 3: m_offset = 1000; break; - case 4: m_offset = 100; break; - case 5: m_offset = 10; break; - case 6: m_offset = 1; break; - default: m_offset = 1000; break; - } - } - }; - /// @brief Namespace containing utility functions/static classes used internally - namespace utils { - /// @brief Deletes memory safely and points to null - template - static inline - typename std::enable_if::value, void>::type - safeDelete(T*& pointer) { - if (pointer == nullptr) - return; - delete pointer; - pointer = nullptr; - } - /// @brief Gets value of const char* but if it is nullptr, a string nullptr is returned - static inline const char* charPtrVal(const char* pointer) { - return pointer == nullptr ? base::consts::kNullPointer : pointer; - } - /// @brief Aborts application due with user-defined status - static inline void abort(int status, const std::string& reason = std::string()) { - // Both status and reason params are there for debugging with tools like gdb etc - ELPP_UNUSED(status); - ELPP_UNUSED(reason); -#if defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG) - // Ignore msvc critical error dialog - break instead (on debug mode) - _asm int 3 -#else - ::abort(); -#endif // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG) - } - /// @brief Bitwise operations for C++11 strong enum class. This casts e into Flag_T and returns value after bitwise operation - /// Use these function as
flag = bitwise::Or(MyEnum::val1, flag);
- namespace bitwise { - template - static inline base::type::EnumType And(Enum e, base::type::EnumType flag) { - return static_cast(flag) & static_cast(e); - } - template - static inline base::type::EnumType Not(Enum e, base::type::EnumType flag) { - return static_cast(flag) & ~(static_cast(e)); - } - template - static inline base::type::EnumType Or(Enum e, base::type::EnumType flag) { - return static_cast(flag) | static_cast(e); - } - } // namespace bitwise - template - static inline void addFlag(Enum e, base::type::EnumType* flag) { - *flag = base::utils::bitwise::Or(e, *flag); - } - template - static inline void removeFlag(Enum e, base::type::EnumType* flag) { - *flag = base::utils::bitwise::Not(e, *flag); - } - template - static inline bool hasFlag(Enum e, base::type::EnumType flag) { - return base::utils::bitwise::And(e, flag) > 0x0; - } - } // namespace utils - namespace threading { -#if ELPP_THREADING_ENABLED -# if !ELPP_USE_STD_THREADING - namespace internal { - /// @brief A mutex wrapper for compiler that dont yet support std::mutex - class Mutex : base::NoCopy { - public: - Mutex(void) { -# if ELPP_OS_UNIX - pthread_mutex_init(&m_underlyingMutex, nullptr); -# elif ELPP_OS_WINDOWS - InitializeCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - virtual ~Mutex(void) { -# if ELPP_OS_UNIX - pthread_mutex_destroy(&m_underlyingMutex); -# elif ELPP_OS_WINDOWS - DeleteCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - inline void lock(void) { -# if ELPP_OS_UNIX - pthread_mutex_lock(&m_underlyingMutex); -# elif ELPP_OS_WINDOWS - EnterCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - inline bool try_lock(void) { -# if ELPP_OS_UNIX - return (pthread_mutex_trylock(&m_underlyingMutex) == 0); -# elif ELPP_OS_WINDOWS - return TryEnterCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - inline void unlock(void) { -# if ELPP_OS_UNIX - pthread_mutex_unlock(&m_underlyingMutex); -# elif ELPP_OS_WINDOWS - LeaveCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - private: -# if ELPP_OS_UNIX - pthread_mutex_t m_underlyingMutex; -# elif ELPP_OS_WINDOWS - CRITICAL_SECTION m_underlyingMutex; -# endif // ELPP_OS_UNIX - }; - /// @brief Scoped lock for compiler that dont yet support std::lock_guard - template - class ScopedLock : base::NoCopy { - public: - explicit ScopedLock(M& mutex) { - m_mutex = &mutex; - m_mutex->lock(); - } - - virtual ~ScopedLock(void) { - m_mutex->unlock(); - } - private: - M* m_mutex; - ScopedLock(void); - }; - } // namespace internal - /// @brief Gets ID of currently running threading in windows systems. On unix, nothing is returned. - static inline std::string getCurrentThreadId(void) { - std::stringstream ss; -# if (ELPP_OS_WINDOWS) - ss << GetCurrentThreadId(); -# endif // (ELPP_OS_WINDOWS) - return ss.str(); - } - static inline void msleep(int) { - // No implementation for non std::thread version - } - typedef base::threading::internal::Mutex Mutex; - typedef base::threading::internal::ScopedLock ScopedLock; -# else - /// @brief Gets ID of currently running threading using std::this_thread::get_id() - static inline std::string getCurrentThreadId(void) { - std::stringstream ss; - ss << std::this_thread::get_id(); - return ss.str(); - } - static inline void msleep(int ms) { - // Only when async logging enabled - this is because async is strict on compiler -# if ELPP_ASYNC_LOGGING -# if defined(ELPP_NO_SLEEP_FOR) - usleep(ms * 1000); -# else - std::this_thread::sleep_for(std::chrono::milliseconds(ms)); -# endif // defined(ELPP_NO_SLEEP_FOR) -# else - ELPP_UNUSED(ms); -# endif // ELPP_ASYNC_LOGGING - } - typedef std::mutex Mutex; - typedef std::lock_guard ScopedLock; -# endif // !ELPP_USE_STD_THREADING -#else - namespace internal { - /// @brief Mutex wrapper used when multi-threading is disabled. - class NoMutex : base::NoCopy { - public: - NoMutex(void) {} - inline void lock(void) {} - inline bool try_lock(void) { return true; } - inline void unlock(void) {} - }; - /// @brief Lock guard wrapper used when multi-threading is disabled. - template - class NoScopedLock : base::NoCopy { - public: - explicit NoScopedLock(Mutex&) { - } - virtual ~NoScopedLock(void) { - } - private: - NoScopedLock(void); - }; - } // namespace internal - static inline std::string getCurrentThreadId(void) { - return std::string(); - } - static inline void msleep(int) { - // No custom implementation - } - typedef base::threading::internal::NoMutex Mutex; - typedef base::threading::internal::NoScopedLock ScopedLock; -#endif // ELPP_THREADING_ENABLED - /// @brief Base of thread safe class, this class is inheritable-only - class ThreadSafe { - public: - virtual inline void acquireLock(void) ELPP_FINAL { m_mutex.lock(); } - virtual inline void releaseLock(void) ELPP_FINAL { m_mutex.unlock(); } - virtual inline base::threading::Mutex& lock(void) ELPP_FINAL { return m_mutex; } - protected: - ThreadSafe(void) {} - virtual ~ThreadSafe(void) {} - private: - base::threading::Mutex m_mutex; - }; - } // namespace threading - namespace utils { - class File : base::StaticClass { - public: - /// @brief Creates new out file stream for specified filename. - /// @return Pointer to newly created fstream or nullptr - static base::type::fstream_t* newFileStream(const std::string& filename) { - base::type::fstream_t *fs = new base::type::fstream_t(filename.c_str(), - base::type::fstream_t::out -#if !defined(ELPP_FRESH_LOG_FILE) - | base::type::fstream_t::app -#endif - ); -#if defined(ELPP_UNICODE) - std::locale elppUnicodeLocale(""); -# if ELPP_OS_WINDOWS - std::locale elppUnicodeLocaleWindows(elppUnicodeLocale, new std::codecvt_utf8_utf16); - elppUnicodeLocale = elppUnicodeLocaleWindows; -# endif // ELPP_OS_WINDOWS - fs->imbue(elppUnicodeLocale); -#endif // defined(ELPP_UNICODE) - if (fs->is_open()) { - fs->flush(); - } else { - base::utils::safeDelete(fs); - ELPP_INTERNAL_ERROR("Bad file [" << filename << "]", true); - } - return fs; - } - - /// @brief Gets size of file provided in stream - static std::size_t getSizeOfFile(base::type::fstream_t* fs) { - if (fs == nullptr) { - return 0; - } - std::streampos currPos = fs->tellg(); - fs->seekg(0, fs->end); - std::size_t size = static_cast(fs->tellg()); - fs->seekg(currPos); - return size; - } - - /// @brief Determines whether or not provided path exist in current file system - static inline bool pathExists(const char* path, bool considerFile = false) { - if (path == nullptr) { - return false; - } -#if ELPP_OS_UNIX - ELPP_UNUSED(considerFile); - struct stat st; - return (stat(path, &st) == 0); -#elif ELPP_OS_WINDOWS - DWORD fileType = GetFileAttributesA(path); - if (fileType == INVALID_FILE_ATTRIBUTES) { - return false; - } - return considerFile ? true : ((fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true); -#endif // ELPP_OS_UNIX - } - - /// @brief Creates specified path on file system - /// @param path Path to create. - static bool createPath(const std::string& path) { - if (path.empty()) { - return false; - } - if (base::utils::File::pathExists(path.c_str())) { - return true; - } - int status = -1; - - char* currPath = const_cast(path.c_str()); - std::string builtPath = std::string(); -#if ELPP_OS_UNIX - if (path[0] == '/') { - builtPath = "/"; - } - currPath = STRTOK(currPath, base::consts::kFilePathSeperator, 0); -#elif ELPP_OS_WINDOWS - // Use secure functions API - char* nextTok_ = nullptr; - currPath = STRTOK(currPath, base::consts::kFilePathSeperator, &nextTok_); - ELPP_UNUSED(nextTok_); -#endif // ELPP_OS_UNIX - while (currPath != nullptr) { - builtPath.append(currPath); - builtPath.append(base::consts::kFilePathSeperator); -#if ELPP_OS_UNIX - status = mkdir(builtPath.c_str(), ELPP_LOG_PERMS); - currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, 0); -#elif ELPP_OS_WINDOWS - status = _mkdir(builtPath.c_str()); - currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, &nextTok_); -#endif // ELPP_OS_UNIX - } - if (status == -1) { - ELPP_INTERNAL_ERROR("Error while creating path [" << path << "]", true); - return false; - } - return true; - } - /// @brief Extracts path of filename with leading slash - static std::string extractPathFromFilename(const std::string& fullPath, - const char* seperator = base::consts::kFilePathSeperator) { - if ((fullPath == "") || (fullPath.find(seperator) == std::string::npos)) { - return fullPath; - } - std::size_t lastSlashAt = fullPath.find_last_of(seperator); - if (lastSlashAt == 0) { - return std::string(seperator); - } - return fullPath.substr(0, lastSlashAt + 1); - } - /// @brief builds stripped filename and puts it in buff - static void buildStrippedFilename(const char* filename, char buff[], - std::size_t limit = base::consts::kSourceFilenameMaxLength) { - std::size_t sizeOfFilename = strlen(filename); - if (sizeOfFilename >= limit) { - filename += (sizeOfFilename - limit); - if (filename[0] != '.' && filename[1] != '.') { // prepend if not already - filename += 3; // 3 = '..' - STRCAT(buff, "..", limit); - } - } - STRCAT(buff, filename, limit); - } - /// @brief builds base filename and puts it in buff - static void buildBaseFilename(const std::string& fullPath, char buff[], - std::size_t limit = base::consts::kSourceFilenameMaxLength, - const char* seperator = base::consts::kFilePathSeperator) { - const char *filename = fullPath.c_str(); - std::size_t lastSlashAt = fullPath.find_last_of(seperator); - filename += lastSlashAt ? lastSlashAt+1 : 0; - std::size_t sizeOfFilename = strlen(filename); - if (sizeOfFilename >= limit) { - filename += (sizeOfFilename - limit); - if (filename[0] != '.' && filename[1] != '.') { // prepend if not already - filename += 3; // 3 = '..' - STRCAT(buff, "..", limit); - } - } - STRCAT(buff, filename, limit); - } - }; - /// @brief String utilities helper class used internally. You should not use it. - class Str : base::StaticClass { - public: - /// @brief Checks if character is digit. Dont use libc implementation of it to prevent locale issues. - static inline bool isDigit(char c) { - return c >= '0' && c <= '9'; - } - - /// @brief Matches wildcards, '*' and '?' only supported. - static bool wildCardMatch(const char* str, const char* pattern) { - while (*pattern) { - switch (*pattern) { - case '?': - if (!*str) - return false; - ++str; - ++pattern; - break; - case '*': - if (wildCardMatch(str, pattern + 1)) - return true; - if (*str && wildCardMatch(str + 1, pattern)) - return true; - return false; - default: - if (*str++ != *pattern++) - return false; - break; - } - } - return !*str && !*pattern; - } - - /// @brief Trims string from start - /// @param [in,out] str String to trim - static inline std::string& ltrim(std::string& str) { - str.erase(str.begin(), std::find_if(str.begin(), str.end(), std::not1(std::ptr_fun(&std::isspace)))); - return str; - } - - /// @brief Trim string from end - /// @param [in,out] str String to trim - static inline std::string& rtrim(std::string& str) { - str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::ptr_fun(&std::isspace))).base(), str.end()); - return str; - } - - /// @brief Trims string from left and right - /// @param [in,out] str String to trim - static inline std::string& trim(std::string& str) { - return ltrim(rtrim(str)); - } - - /// @brief Determines whether or not str starts with specified string - /// @param str String to check - /// @param start String to check against - /// @return Returns true if starts with specified string, false otherwise - static inline bool startsWith(const std::string& str, const std::string& start) { - return (str.length() >= start.length()) && (str.compare(0, start.length(), start) == 0); - } - - /// @brief Determines whether or not str ends with specified string - /// @param str String to check - /// @param end String to check against - /// @return Returns true if ends with specified string, false otherwise - static inline bool endsWith(const std::string& str, const std::string& end) { - return (str.length() >= end.length()) && (str.compare(str.length() - end.length(), end.length(), end) == 0); - } - - /// @brief Replaces all instances of replaceWhat with 'replaceWith'. Original variable is changed for performance. - /// @param [in,out] str String to replace from - /// @param replaceWhat Character to replace - /// @param replaceWith Character to replace with - /// @return Modified version of str - static inline std::string& replaceAll(std::string& str, char replaceWhat, char replaceWith) { - std::replace(str.begin(), str.end(), replaceWhat, replaceWith); - return str; - } - - /// @brief Replaces all instances of 'replaceWhat' with 'replaceWith'. (String version) Replaces in place - /// @param str String to replace from - /// @param replaceWhat Character to replace - /// @param replaceWith Character to replace with - /// @return Modified (original) str - static inline std::string& replaceAll(std::string& str, const std::string& replaceWhat, // NOLINT - const std::string& replaceWith) { - if (replaceWhat == replaceWith) - return str; - std::size_t foundAt = std::string::npos; - while ((foundAt = str.find(replaceWhat, foundAt + 1)) != std::string::npos) { - str.replace(foundAt, replaceWhat.length(), replaceWith); - } - return str; - } - - static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, // NOLINT - const base::type::string_t& replaceWith) { - std::size_t foundAt = base::type::string_t::npos; - while ((foundAt = str.find(replaceWhat, foundAt + 1)) != base::type::string_t::npos) { - if (foundAt > 0 && str[foundAt - 1] == base::consts::kFormatSpecifierChar) { - str.erase(foundAt > 0 ? foundAt - 1 : 0, 1); - ++foundAt; - } else { - str.replace(foundAt, replaceWhat.length(), replaceWith); - return; - } - } - } -#if defined(ELPP_UNICODE) - static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, // NOLINT - const std::string& replaceWith) { - replaceFirstWithEscape(str, replaceWhat, base::type::string_t(replaceWith.begin(), replaceWith.end())); - } -#endif // defined(ELPP_UNICODE) - /// @brief Converts string to uppercase - /// @param str String to convert - /// @return Uppercase string - static inline std::string& toUpper(std::string& str) { - std::transform(str.begin(), str.end(), str.begin(), ::toupper); - return str; - } - - /// @brief Compares cstring equality - uses strcmp - static inline bool cStringEq(const char* s1, const char* s2) { - if (s1 == nullptr && s2 == nullptr) return true; - if (s1 == nullptr || s2 == nullptr) return false; - return strcmp(s1, s2) == 0; - } - - /// @brief Compares cstring equality (case-insensitive) - uses toupper(char) - /// Dont use strcasecmp because of CRT (VC++) - static bool cStringCaseEq(const char* s1, const char* s2) { - if (s1 == nullptr && s2 == nullptr) return true; - if (s1 == nullptr || s2 == nullptr) return false; - if (strlen(s1) != strlen(s2)) return false; - while (*s1 != '\0' && *s2 != '\0') { - if (::toupper(*s1) != ::toupper(*s2)) return false; - ++s1; - ++s2; - } - return true; - } - - /// @brief Returns true if c exist in str - static inline bool contains(const char* str, char c) { - for (; *str; ++str) { - if (*str == c) - return true; - } - return false; - } - - static inline char* convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded = true) { - char localBuff[10] = ""; - char* p = localBuff + sizeof(localBuff) - 2; - if (n > 0) { - for (; n > 0 && p > localBuff && len > 0; n /= 10, --len) - *--p = static_cast(n % 10 + '0'); - } else { - *--p = '0'; - --len; - } - if (zeroPadded) - while (p > localBuff && len-- > 0) *--p = static_cast('0'); - return addToBuff(p, buf, bufLim); - } - - static inline char* addToBuff(const char* str, char* buf, const char* bufLim) { - while ((buf < bufLim) && ((*buf = *str++) != '\0')) - ++buf; - return buf; - } - - static inline char* clearBuff(char buff[], std::size_t lim) { - STRCPY(buff, "", lim); - ELPP_UNUSED(lim); // For *nix we dont have anything using lim in above STRCPY macro - return buff; - } - - /// @brief Converst wchar* to char* - /// NOTE: Need to free return value after use! - static char* wcharPtrToCharPtr(const wchar_t* line) { - std::size_t len_ = wcslen(line) + 1; - char* buff_ = static_cast(malloc(len_ + 1)); -# if ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS) - std::wcstombs(buff_, line, len_); -# elif ELPP_OS_WINDOWS - std::size_t convCount_ = 0; - mbstate_t mbState_; - ::memset(static_cast(&mbState_), 0, sizeof(mbState_)); - wcsrtombs_s(&convCount_, buff_, len_, &line, len_, &mbState_); -# endif // ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS) - return buff_; - } - }; - /// @brief Operating System helper static class used internally. You should not use it. - class OS : base::StaticClass { - public: -#if ELPP_OS_WINDOWS - /// @brief Gets environment variables for Windows based OS. - /// We are not using getenv(const char*) because of CRT deprecation - /// @param varname Variable name to get environment variable value for - /// @return If variable exist the value of it otherwise nullptr - static const char* getWindowsEnvironmentVariable(const char* varname) { - const DWORD bufferLen = 50; - static char buffer[bufferLen]; - if (GetEnvironmentVariableA(varname, buffer, bufferLen)) { - return buffer; - } - return nullptr; - } -#endif // ELPP_OS_WINDOWS -#if ELPP_OS_ANDROID - /// @brief Reads android property value - static inline std::string getProperty(const char* prop) { - char propVal[PROP_VALUE_MAX + 1]; - int ret = __system_property_get(prop, propVal); - return ret == 0 ? std::string() : std::string(propVal); - } - - /// @brief Reads android device name - static std::string getDeviceName(void) { - std::stringstream ss; - std::string manufacturer = getProperty("ro.product.manufacturer"); - std::string model = getProperty("ro.product.model"); - if (manufacturer.empty() || model.empty()) { - return std::string(); - } - ss << manufacturer << "-" << model; - return ss.str(); - } -#endif // ELPP_OS_ANDROID - - /// @brief Runs command on terminal and returns the output. - /// - /// @detail This is applicable only on unix based systems, for all other OS, an empty string is returned. - /// @param command Bash command - /// @return Result of bash output or empty string if no result found. - static const std::string getBashOutput(const char* command) { -#if (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN) - if (command == nullptr) { - return std::string(); - } - FILE* proc = nullptr; - if ((proc = popen(command, "r")) == nullptr) { - ELPP_INTERNAL_ERROR("\nUnable to run command [" << command << "]", true); - return std::string(); - } - char hBuff[4096]; - if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) { - pclose(proc); - if (hBuff[strlen(hBuff) - 1] == '\n') { - hBuff[strlen(hBuff) - 1] = '\0'; - } - return std::string(hBuff); - } - return std::string(); -#else - ELPP_UNUSED(command); - return std::string(); -#endif // (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN) - } - - /// @brief Gets environment variable. This is cross-platform and CRT safe (for VC++) - /// @param variableName Environment variable name - /// @param defaultVal If no environment variable or value found the value to return by default - /// @param alternativeBashCommand If environment variable not found what would be alternative bash command - /// in order to look for value user is looking for. E.g, for 'user' alternative command will 'whoami' - static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal, const char* alternativeBashCommand = nullptr) { -#if ELPP_OS_UNIX - const char* val = getenv(variableName); -#elif ELPP_OS_WINDOWS - const char* val = getWindowsEnvironmentVariable(variableName); -#endif // ELPP_OS_UNIX - if ((val == nullptr) || ((strcmp(val, "") == 0))) { -#if ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH) - // Try harder on unix-based systems - std::string valBash = base::utils::OS::getBashOutput(alternativeBashCommand); - if (valBash.empty()) { - return std::string(defaultVal); - } else { - return valBash; - } -#elif ELPP_OS_WINDOWS || ELPP_OS_UNIX - ELPP_UNUSED(alternativeBashCommand); - return std::string(defaultVal); -#endif // ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH) - } - return std::string(val); - } - /// @brief Gets current username. - static inline std::string currentUser(void) { -#if ELPP_OS_UNIX && !ELPP_OS_ANDROID - return getEnvironmentVariable("USER", base::consts::kUnknownUser, "whoami"); -#elif ELPP_OS_WINDOWS - return getEnvironmentVariable("USERNAME", base::consts::kUnknownUser); -#elif ELPP_OS_ANDROID - ELPP_UNUSED(base::consts::kUnknownUser); - return std::string("android"); -#else - return std::string(); -#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID - } - - /// @brief Gets current host name or computer name. - /// - /// @detail For android systems this is device name with its manufacturer and model seperated by hyphen - static inline std::string currentHost(void) { -#if ELPP_OS_UNIX && !ELPP_OS_ANDROID - return getEnvironmentVariable("HOSTNAME", base::consts::kUnknownHost, "hostname"); -#elif ELPP_OS_WINDOWS - return getEnvironmentVariable("COMPUTERNAME", base::consts::kUnknownHost); -#elif ELPP_OS_ANDROID - ELPP_UNUSED(base::consts::kUnknownHost); - return getDeviceName(); -#else - return std::string(); -#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID - } - /// @brief Whether or not terminal supports colors - static inline bool termSupportsColor(void) { - std::string term = getEnvironmentVariable("TERM", ""); - return term == "xterm" || term == "xterm-color" || term == "xterm-256color" - || term == "screen" || term == "linux" || term == "cygwin" - || term == "screen-256color"; - } - }; - extern std::string s_currentUser; - extern std::string s_currentHost; - extern bool s_termSupportsColor; -#define ELPP_INITI_BASIC_DECLR \ -namespace el {\ -namespace base {\ -namespace utils {\ -std::string s_currentUser = el::base::utils::OS::currentUser(); \ -std::string s_currentHost = el::base::utils::OS::currentHost(); \ -bool s_termSupportsColor = el::base::utils::OS::termSupportsColor(); \ -}\ -}\ -} - /// @brief Contains utilities for cross-platform date/time. This class make use of el::base::utils::Str - class DateTime : base::StaticClass { - public: - /// @brief Cross platform gettimeofday for Windows and unix platform. This can be used to determine current millisecond. - /// - /// @detail For unix system it uses gettimeofday(timeval*, timezone*) and for Windows, a seperate implementation is provided - /// @param [in,out] tv Pointer that gets updated - static void gettimeofday(struct timeval* tv) { -#if ELPP_OS_WINDOWS - if (tv != nullptr) { -# if ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS) - const unsigned __int64 delta_ = 11644473600000000Ui64; -# else - const unsigned __int64 delta_ = 11644473600000000ULL; -# endif // ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS) - const double secOffSet = 0.000001; - const unsigned long usecOffSet = 1000000; - FILETIME fileTime; - GetSystemTimeAsFileTime(&fileTime); - unsigned __int64 present = 0; - present |= fileTime.dwHighDateTime; - present = present << 32; - present |= fileTime.dwLowDateTime; - present /= 10; // mic-sec - // Subtract the difference - present -= delta_; - tv->tv_sec = static_cast(present * secOffSet); - tv->tv_usec = static_cast(present % usecOffSet); - } -#else - ::gettimeofday(tv, nullptr); -#endif // ELPP_OS_WINDOWS - } - - /// @brief Gets current date and time with milliseconds. - /// @param format User provided date/time format - /// @param msWidth A pointer to base::MillisecondsWidth from configuration (non-null) - /// @returns string based date time in specified format. - static inline std::string getDateTime(const char* format, const base::MillisecondsWidth* msWidth) { - struct timeval currTime; - gettimeofday(&currTime); - struct ::tm timeInfo; - buildTimeInfo(&currTime, &timeInfo); - const int kBuffSize = 30; - char buff_[kBuffSize] = ""; - parseFormat(buff_, kBuffSize, format, &timeInfo, static_cast(currTime.tv_usec / msWidth->m_offset), msWidth); - return std::string(buff_); - } - - /// @brief Formats time to get unit accordingly, units like second if > 1000 or minutes if > 60000 etc - static base::type::string_t formatTime(unsigned long long time, base::TimestampUnit timestampUnit) { - double result = static_cast(time); - base::type::EnumType start = static_cast(timestampUnit); - const base::type::char_t* unit = base::consts::kTimeFormats[start].unit; - for (base::type::EnumType i = start; i < base::consts::kTimeFormatsCount - 1; ++i) { - if (result <= base::consts::kTimeFormats[i].value) { - break; - } - result /= base::consts::kTimeFormats[i].value; - unit = base::consts::kTimeFormats[i + 1].unit; - } - base::type::stringstream_t ss; - ss << result << " " << unit; - return ss.str(); - } - - /// @brief Gets time difference in milli/micro second depending on timestampUnit - static inline unsigned long long getTimeDifference(const struct timeval& endTime, const struct timeval& startTime, base::TimestampUnit timestampUnit) { - if (timestampUnit == base::TimestampUnit::Microsecond) { - return static_cast(static_cast(1000000 * endTime.tv_sec + endTime.tv_usec) - - static_cast(1000000 * startTime.tv_sec + startTime.tv_usec)); - } else { - return static_cast((((endTime.tv_sec - startTime.tv_sec) * 1000000) + (endTime.tv_usec - startTime.tv_usec)) / 1000); - } - } - - private: - static inline struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo) { -#if ELPP_OS_UNIX - time_t rawTime = currTime->tv_sec; - ::localtime_r(&rawTime, timeInfo); - return timeInfo; -#else -# if ELPP_COMPILER_MSVC - ELPP_UNUSED(currTime); - time_t t; - _time64(&t); - localtime_s(timeInfo, &t); - return timeInfo; -# else - // For any other compilers that don't have CRT warnings issue e.g, MinGW or TDM GCC- we use different method - time_t rawTime = currTime->tv_sec; - struct tm* tmInf = localtime(&rawTime); - *timeInfo = *tmInf; - return timeInfo; -# endif // ELPP_COMPILER_MSVC -#endif // ELPP_OS_UNIX - } - static char* parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo, - std::size_t msec, const base::MillisecondsWidth* msWidth) { - const char* bufLim = buf + bufSz; - for (; *format; ++format) { - if (*format == base::consts::kFormatSpecifierChar) { - switch (*++format) { - case base::consts::kFormatSpecifierChar: // Escape - break; - case '\0': // End - --format; - break; - case 'd': // Day - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mday, 2, buf, bufLim); - continue; - case 'a': // Day of week (short) - buf = base::utils::Str::addToBuff(base::consts::kDaysAbbrev[tInfo->tm_wday], buf, bufLim); - continue; - case 'A': // Day of week (long) - buf = base::utils::Str::addToBuff(base::consts::kDays[tInfo->tm_wday], buf, bufLim); - continue; - case 'M': // month - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mon + 1, 2, buf, bufLim); - continue; - case 'b': // month (short) - buf = base::utils::Str::addToBuff(base::consts::kMonthsAbbrev[tInfo->tm_mon], buf, bufLim); - continue; - case 'B': // month (long) - buf = base::utils::Str::addToBuff(base::consts::kMonths[tInfo->tm_mon], buf, bufLim); - continue; - case 'y': // year (two digits) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 2, buf, bufLim); - continue; - case 'Y': // year (four digits) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 4, buf, bufLim); - continue; - case 'h': // hour (12-hour) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour % 12, 2, buf, bufLim); - continue; - case 'H': // hour (24-hour) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour, 2, buf, bufLim); - continue; - case 'm': // minute - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_min, 2, buf, bufLim); - continue; - case 's': // second - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_sec, 2, buf, bufLim); - continue; - case 'z': // milliseconds - case 'g': - buf = base::utils::Str::convertAndAddToBuff(msec, msWidth->m_width, buf, bufLim); - continue; - case 'F': // AM/PM - buf = base::utils::Str::addToBuff((tInfo->tm_hour >= 12) ? base::consts::kPm : base::consts::kAm, buf, bufLim); - continue; - default: - continue; - } - } - if (buf == bufLim) break; - *buf++ = *format; - } - return buf; - } - }; - /// @brief Command line arguments for application if specified using el::Helpers::setArgs(..) or START_EASYLOGGINGPP(..) - class CommandLineArgs { - public: - CommandLineArgs(void) { - setArgs(0, static_cast(nullptr)); - } - CommandLineArgs(int argc, const char** argv) { - setArgs(argc, argv); - } - CommandLineArgs(int argc, char** argv) { - setArgs(argc, argv); - } - virtual ~CommandLineArgs(void) {} - /// @brief Sets arguments and parses them - inline void setArgs(int argc, const char** argv) { - setArgs(argc, const_cast(argv)); - } - /// @brief Sets arguments and parses them - inline void setArgs(int argc, char** argv) { - m_params.clear(); - m_paramsWithValue.clear(); - if (argc == 0 || argv == nullptr) { - return; - } - m_argc = argc; - m_argv = argv; - for (int i = 1; i < m_argc; ++i) { - const char* v = (strstr(m_argv[i], "=")); - if (v != nullptr && strlen(v) > 0) { - std::string key = std::string(m_argv[i]); - key = key.substr(0, key.find_first_of('=')); - if (hasParamWithValue(key.c_str())) { - ELPP_INTERNAL_INFO(1, "Skipping [" << key << "] arg since it already has value [" - << getParamValue(key.c_str()) << "]"); - } else { - m_paramsWithValue.insert(std::make_pair(key, std::string(v + 1))); - } - } - if (v == nullptr) { - if (hasParam(m_argv[i])) { - ELPP_INTERNAL_INFO(1, "Skipping [" << m_argv[i] << "] arg since it already exists"); - } else { - m_params.push_back(std::string(m_argv[i])); - } - } - } - } - /// @brief Returns true if arguments contain paramKey with a value (seperated by '=') - inline bool hasParamWithValue(const char* paramKey) const { - return m_paramsWithValue.find(std::string(paramKey)) != m_paramsWithValue.end(); - } - /// @brief Returns value of arguments - /// @see hasParamWithValue(const char*) - inline const char* getParamValue(const char* paramKey) const { - return m_paramsWithValue.find(std::string(paramKey))->second.c_str(); - } - /// @brief Return true if arguments has a param (not having a value) i,e without '=' - inline bool hasParam(const char* paramKey) const { - return std::find(m_params.begin(), m_params.end(), std::string(paramKey)) != m_params.end(); - } - /// @brief Returns true if no params available. This exclude argv[0] - inline bool empty(void) const { - return m_params.empty() && m_paramsWithValue.empty(); - } - /// @brief Returns total number of arguments. This exclude argv[0] - inline std::size_t size(void) const { - return m_params.size() + m_paramsWithValue.size(); - } - inline friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c) { - for (int i = 1; i < c.m_argc; ++i) { - os << ELPP_LITERAL("[") << c.m_argv[i] << ELPP_LITERAL("]"); - if (i < c.m_argc - 1) { - os << ELPP_LITERAL(" "); - } - } - return os; - } - - private: - int m_argc; - char** m_argv; - std::map m_paramsWithValue; - std::vector m_params; - }; - /// @brief Abstract registry (aka repository) that provides basic interface for pointer repository specified by T_Ptr type. - /// - /// @detail Most of the functions are virtual final methods but anything implementing this abstract class should implement - /// unregisterAll() and deepCopy(const AbstractRegistry&) and write registerNew() method according to container - /// and few more methods; get() to find element, unregister() to unregister single entry. - /// Please note that this is thread-unsafe and should also implement thread-safety mechanisms in implementation. - template - class AbstractRegistry : public base::threading::ThreadSafe { - public: - typedef typename Container::iterator iterator; - typedef typename Container::const_iterator const_iterator; - - /// @brief Default constructor - AbstractRegistry(void) {} - - /// @brief Move constructor that is useful for base classes - AbstractRegistry(AbstractRegistry&& sr) { - if (this == &sr) { - return; - } - unregisterAll(); - m_list = std::move(sr.m_list); - } - - bool operator==(const AbstractRegistry& other) { - if (size() != other.size()) { - return false; - } - for (std::size_t i = 0; i < m_list.size(); ++i) { - if (m_list.at(i) != other.m_list.at(i)) { - return false; - } - } - return true; - } - - bool operator!=(const AbstractRegistry& other) { - if (size() != other.size()) { - return true; - } - for (std::size_t i = 0; i < m_list.size(); ++i) { - if (m_list.at(i) != other.m_list.at(i)) { - return true; - } - } - return false; - } - - /// @brief Assignment move operator - AbstractRegistry& operator=(AbstractRegistry&& sr) { - if (this == &sr) { - return *this; - } - unregisterAll(); - m_list = std::move(sr.m_list); - return *this; - } - - virtual ~AbstractRegistry(void) { - } - - /// @return Iterator pointer from start of repository - virtual inline iterator begin(void) ELPP_FINAL { - return m_list.begin(); - } - - /// @return Iterator pointer from end of repository - virtual inline iterator end(void) ELPP_FINAL { - return m_list.end(); - } - - - /// @return Constant iterator pointer from start of repository - virtual inline const_iterator cbegin(void) const ELPP_FINAL { - return m_list.cbegin(); - } - - /// @return End of repository - virtual inline const_iterator cend(void) const ELPP_FINAL { - return m_list.cend(); - } - - /// @return Whether or not repository is empty - virtual inline bool empty(void) const ELPP_FINAL { - return m_list.empty(); - } - - /// @return Size of repository - virtual inline std::size_t size(void) const ELPP_FINAL { - return m_list.size(); - } - - /// @brief Returns underlying container by reference - virtual inline Container& list(void) ELPP_FINAL { - return m_list; - } - - /// @brief Returns underlying container by constant reference. - virtual inline const Container& list(void) const ELPP_FINAL { - return m_list; - } - - /// @brief Unregisters all the pointers from current repository. - virtual void unregisterAll(void) = 0; - -protected: - virtual void deepCopy(const AbstractRegistry&) = 0; - void reinitDeepCopy(const AbstractRegistry& sr) { - unregisterAll(); - deepCopy(sr); - } - -private: - Container m_list; -}; - -/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (non-predicate version) -/// -/// @detail NOTE: This is thread-unsafe implementation (although it contains lock function, it does not use these functions) -/// of AbstractRegistry. Any implementation of this class should be -/// explicitly (by using lock functions) -template -class Registry : public AbstractRegistry> { -public: - typedef typename Registry::iterator iterator; - typedef typename Registry::const_iterator const_iterator; - - Registry(void) {} - - /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor. - Registry(const Registry& sr) : AbstractRegistry>() { - if (this == &sr) { - return; - } - this->reinitDeepCopy(sr); - } - - /// @brief Assignment operator that unregisters all the existing registeries and deeply copies each of repo element - /// @see unregisterAll() - /// @see deepCopy(const AbstractRegistry&) - Registry& operator=(const Registry& sr) { - if (this == &sr) { - return *this; - } - this->reinitDeepCopy(sr); - return *this; - } - - virtual ~Registry(void) { - unregisterAll(); - } - -protected: - virtual inline void unregisterAll(void) ELPP_FINAL { - if (!this->empty()) { - for (auto&& curr : this->list()) { - base::utils::safeDelete(curr.second); - } - this->list().clear(); - } -} - -/// @brief Registers new registry to repository. -virtual inline void registerNew(const T_Key& uniqKey, T_Ptr* ptr) ELPP_FINAL { -unregister(uniqKey); -this->list().insert(std::make_pair(uniqKey, ptr)); -} - -/// @brief Unregisters single entry mapped to specified unique key -inline void unregister(const T_Key& uniqKey) { - T_Ptr* existing = get(uniqKey); - if (existing != nullptr) { - base::utils::safeDelete(existing); - this->list().erase(uniqKey); - } -} - -/// @brief Gets pointer from repository. If none found, nullptr is returned. -inline T_Ptr* get(const T_Key& uniqKey) { - iterator it = this->list().find(uniqKey); - return it == this->list().end() - ? nullptr - : it->second; -} - -private: -virtual inline void deepCopy(const AbstractRegistry>& sr) ELPP_FINAL { -for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it) { - registerNew(it->first, new T_Ptr(*it->second)); -} -} -}; - -/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (predicate version) -/// -/// @detail NOTE: This is thread-unsafe implementation of AbstractRegistry. Any implementation of this class -/// should be made thread-safe explicitly -template -class RegistryWithPred : public AbstractRegistry> { -public: - typedef typename RegistryWithPred::iterator iterator; - typedef typename RegistryWithPred::const_iterator const_iterator; - - RegistryWithPred(void) { - } - - virtual ~RegistryWithPred(void) { - unregisterAll(); - } - - /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor. - RegistryWithPred(const RegistryWithPred& sr) : AbstractRegistry>() { - if (this == &sr) { - return; - } - this->reinitDeepCopy(sr); - } - - /// @brief Assignment operator that unregisters all the existing registeries and deeply copies each of repo element - /// @see unregisterAll() - /// @see deepCopy(const AbstractRegistry&) - RegistryWithPred& operator=(const RegistryWithPred& sr) { - if (this == &sr) { - return *this; - } - this->reinitDeepCopy(sr); - return *this; - } - - friend inline base::type::ostream_t& operator<<(base::type::ostream_t& os, const RegistryWithPred& sr) { - for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) { - os << ELPP_LITERAL(" ") << **it << ELPP_LITERAL("\n"); - } - return os; - } - -protected: - virtual inline void unregisterAll(void) ELPP_FINAL { - if (!this->empty()) { - for (auto&& curr : this->list()) { - base::utils::safeDelete(curr); - } - this->list().clear(); - } -} - -virtual void unregister(T_Ptr*& ptr) ELPP_FINAL { -if (ptr) { - iterator iter = this->begin(); - for (; iter != this->end(); ++iter) { - if (ptr == *iter) { - break; - } - } - if (iter != this->end() && *iter != nullptr) { - this->list().erase(iter); - base::utils::safeDelete(*iter); - } -} -} - -virtual inline void registerNew(T_Ptr* ptr) ELPP_FINAL { -this->list().push_back(ptr); -} - -/// @brief Gets pointer from repository with speicifed arguments. Arguments are passed to predicate -/// in order to validate pointer. -template -inline T_Ptr* get(const T& arg1, const T2 arg2) { - iterator iter = std::find_if(this->list().begin(), this->list().end(), Pred(arg1, arg2)); - if (iter != this->list().end() && *iter != nullptr) { - return *iter; - } - return nullptr; -} - -private: -virtual inline void deepCopy(const AbstractRegistry>& sr) { - for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) { - registerNew(new T_Ptr(**it)); - } -} -}; - -} // namespace utils -} // namespace base -/// @brief Base of Easylogging++ friendly class -/// -/// @detail After inheriting this class publicly, implement pure-virtual function `void log(std::ostream&) const` -class Loggable { -public: - virtual ~Loggable(void) {} - virtual void log(el::base::type::ostream_t&) const = 0; -private: - friend inline el::base::type::ostream_t& operator<<(el::base::type::ostream_t& os, const Loggable& loggable) { - loggable.log(os); - return os; - } -}; -namespace base { - /// @brief Represents log format containing flags and date format. This is used internally to start initial log - class LogFormat : public Loggable { - public: - LogFormat(void) : - m_level(Level::Unknown), - m_userFormat(base::type::string_t()), - m_format(base::type::string_t()), - m_dateTimeFormat(std::string()), - m_flags(0x0) { - } - - LogFormat(Level level, const base::type::string_t& format) - : m_level(level), m_userFormat(format) { - parseFromFormat(m_userFormat); - } - - LogFormat(const LogFormat& logFormat) { - m_level = logFormat.m_level; - m_userFormat = logFormat.m_userFormat; - m_format = logFormat.m_format; - m_dateTimeFormat = logFormat.m_dateTimeFormat; - m_flags = logFormat.m_flags; - } - - LogFormat(LogFormat&& logFormat) { - m_level = std::move(logFormat.m_level); - m_userFormat = std::move(logFormat.m_userFormat); - m_format = std::move(logFormat.m_format); - m_dateTimeFormat = std::move(logFormat.m_dateTimeFormat); - m_flags = std::move(logFormat.m_flags); - } - - LogFormat& operator=(const LogFormat& logFormat) { - m_level = logFormat.m_level; - m_userFormat = logFormat.m_userFormat; - m_dateTimeFormat = logFormat.m_dateTimeFormat; - m_flags = logFormat.m_flags; - return *this; - } - - virtual ~LogFormat(void) { - } - - inline bool operator==(const LogFormat& other) { - return m_level == other.m_level && m_userFormat == other.m_userFormat && m_format == other.m_format && - m_dateTimeFormat == other.m_dateTimeFormat && m_flags == other.m_flags; - } - - /// @brief Updates format to be used while logging. - /// @param userFormat User provided format - void parseFromFormat(const base::type::string_t& userFormat) { - // We make copy because we will be changing the format - // i.e, removing user provided date format from original format - // and then storing it. - base::type::string_t formatCopy = userFormat; - m_flags = 0x0; - auto conditionalAddFlag = [&](const base::type::char_t* specifier, base::FormatFlags flag) { - std::size_t foundAt = base::type::string_t::npos; - while ((foundAt = formatCopy.find(specifier, foundAt + 1)) != base::type::string_t::npos){ - if (foundAt > 0 && formatCopy[foundAt - 1] == base::consts::kFormatSpecifierChar) { - if (hasFlag(flag)) { - // If we already have flag we remove the escape chars so that '%%' is turned to '%' - // even after specifier resolution - this is because we only replaceFirst specifier - formatCopy.erase(foundAt > 0 ? foundAt - 1 : 0, 1); - ++foundAt; - } - } else { - if (!hasFlag(flag)) addFlag(flag); - } - } - }; - conditionalAddFlag(base::consts::kAppNameFormatSpecifier, base::FormatFlags::AppName); - conditionalAddFlag(base::consts::kSeverityLevelFormatSpecifier, base::FormatFlags::Level); - conditionalAddFlag(base::consts::kSeverityLevelShortFormatSpecifier, base::FormatFlags::LevelShort); - conditionalAddFlag(base::consts::kLoggerIdFormatSpecifier, base::FormatFlags::LoggerId); - conditionalAddFlag(base::consts::kThreadIdFormatSpecifier, base::FormatFlags::ThreadId); - conditionalAddFlag(base::consts::kLogFileFormatSpecifier, base::FormatFlags::File); - conditionalAddFlag(base::consts::kLogFileBaseFormatSpecifier, base::FormatFlags::FileBase); - conditionalAddFlag(base::consts::kLogLineFormatSpecifier, base::FormatFlags::Line); - conditionalAddFlag(base::consts::kLogLocationFormatSpecifier, base::FormatFlags::Location); - conditionalAddFlag(base::consts::kLogFunctionFormatSpecifier, base::FormatFlags::Function); - conditionalAddFlag(base::consts::kCurrentUserFormatSpecifier, base::FormatFlags::User); - conditionalAddFlag(base::consts::kCurrentHostFormatSpecifier, base::FormatFlags::Host); - conditionalAddFlag(base::consts::kMessageFormatSpecifier, base::FormatFlags::LogMessage); - conditionalAddFlag(base::consts::kVerboseLevelFormatSpecifier, base::FormatFlags::VerboseLevel); - // For date/time we need to extract user's date format first - std::size_t dateIndex = std::string::npos; - if ((dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier)) != std::string::npos) { - while (dateIndex > 0 && formatCopy[dateIndex - 1] == base::consts::kFormatSpecifierChar) { - dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier, dateIndex + 1); - } - if (dateIndex != std::string::npos) { - addFlag(base::FormatFlags::DateTime); - updateDateFormat(dateIndex, formatCopy); - } - } - m_format = formatCopy; - updateFormatSpec(); - } - - inline Level level(void) const { - return m_level; - } - - inline const base::type::string_t& userFormat(void) const { - return m_userFormat; - } - - inline const base::type::string_t& format(void) const { - return m_format; - } - - inline const std::string& dateTimeFormat(void) const { - return m_dateTimeFormat; - } - - inline base::type::EnumType flags(void) const { - return m_flags; - } - - inline bool hasFlag(base::FormatFlags flag) const { - return base::utils::hasFlag(flag, m_flags); - } - - virtual void log(el::base::type::ostream_t& os) const { - os << m_format; - } - - protected: - /// @brief Updates date time format if available in currFormat. - /// @param index Index where %datetime, %date or %time was found - /// @param [in,out] currFormat current format that is being used to format - virtual void updateDateFormat(std::size_t index, base::type::string_t& currFormat) ELPP_FINAL { - if (hasFlag(base::FormatFlags::DateTime)) { - index += ELPP_STRLEN(base::consts::kDateTimeFormatSpecifier); - } - const base::type::char_t* ptr = currFormat.c_str() + index; - if ((currFormat.size() > index) && (ptr[0] == '{')) { - // User has provided format for date/time - ++ptr; - int count = 1; // Start by 1 in order to remove starting brace - std::stringstream ss; - for (; *ptr; ++ptr, ++count) { - if (*ptr == '}') { - ++count; // In order to remove ending brace - break; - } - ss << *ptr; - } - currFormat.erase(index, count); - m_dateTimeFormat = ss.str(); - } else { - // No format provided, use default - if (hasFlag(base::FormatFlags::DateTime)) { - m_dateTimeFormat = std::string(base::consts::kDefaultDateTimeFormat); - } - } - } - - /// @brief Updates %level from format. This is so that we dont have to do it at log-writing-time. It uses m_format and m_level - virtual void updateFormatSpec(void) ELPP_FINAL { - // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. - if (m_level == Level::Debug) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kDebugLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kDebugLevelShortLogValue); - } else if (m_level == Level::Info) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kInfoLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kInfoLevelShortLogValue); - } else if (m_level == Level::Warning) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kWarningLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kWarningLevelShortLogValue); - } else if (m_level == Level::Error) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kErrorLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kErrorLevelShortLogValue); - } else if (m_level == Level::Fatal) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kFatalLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kFatalLevelShortLogValue); - } else if (m_level == Level::Verbose) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kVerboseLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kVerboseLevelShortLogValue); - } else if (m_level == Level::Trace) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kTraceLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kTraceLevelShortLogValue); - } - if (hasFlag(base::FormatFlags::User)) { - std::string s = base::utils::s_currentUser; - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentUserFormatSpecifier, - base::utils::s_currentUser); - } - if (hasFlag(base::FormatFlags::Host)) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentHostFormatSpecifier, - base::utils::s_currentHost); - } - // Ignore Level::Global and Level::Unknown - } - - inline void addFlag(base::FormatFlags flag) { - base::utils::addFlag(flag, &m_flags); - } - - private: - Level m_level; - base::type::string_t m_userFormat; - base::type::string_t m_format; - std::string m_dateTimeFormat; - base::type::EnumType m_flags; - friend class el::Logger; // To resolve loggerId format specifier easily - }; -} // namespace base -/// @brief Resolving function for format specifier -typedef std::function FormatSpecifierValueResolver; -/// @brief User-provided custom format specifier -/// @see el::Helpers::installCustomFormatSpecifier -/// @see FormatSpecifierValueResolver -class CustomFormatSpecifier { -public: - CustomFormatSpecifier(const char* formatSpecifier, const FormatSpecifierValueResolver& resolver) : - m_formatSpecifier(formatSpecifier), m_resolver(resolver) {} - inline const char* formatSpecifier(void) const { return m_formatSpecifier; } - inline const FormatSpecifierValueResolver& resolver(void) const { return m_resolver; } - inline bool operator==(const char* formatSpecifier) { - return strcmp(m_formatSpecifier, formatSpecifier) == 0; - } - -private: - const char* m_formatSpecifier; - FormatSpecifierValueResolver m_resolver; -}; -/// @brief Represents single configuration that has representing level, configuration type and a string based value. -/// -/// @detail String based value means any value either its boolean, integer or string itself, it will be embedded inside quotes -/// and will be parsed later. -/// -/// Consider some examples below: -/// * el::Configuration confEnabledInfo(el::Level::Info, el::ConfigurationType::Enabled, "true"); -/// * el::Configuration confMaxLogFileSizeInfo(el::Level::Info, el::ConfigurationType::MaxLogFileSize, "2048"); -/// * el::Configuration confFilenameInfo(el::Level::Info, el::ConfigurationType::Filename, "/var/log/my.log"); -class Configuration : public Loggable { -public: - Configuration(const Configuration& c) : - m_level(c.m_level), - m_configurationType(c.m_configurationType), - m_value(c.m_value) { - } - - Configuration& operator=(const Configuration& c) { - m_level = c.m_level; - m_configurationType = c.m_configurationType; - m_value = c.m_value; - return *this; - } - - virtual ~Configuration(void) { - } - - /// @brief Full constructor used to sets value of configuration - Configuration(Level level, ConfigurationType configurationType, const std::string& value) : - m_level(level), - m_configurationType(configurationType), - m_value(value) { - } - - /// @brief Gets level of current configuration - inline Level level(void) const { - return m_level; - } - - /// @brief Gets configuration type of current configuration - inline ConfigurationType configurationType(void) const { - return m_configurationType; - } - - /// @brief Gets string based configuration value - inline const std::string& value(void) const { - return m_value; - } - - /// @brief Set string based configuration value - /// @param value Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values - /// use them in quotes. They will be parsed when configuring - inline void setValue(const std::string& value) { - m_value = value; - } - - virtual inline void log(el::base::type::ostream_t& os) const { - os << LevelHelper::convertToString(m_level) - << ELPP_LITERAL(" ") << ConfigurationTypeHelper::convertToString(m_configurationType) - << ELPP_LITERAL(" = ") << m_value.c_str(); - } - - /// @brief Used to find configuration from configuration (pointers) repository. Avoid using it. - class Predicate { - public: - Predicate(Level level, ConfigurationType configurationType) : - m_level(level), - m_configurationType(configurationType) { - } - - inline bool operator()(const Configuration* conf) const { - return ((conf != nullptr) && (conf->level() == m_level) && (conf->configurationType() == m_configurationType)); - } - - private: - Level m_level; - ConfigurationType m_configurationType; - }; - -private: - Level m_level; - ConfigurationType m_configurationType; - std::string m_value; -}; - -/// @brief Thread-safe Configuration repository -/// -/// @detail This repository represents configurations for all the levels and configuration type mapped to a value. -class Configurations : public base::utils::RegistryWithPred { -public: - /// @brief Default constructor with empty repository - Configurations(void) : - m_configurationFile(std::string()), - m_isFromFile(false) { - } - - /// @brief Constructor used to set configurations using configuration file. - /// @param configurationFile Full path to configuration file - /// @param useDefaultsForRemaining Lets you set the remaining configurations to default. - /// @param base If provided, this configuration will be based off existing repository that this argument is pointing to. - /// @see parseFromFile(const std::string&, Configurations* base) - /// @see setRemainingToDefault() - Configurations(const std::string& configurationFile, bool useDefaultsForRemaining = true, Configurations* base = nullptr) : - m_configurationFile(configurationFile), - m_isFromFile(false) { - parseFromFile(configurationFile, base); - if (useDefaultsForRemaining) { - setRemainingToDefault(); - } - } - - virtual ~Configurations(void) { - } - - /// @brief Parses configuration from file. - /// @param configurationFile Full path to configuration file - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration file. - /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you - /// do not proceed without successful parse. - inline bool parseFromFile(const std::string& configurationFile, Configurations* base = nullptr) { - // We initial assertion with true because if we have assertion diabled, we want to pass this - // check and if assertion is enabled we will have values re-assigned any way. - bool assertionPassed = true; - ELPP_ASSERT((assertionPassed = base::utils::File::pathExists(configurationFile.c_str(), true)), - "Configuration file [" << configurationFile << "] does not exist!"); - if (!assertionPassed) { - return false; - } - bool success = Parser::parseFromFile(configurationFile, this, base); - m_isFromFile = success; - return success; - } - - /// @brief Parse configurations from configuration string. - /// - /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary - /// new line characters are provided. - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration text. - /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you - /// do not proceed without successful parse. - inline bool parseFromText(const std::string& configurationsString, Configurations* base = nullptr) { - bool success = Parser::parseFromText(configurationsString, this, base); - if (success) { - m_isFromFile = false; - } - return success; - } - - /// @brief Sets configuration based-off an existing configurations. - /// @param base Pointer to existing configurations. - inline void setFromBase(Configurations* base) { - if (base == nullptr || base == this) { - return; - } - base::threading::ScopedLock scopedLock(base->lock()); - for (Configuration*& conf : base->list()) { - set(conf); - } - } - - /// @brief Determines whether or not specified configuration type exists in the repository. - /// - /// @detail Returns as soon as first level is found. - /// @param configurationType Type of configuration to check existence for. - bool hasConfiguration(ConfigurationType configurationType) { - base::type::EnumType lIndex = LevelHelper::kMinValid; - bool result = false; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - if (hasConfiguration(LevelHelper::castFromInt(lIndex), configurationType)) { - result = true; - } - return result; - }); - return result; - } - - /// @brief Determines whether or not specified configuration type exists for specified level - /// @param level Level to check - /// @param configurationType Type of configuration to check existence for. - inline bool hasConfiguration(Level level, ConfigurationType configurationType) { - base::threading::ScopedLock scopedLock(lock()); -#if ELPP_COMPILER_INTEL - // We cant specify template types here, Intel C++ throws compilation error - // "error: type name is not allowed" - return RegistryWithPred::get(level, configurationType) != nullptr; -#else - return RegistryWithPred::get(level, configurationType) != nullptr; -#endif // ELPP_COMPILER_INTEL - } - - /// @brief Sets value of configuration for specified level. - /// - /// @detail Any existing configuration for specified level will be replaced. Also note that configuration types - /// ConfigurationType::MillisecondsWidth and ConfigurationType::PerformanceTracking will be ignored if not set for - /// Level::Global because these configurations are not dependant on level. - /// @param level Level to set configuration for (el::Level). - /// @param configurationType Type of configuration (el::ConfigurationType) - /// @param value A string based value. Regardless of what the data type of configuration is, it will always be string - /// from users' point of view. This is then parsed later to be used internally. - /// @see Configuration::setValue(const std::string& value) - /// @see el::Level - /// @see el::ConfigurationType - inline void set(Level level, ConfigurationType configurationType, const std::string& value) { - base::threading::ScopedLock scopedLock(lock()); - unsafeSet(level, configurationType, value); // This is not unsafe anymore as we have locked mutex - if (level == Level::Global) { - unsafeSetGlobally(configurationType, value, false); // Again this is not unsafe either - } - } - - /// @brief Sets single configuration based on other single configuration. - /// @see set(Level level, ConfigurationType configurationType, const std::string& value) - inline void set(Configuration* conf) { - if (conf == nullptr) { - return; - } - set(conf->level(), conf->configurationType(), conf->value()); - } - - inline Configuration* get(Level level, ConfigurationType configurationType) { - base::threading::ScopedLock scopedLock(lock()); - return RegistryWithPred::get(level, configurationType); - } - - /// @brief Sets configuration for all levels. - /// @param configurationType Type of configuration - /// @param value String based value - /// @see Configurations::set(Level level, ConfigurationType configurationType, const std::string& value) - inline void setGlobally(ConfigurationType configurationType, const std::string& value) { - setGlobally(configurationType, value, false); - } - - /// @brief Clears repository so that all the configurations are unset - inline void clear(void) { - base::threading::ScopedLock scopedLock(lock()); - unregisterAll(); - } - - /// @brief Gets configuration file used in parsing this configurations. - /// - /// @detail If this repository was set manually or by text this returns empty string. - inline const std::string& configurationFile(void) const { - return m_configurationFile; - } - - /// @brief Sets configurations to "factory based" configurations. - void setToDefault(void) { - setGlobally(ConfigurationType::Enabled, std::string("true"), true); -#if !defined(ELPP_NO_DEFAULT_LOG_FILE) - setGlobally(ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile), true); -#else - ELPP_UNUSED(base::consts::kDefaultLogFile); -#endif // !defined(ELPP_NO_DEFAULT_LOG_FILE) - setGlobally(ConfigurationType::ToFile, std::string("true"), true); - setGlobally(ConfigurationType::ToStandardOutput, std::string("true"), true); - setGlobally(ConfigurationType::MillisecondsWidth, std::string("3"), true); - setGlobally(ConfigurationType::PerformanceTracking, std::string("true"), true); - setGlobally(ConfigurationType::MaxLogFileSize, std::string("0"), true); - setGlobally(ConfigurationType::LogFlushThreshold, std::string("0"), true); - - setGlobally(ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"), true); - set(Level::Debug, ConfigurationType::Format, std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg")); - // INFO and WARNING are set to default by Level::Global - set(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - set(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - set(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg")); - set(Level::Trace, ConfigurationType::Format, std::string("%datetime %level [%logger] [%func] [%loc] %msg")); - } - - /// @brief Lets you set the remaining configurations to default. - /// - /// @detail By remaining, it means that the level/type a configuration does not exist for. - /// This function is useful when you want to minimize chances of failures, e.g, if you have a configuration file that sets - /// configuration for all the configurations except for Enabled or not, we use this so that ENABLED is set to default i.e, - /// true. If you dont do this explicitley (either by calling this function or by using second param in Constructor - /// and try to access a value, an error is thrown - void setRemainingToDefault(void) { - base::threading::ScopedLock scopedLock(lock()); - unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("true")); -#if !defined(ELPP_NO_DEFAULT_LOG_FILE) - unsafeSetIfNotExist(Level::Global, ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile)); -#endif // !defined(ELPP_NO_DEFAULT_LOG_FILE) - unsafeSetIfNotExist(Level::Global, ConfigurationType::ToFile, std::string("true")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::ToStandardOutput, std::string("true")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::MillisecondsWidth, std::string("3")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::PerformanceTracking, std::string("true")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::MaxLogFileSize, std::string("0")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist(Level::Debug, ConfigurationType::Format, - std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg")); - // INFO and WARNING are set to default by Level::Global - unsafeSetIfNotExist(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg")); - unsafeSetIfNotExist(Level::Trace, ConfigurationType::Format, std::string("%datetime %level [%logger] [%func] [%loc] %msg")); - } - - /// @brief Parser used internally to parse configurations from file or text. - /// - /// @detail This class makes use of base::utils::Str. - /// You should not need this unless you are working on some tool for Easylogging++ - class Parser : base::StaticClass { - public: - /// @brief Parses configuration from file. - /// @param configurationFile Full path to configuration file - /// @param sender Sender configurations pointer. Usually 'this' is used from calling class - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration file. - /// @return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you - /// do not proceed without successful parse. - static bool parseFromFile(const std::string& configurationFile, Configurations* sender, Configurations* base = nullptr) { - sender->setFromBase(base); - std::ifstream fileStream_(configurationFile.c_str(), std::ifstream::in); - ELPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file [" << configurationFile << "] for parsing."); - bool parsedSuccessfully = false; - std::string line = std::string(); - Level currLevel = Level::Unknown; - std::string currConfigStr = std::string(); - std::string currLevelStr = std::string(); - while (fileStream_.good()) { - std::getline(fileStream_, line); - parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender); - ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line); - } - return parsedSuccessfully; - } - - /// @brief Parse configurations from configuration string. - /// - /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary - /// new line characters are provided. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you - /// do not proceed without successful parse (This is recommended) - /// @param configurationsString - /// @param sender Sender configurations pointer. Usually 'this' is used from calling class - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration text. - /// @return True if successfully parsed, false otherwise. - static bool parseFromText(const std::string& configurationsString, Configurations* sender, Configurations* base = nullptr) { - sender->setFromBase(base); - bool parsedSuccessfully = false; - std::stringstream ss(configurationsString); - std::string line = std::string(); - Level currLevel = Level::Unknown; - std::string currConfigStr = std::string(); - std::string currLevelStr = std::string(); - while (std::getline(ss, line)) { - parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender); - ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line); - } - return parsedSuccessfully; - } - - private: - friend class el::Loggers; - static void ignoreComments(std::string* line) { - std::size_t foundAt = 0; - std::size_t quotesStart = line->find("\""); - std::size_t quotesEnd = std::string::npos; - if (quotesStart != std::string::npos) { - quotesEnd = line->find("\"", quotesStart + 1); - while (quotesEnd != std::string::npos && line->at(quotesEnd - 1) == '\\') { - // Do not erase slash yet - we will erase it in parseLine(..) while loop - quotesEnd = line->find("\"", quotesEnd + 2); - } - } - if ((foundAt = line->find(base::consts::kConfigurationComment)) != std::string::npos) { - if (foundAt < quotesEnd) { - foundAt = line->find(base::consts::kConfigurationComment, quotesEnd + 1); - } - *line = line->substr(0, foundAt); - } - } - static inline bool isLevel(const std::string& line) { - return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLevel)); - } - - static inline bool isComment(const std::string& line) { - return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationComment)); - } - - static inline bool isConfig(const std::string& line) { - std::size_t assignment = line.find('='); - return line != "" && - ((line[0] >= 65 && line[0] <= 90) || (line[0] >= 97 && line[0] <= 122)) && - (assignment != std::string::npos) && - (line.size() > assignment); - } - - static bool parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, Level* currLevel, Configurations* conf) { - ConfigurationType currConfig = ConfigurationType::Unknown; - std::string currValue = std::string(); - *line = base::utils::Str::trim(*line); - if (isComment(*line)) return true; - ignoreComments(line); - *line = base::utils::Str::trim(*line); - if (line->empty()) { - // Comment ignored - return true; - } - if (isLevel(*line)) { - if (line->size() <= 2) { - return true; - } - *currLevelStr = line->substr(1, line->size() - 2); - *currLevelStr = base::utils::Str::toUpper(*currLevelStr); - *currLevelStr = base::utils::Str::trim(*currLevelStr); - *currLevel = LevelHelper::convertFromString(currLevelStr->c_str()); - return true; - } - if (isConfig(*line)) { - std::size_t assignment = line->find('='); - *currConfigStr = line->substr(0, assignment); - *currConfigStr = base::utils::Str::toUpper(*currConfigStr); - *currConfigStr = base::utils::Str::trim(*currConfigStr); - currConfig = ConfigurationTypeHelper::convertFromString(currConfigStr->c_str()); - currValue = line->substr(assignment + 1); - currValue = base::utils::Str::trim(currValue); - std::size_t quotesStart = currValue.find("\"", 0); - std::size_t quotesEnd = std::string::npos; - if (quotesStart != std::string::npos) { - quotesEnd = currValue.find("\"", quotesStart + 1); - while (quotesEnd != std::string::npos && currValue.at(quotesEnd - 1) == '\\') { - currValue = currValue.erase(quotesEnd - 1, 1); - quotesEnd = currValue.find("\"", quotesEnd + 2); - } - } - if (quotesStart != std::string::npos && quotesEnd != std::string::npos) { - // Quote provided - check and strip if valid - ELPP_ASSERT((quotesStart < quotesEnd), "Configuration error - No ending quote found in [" - << currConfigStr << "]"); - ELPP_ASSERT((quotesStart + 1 != quotesEnd), "Empty configuration value for [" << currConfigStr << "]"); - if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) { - // Explicit check in case if assertion is disabled - currValue = currValue.substr(quotesStart + 1, quotesEnd - 1); - } - } - } - ELPP_ASSERT(*currLevel != Level::Unknown, "Unrecognized severity level [" << *currLevelStr << "]"); - ELPP_ASSERT(currConfig != ConfigurationType::Unknown, "Unrecognized configuration [" << *currConfigStr << "]"); - if (*currLevel == Level::Unknown || currConfig == ConfigurationType::Unknown) { - return false; // unrecognizable level or config - } - conf->set(*currLevel, currConfig, currValue); - return true; - } - }; - -private: - std::string m_configurationFile; - bool m_isFromFile; - friend class el::Loggers; - - /// @brief Unsafely sets configuration if does not already exist - void unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value) { - Configuration* conf = RegistryWithPred::get(level, configurationType); - if (conf == nullptr) { - unsafeSet(level, configurationType, value); - } - } - - /// @brief Thread unsafe set - void unsafeSet(Level level, ConfigurationType configurationType, const std::string& value) { - Configuration* conf = RegistryWithPred::get(level, configurationType); - if (conf == nullptr) { - registerNew(new Configuration(level, configurationType, value)); - } else { - conf->setValue(value); - } - if (level == Level::Global) { - unsafeSetGlobally(configurationType, value, false); - } - } - - /// @brief Sets configurations for all levels including Level::Global if includeGlobalLevel is true - /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value) - void setGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel) { - if (includeGlobalLevel) { - set(Level::Global, configurationType, value); - } - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - set(LevelHelper::castFromInt(lIndex), configurationType, value); - return false; // Do not break lambda function yet as we need to set all levels regardless - }); - } - - /// @brief Sets configurations (Unsafely) for all levels including Level::Global if includeGlobalLevel is true - /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value) - void unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel) { - if (includeGlobalLevel) { - unsafeSet(Level::Global, configurationType, value); - } - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - unsafeSet(LevelHelper::castFromInt(lIndex), configurationType, value); - return false; // Do not break lambda function yet as we need to set all levels regardless - }); - } -}; - -namespace base { - typedef std::shared_ptr FileStreamPtr; - typedef std::map LogStreamsReferenceMap; - /// @brief Configurations with data types. - /// - /// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations. - /// This is to perform faster while writing logs using correct configurations. - /// - /// This is thread safe and final class containing non-virtual destructor (means nothing should inherit this class) - class TypedConfigurations : public base::threading::ThreadSafe { - public: - /// @brief Constructor to initialize (construct) the object off el::Configurations - /// @param configurations Configurations pointer/reference to base this typed configurations off. - /// @param logStreamsReference Use ELPP->registeredLoggers()->logStreamsReference() - TypedConfigurations(Configurations* configurations, base::LogStreamsReferenceMap* logStreamsReference) { - m_configurations = configurations; - m_logStreamsReference = logStreamsReference; - build(m_configurations); - } - - TypedConfigurations(const TypedConfigurations& other) { - this->m_configurations = other.m_configurations; - this->m_logStreamsReference = other.m_logStreamsReference; - build(m_configurations); - } - - virtual ~TypedConfigurations(void) { - } - - const Configurations* configurations(void) const { - return m_configurations; - } - - inline bool enabled(Level level) { - return getConfigByVal(level, &m_enabledMap, "enabled"); - } - - inline bool toFile(Level level) { - return getConfigByVal(level, &m_toFileMap, "toFile"); - } - - inline const std::string& filename(Level level) { - return getConfigByRef(level, &m_filenameMap, "filename"); - } - - inline bool toStandardOutput(Level level) { - return getConfigByVal(level, &m_toStandardOutputMap, "toStandardOutput"); - } - - inline const base::LogFormat& logFormat(Level level) { - return getConfigByRef(level, &m_logFormatMap, "logFormat"); - } - - inline const base::MillisecondsWidth& millisecondsWidth(Level level = Level::Global) { - return getConfigByRef(level, &m_millisecondsWidthMap, "millisecondsWidth"); - } - - inline bool performanceTracking(Level level = Level::Global) { - return getConfigByVal(level, &m_performanceTrackingMap, "performanceTracking"); - } - - inline base::type::fstream_t* fileStream(Level level) { - return getConfigByRef(level, &m_fileStreamMap, "fileStream").get(); - } - - inline std::size_t maxLogFileSize(Level level) { - return getConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize"); - } - - inline std::size_t logFlushThreshold(Level level) { - return getConfigByVal(level, &m_logFlushThresholdMap, "logFlushThreshold"); - } - - private: - Configurations* m_configurations; - std::map m_enabledMap; - std::map m_toFileMap; - std::map m_filenameMap; - std::map m_toStandardOutputMap; - std::map m_logFormatMap; - std::map m_millisecondsWidthMap; - std::map m_performanceTrackingMap; - std::map m_fileStreamMap; - std::map m_maxLogFileSizeMap; - std::map m_logFlushThresholdMap; - base::LogStreamsReferenceMap* m_logStreamsReference; - - friend class el::Helpers; - friend class el::base::MessageBuilder; - friend class el::base::Writer; - friend class el::base::DefaultLogDispatchCallback; - friend class el::base::LogDispatcher; - - template - inline Conf_T getConfigByVal(Level level, const std::map* confMap, const char* confName) { - base::threading::ScopedLock scopedLock(lock()); - return unsafeGetConfigByVal(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope - } - - template - inline Conf_T& getConfigByRef(Level level, std::map* confMap, const char* confName) { - base::threading::ScopedLock scopedLock(lock()); - return unsafeGetConfigByRef(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope - } - - template - inline Conf_T unsafeGetConfigByVal(Level level, const std::map* confMap, const char* confName) { - ELPP_UNUSED(confName); - typename std::map::const_iterator it = confMap->find(level); - if (it == confMap->end()) { - try { - return confMap->at(Level::Global); - } catch (...) { - ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level [" - << LevelHelper::convertToString(level) << "]" - << std::endl << "Please ensure you have properly configured logger.", false); - return Conf_T(); - } - } - return it->second; - } - - template - inline Conf_T& unsafeGetConfigByRef(Level level, std::map* confMap, const char* confName) { - ELPP_UNUSED(confName); - typename std::map::iterator it = confMap->find(level); - if (it == confMap->end()) { - try { - return confMap->at(Level::Global); - } catch (...) { - ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level [" - << LevelHelper::convertToString(level) << "]" - << std::endl << "Please ensure you have properly configured logger.", false); - } - } - return it->second; - } - - template - void setValue(Level level, const Conf_T& value, std::map* confMap, bool includeGlobalLevel = true) { - // If map is empty and we are allowed to add into generic level (Level::Global), do it! - if (confMap->empty() && includeGlobalLevel) { - confMap->insert(std::make_pair(Level::Global, value)); - return; - } - // If same value exist in generic level already, dont add it to explicit level - typename std::map::iterator it = confMap->find(Level::Global); - if (it != confMap->end() && it->second == value) { - return; - } - // Now make sure we dont double up values if we really need to add it to explicit level - it = confMap->find(level); - if (it == confMap->end()) { - // Value not found for level, add new - confMap->insert(std::make_pair(level, value)); - } else { - // Value found, just update value - confMap->at(level) = value; - } - } - - void build(Configurations* configurations) { - base::threading::ScopedLock scopedLock(lock()); - auto getBool = [] (std::string boolStr) -> bool { // Pass by value for trimming - base::utils::Str::trim(boolStr); - return (boolStr == "TRUE" || boolStr == "true" || boolStr == "1"); - }; - std::vector withFileSizeLimit; - for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) { - Configuration* conf = *it; - // We cannot use switch on strong enums because Intel C++ dont support them yet - if (conf->configurationType() == ConfigurationType::Enabled) { - setValue(conf->level(), getBool(conf->value()), &m_enabledMap); - } else if (conf->configurationType() == ConfigurationType::ToFile) { - setValue(conf->level(), getBool(conf->value()), &m_toFileMap); - } else if (conf->configurationType() == ConfigurationType::ToStandardOutput) { - setValue(conf->level(), getBool(conf->value()), &m_toStandardOutputMap); - } else if (conf->configurationType() == ConfigurationType::Filename) { - // We do not yet configure filename but we will configure in another - // loop. This is because if file cannot be created, we will force ToFile - // to be false. Because configuring logger is not necessarily performance - // sensative operation, we can live with another loop; (by the way this loop - // is not very heavy either) - } else if (conf->configurationType() == ConfigurationType::Format) { - setValue(conf->level(), base::LogFormat(conf->level(), - base::type::string_t(conf->value().begin(), conf->value().end())), &m_logFormatMap); - } else if (conf->configurationType() == ConfigurationType::MillisecondsWidth) { - setValue(Level::Global, - base::MillisecondsWidth(static_cast(getULong(conf->value()))), &m_millisecondsWidthMap); - } else if (conf->configurationType() == ConfigurationType::PerformanceTracking) { - setValue(Level::Global, getBool(conf->value()), &m_performanceTrackingMap); - } else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) { - setValue(conf->level(), static_cast(getULong(conf->value())), &m_maxLogFileSizeMap); -#if !defined(ELPP_NO_DEFAULT_LOG_FILE) - withFileSizeLimit.push_back(conf); -#endif // !defined(ELPP_NO_DEFAULT_LOG_FILE) - } else if (conf->configurationType() == ConfigurationType::LogFlushThreshold) { - setValue(conf->level(), static_cast(getULong(conf->value())), &m_logFlushThresholdMap); - } - } - // As mentioned early, we will now set filename configuration in separate loop to deal with non-existent files - for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) { - Configuration* conf = *it; - if (conf->configurationType() == ConfigurationType::Filename) { - insertFile(conf->level(), conf->value()); - } - } - for (std::vector::iterator conf = withFileSizeLimit.begin(); - conf != withFileSizeLimit.end(); ++conf) { - // This is not unsafe as mutex is locked in currect scope - unsafeValidateFileRolling((*conf)->level(), base::defaultPreRollOutCallback); - } - } - - unsigned long getULong(std::string confVal) { - bool valid = true; - base::utils::Str::trim(confVal); - valid = !confVal.empty() && std::find_if(confVal.begin(), confVal.end(), - [](char c) { return !base::utils::Str::isDigit(c); }) == confVal.end(); - if (!valid) { - valid = false; - ELPP_ASSERT(valid, "Configuration value not a valid integer [" << confVal << "]"); - return 0; - } - return atol(confVal.c_str()); - } - - std::string resolveFilename(const std::string& filename) { - std::string resultingFilename = filename; - std::size_t dateIndex = std::string::npos; - std::string dateTimeFormatSpecifierStr = std::string(base::consts::kDateTimeFormatSpecifierForFilename); - if ((dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str())) != std::string::npos) { - while (dateIndex > 0 && resultingFilename[dateIndex - 1] == base::consts::kFormatSpecifierChar) { - dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str(), dateIndex + 1); - } - if (dateIndex != std::string::npos) { - const char* ptr = resultingFilename.c_str() + dateIndex; - // Goto end of specifier - ptr += dateTimeFormatSpecifierStr.size(); - std::string fmt; - if ((resultingFilename.size() > dateIndex) && (ptr[0] == '{')) { - // User has provided format for date/time - ++ptr; - int count = 1; // Start by 1 in order to remove starting brace - std::stringstream ss; - for (; *ptr; ++ptr, ++count) { - if (*ptr == '}') { - ++count; // In order to remove ending brace - break; - } - ss << *ptr; - } - resultingFilename.erase(dateIndex + dateTimeFormatSpecifierStr.size(), count); - fmt = ss.str(); - } else { - fmt = std::string(base::consts::kDefaultDateTimeFormatInFilename); - } - base::MillisecondsWidth msWidth(3); - std::string now = base::utils::DateTime::getDateTime(fmt.c_str(), &msWidth); - base::utils::Str::replaceAll(now, '/', '-'); // Replace path element since we are dealing with filename - base::utils::Str::replaceAll(resultingFilename, dateTimeFormatSpecifierStr, now); - } - } - return resultingFilename; - } - - void insertFile(Level level, const std::string& fullFilename) { - std::string resolvedFilename = resolveFilename(fullFilename); - if (resolvedFilename.empty()) { - std::cerr << "Could not load empty file for logging, please re-check your configurations for level [" - << LevelHelper::convertToString(level) << "]"; - } - std::string filePath = base::utils::File::extractPathFromFilename(resolvedFilename, base::consts::kFilePathSeperator); - if (filePath.size() < resolvedFilename.size()) { - base::utils::File::createPath(filePath); - } - auto create = [&](Level level) { - base::LogStreamsReferenceMap::iterator filestreamIter = m_logStreamsReference->find(resolvedFilename); - base::type::fstream_t* fs = nullptr; - if (filestreamIter == m_logStreamsReference->end()) { - // We need a completely new stream, nothing to share with - fs = base::utils::File::newFileStream(resolvedFilename); - m_filenameMap.insert(std::make_pair(level, resolvedFilename)); - m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(fs))); - m_logStreamsReference->insert(std::make_pair(resolvedFilename, base::FileStreamPtr(m_fileStreamMap.at(level)))); - } else { - // Woops! we have an existing one, share it! - m_filenameMap.insert(std::make_pair(level, filestreamIter->first)); - m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(filestreamIter->second))); - fs = filestreamIter->second.get(); - } - if (fs == nullptr) { - // We display bad file error from newFileStream() - ELPP_INTERNAL_ERROR("Setting [TO_FILE] of [" - << LevelHelper::convertToString(level) << "] to FALSE", false); - setValue(level, false, &m_toFileMap); - } - }; - // If we dont have file conf for any level, create it for Level::Global first - // otherwise create for specified level - create(m_filenameMap.empty() && m_fileStreamMap.empty() ? Level::Global : level); - } - - bool unsafeValidateFileRolling(Level level, const PreRollOutCallback& PreRollOutCallback) { - base::type::fstream_t* fs = unsafeGetConfigByRef(level, &m_fileStreamMap, "fileStream").get(); - if (fs == nullptr) { - return true; - } - std::size_t maxLogFileSize = unsafeGetConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize"); - std::size_t currFileSize = base::utils::File::getSizeOfFile(fs); - if (maxLogFileSize != 0 && currFileSize >= maxLogFileSize) { - std::string fname = unsafeGetConfigByRef(level, &m_filenameMap, "filename"); - ELPP_INTERNAL_INFO(1, "Truncating log file [" << fname << "] as a result of configurations for level [" - << LevelHelper::convertToString(level) << "]"); - fs->close(); - PreRollOutCallback(fname.c_str(), currFileSize); - fs->open(fname, std::fstream::out | std::fstream::trunc); - return true; - } - return false; - } - - bool validateFileRolling(Level level, const PreRollOutCallback& PreRollOutCallback) { - base::threading::ScopedLock scopedLock(lock()); - return unsafeValidateFileRolling(level, PreRollOutCallback); - } - }; - /// @brief Class that keeps record of current line hit for occasional logging - class HitCounter { - public: - HitCounter(void) : - m_filename(""), - m_lineNumber(0), - m_hitCounts(0) { - } - - HitCounter(const char* filename, unsigned long int lineNumber) : - m_filename(filename), - m_lineNumber(lineNumber), - m_hitCounts(0) { - } - - HitCounter(const HitCounter& hitCounter) : - m_filename(hitCounter.m_filename), - m_lineNumber(hitCounter.m_lineNumber), - m_hitCounts(hitCounter.m_hitCounts) { - } - - HitCounter& operator=(const HitCounter& hitCounter) { - m_filename = hitCounter.m_filename; - m_lineNumber = hitCounter.m_lineNumber; - m_hitCounts = hitCounter.m_hitCounts; - return *this; - } - - virtual ~HitCounter(void) { - } - - /// @brief Resets location of current hit counter - inline void resetLocation(const char* filename, unsigned long int lineNumber) { - m_filename = filename; - m_lineNumber = lineNumber; - } - - /// @brief Validates hit counts and resets it if necessary - inline void validateHitCounts(std::size_t n) { - if (m_hitCounts >= base::consts::kMaxLogPerCounter) { - m_hitCounts = (n >= 1 ? base::consts::kMaxLogPerCounter % n : 0); - } - ++m_hitCounts; - } - - inline const char* filename(void) const { - return m_filename; - } - - inline unsigned long int lineNumber(void) const { - return m_lineNumber; - } - - inline std::size_t hitCounts(void) const { - return m_hitCounts; - } - - inline void increment(void) { - ++m_hitCounts; - } - - class Predicate { - public: - Predicate(const char* filename, unsigned long int lineNumber) - : m_filename(filename), - m_lineNumber(lineNumber) { - } - inline bool operator()(const HitCounter* counter) { - return ((counter != nullptr) && - (strcmp(counter->m_filename, m_filename) == 0) && - (counter->m_lineNumber == m_lineNumber)); - } - - private: - const char* m_filename; - unsigned long int m_lineNumber; - }; - - private: - const char* m_filename; - unsigned long int m_lineNumber; - std::size_t m_hitCounts; - }; - /// @brief Repository for hit counters used across the application - class RegisteredHitCounters : public base::utils::RegistryWithPred { - public: - /// @brief Validates counter for every N, i.e, registers new if does not exist otherwise updates original one - /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned - bool validateEveryN(const char* filename, unsigned long int lineNumber, std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter* counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - counter->validateHitCounts(n); - bool result = (n >= 1 && counter->hitCounts() != 0 && counter->hitCounts() % n == 0); - return result; - } - - /// @brief Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one - /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned - bool validateAfterN(const char* filename, unsigned long int lineNumber, std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter* counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - // Do not use validateHitCounts here since we do not want to reset counter here - // Note the >= instead of > because we are incrementing - // after this check - if (counter->hitCounts() >= n) - return true; - counter->increment(); - return false; - } - - /// @brief Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original one - /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned - bool validateNTimes(const char* filename, unsigned long int lineNumber, std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter* counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - counter->increment(); - // Do not use validateHitCounts here since we do not want to reset counter here - if (counter->hitCounts() <= n) - return true; - return false; - } - - /// @brief Gets hit counter registered at specified position - inline const base::HitCounter* getCounter(const char* filename, unsigned long int lineNumber) { - base::threading::ScopedLock scopedLock(lock()); - return get(filename, lineNumber); - } - }; - /// @brief Action to be taken for dispatching - enum class DispatchAction : base::type::EnumType { - None = 1, NormalLog = 2, SysLog = 4 - }; - } // namespace base - template - class Callback : protected base::threading::ThreadSafe { - public: - Callback(void) : m_enabled(true) {} - inline bool enabled(void) const { return m_enabled; } - inline void setEnabled(bool enabled) { - base::threading::ScopedLock scopedLock(lock()); - m_enabled = enabled; - } - protected: - virtual void handle(const T* handlePtr) = 0; - private: - bool m_enabled; - }; - class LogDispatchData { - public: - LogDispatchData() : m_logMessage(nullptr), m_dispatchAction(base::DispatchAction::None) {} - inline const LogMessage* logMessage(void) const { return m_logMessage; } - inline base::DispatchAction dispatchAction(void) const { return m_dispatchAction; } - private: - LogMessage* m_logMessage; - base::DispatchAction m_dispatchAction; - friend class base::LogDispatcher; - - inline void setLogMessage(LogMessage* logMessage) { m_logMessage = logMessage; } - inline void setDispatchAction(base::DispatchAction dispatchAction) { m_dispatchAction = dispatchAction; } - }; - class LogDispatchCallback : public Callback { - private: - friend class base::LogDispatcher; - }; - class PerformanceTrackingCallback : public Callback { - private: - friend class base::PerformanceTracker; - }; - class LogBuilder : base::NoCopy { - public: - virtual ~LogBuilder(void) { ELPP_INTERNAL_INFO(3, "Destroying log builder...")} - virtual base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const = 0; - void convertToColoredOutput(base::type::string_t* logLine, Level level) { - if (!base::utils::s_termSupportsColor) return; - const base::type::char_t* resetColor = ELPP_LITERAL("\x1b[0m"); - if (level == Level::Error || level == Level::Fatal) - *logLine = ELPP_LITERAL("\x1b[31m") + *logLine + resetColor; - else if (level == Level::Warning) - *logLine = ELPP_LITERAL("\x1b[33m") + *logLine + resetColor; - else if (level == Level::Debug) - *logLine = ELPP_LITERAL("\x1b[32m") + *logLine + resetColor; - else if (level == Level::Info) - *logLine = ELPP_LITERAL("\x1b[36m") + *logLine + resetColor; - else if (level == Level::Trace) - *logLine = ELPP_LITERAL("\x1b[35m") + *logLine + resetColor; - } - private: - friend class el::base::DefaultLogDispatchCallback; - }; - typedef std::shared_ptr LogBuilderPtr; - /// @brief Represents a logger holding ID and configurations we need to write logs - /// - /// @detail This class does not write logs itself instead its used by writer to read configuations from. - class Logger : public base::threading::ThreadSafe, public Loggable { - public: - Logger(const std::string& id, base::LogStreamsReferenceMap* logStreamsReference) : - m_id(id), - m_typedConfigurations(nullptr), - m_parentApplicationName(std::string()), - m_isConfigured(false), - m_logStreamsReference(logStreamsReference) { - initUnflushedCount(); - } - - Logger(const std::string& id, const Configurations& configurations, base::LogStreamsReferenceMap* logStreamsReference) : - m_id(id), - m_typedConfigurations(nullptr), - m_parentApplicationName(std::string()), - m_isConfigured(false), - m_logStreamsReference(logStreamsReference) { - initUnflushedCount(); - configure(configurations); - } - - Logger(const Logger& logger) { - base::utils::safeDelete(m_typedConfigurations); - m_id = logger.m_id; - m_typedConfigurations = logger.m_typedConfigurations; - m_parentApplicationName = logger.m_parentApplicationName; - m_isConfigured = logger.m_isConfigured; - m_configurations = logger.m_configurations; - m_unflushedCount = logger.m_unflushedCount; - m_logStreamsReference = logger.m_logStreamsReference; - } - - Logger& operator=(const Logger& logger) { - base::utils::safeDelete(m_typedConfigurations); - m_id = logger.m_id; - m_typedConfigurations = logger.m_typedConfigurations; - m_parentApplicationName = logger.m_parentApplicationName; - m_isConfigured = logger.m_isConfigured; - m_configurations = logger.m_configurations; - m_unflushedCount = logger.m_unflushedCount; - m_logStreamsReference = logger.m_logStreamsReference; - return *this; - } - - virtual ~Logger(void) { - base::utils::safeDelete(m_typedConfigurations); - } - - virtual inline void log(el::base::type::ostream_t& os) const { - os << m_id.c_str(); - } - - /// @brief Configures the logger using specified configurations. - void configure(const Configurations& configurations) { - m_isConfigured = false; // we set it to false in case if we fail - initUnflushedCount(); - if (m_typedConfigurations != nullptr) { - Configurations* c = const_cast(m_typedConfigurations->configurations()); - if (c->hasConfiguration(Level::Global, ConfigurationType::Filename)) { - // This check is definitely needed for cases like ELPP_NO_DEFAULT_LOG_FILE - flush(); - } - } - base::threading::ScopedLock scopedLock(lock()); - if (m_configurations != configurations) { - m_configurations.setFromBase(const_cast(&configurations)); - } - base::utils::safeDelete(m_typedConfigurations); - m_typedConfigurations = new base::TypedConfigurations(&m_configurations, m_logStreamsReference); - resolveLoggerFormatSpec(); - m_isConfigured = true; - } - - /// @brief Reconfigures logger using existing configurations - inline void reconfigure(void) { - ELPP_INTERNAL_INFO(1, "Reconfiguring logger [" << m_id << "]"); - configure(m_configurations); - } - - inline const std::string& id(void) const { - return m_id; - } - - inline const std::string& parentApplicationName(void) const { - return m_parentApplicationName; - } - - inline void setParentApplicationName(const std::string& parentApplicationName) { - m_parentApplicationName = parentApplicationName; - } - - inline Configurations* configurations(void) { - return &m_configurations; - } - - inline base::TypedConfigurations* typedConfigurations(void) { - return m_typedConfigurations; - } - - static inline bool isValidId(const std::string& id) { - for (std::string::const_iterator it = id.begin(); it != id.end(); ++it) { - if (!base::utils::Str::contains(base::consts::kValidLoggerIdSymbols, *it)) { - return false; - } - } - return true; - } - /// @brief Flushes logger to sync all log files for all levels - inline void flush(void) { - ELPP_INTERNAL_INFO(3, "Flushing logger [" << m_id << "] all levels"); - base::threading::ScopedLock scopedLock(lock()); - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - flush(LevelHelper::castFromInt(lIndex), nullptr); - return false; - }); - } - - inline void flush(Level level, base::type::fstream_t* fs) { - if (fs == nullptr && m_typedConfigurations->toFile(level)) { - fs = m_typedConfigurations->fileStream(level); - } - if (fs != nullptr) { - fs->flush(); - m_unflushedCount.find(level)->second = 0; - } - } - - inline bool isFlushNeeded(Level level) { - return ++m_unflushedCount.find(level)->second >= m_typedConfigurations->logFlushThreshold(level); - } - - inline LogBuilder* logBuilder(void) const { - return m_logBuilder.get(); - } - - inline void setLogBuilder(const LogBuilderPtr& logBuilder) { - m_logBuilder = logBuilder; - } - - inline bool enabled(Level level) const { - return m_typedConfigurations->enabled(level); - } - -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED -# define LOGGER_LEVEL_WRITERS_SIGNATURES(FUNCTION_NAME)\ -template \ -inline void FUNCTION_NAME(const char*, const T&, const Args&...);\ -template \ -inline void FUNCTION_NAME(const T&); - - template - inline void verbose(int, const char*, const T&, const Args&...); - - template - inline void verbose(int, const T&); - - LOGGER_LEVEL_WRITERS_SIGNATURES(info) - LOGGER_LEVEL_WRITERS_SIGNATURES(debug) - LOGGER_LEVEL_WRITERS_SIGNATURES(warn) - LOGGER_LEVEL_WRITERS_SIGNATURES(error) - LOGGER_LEVEL_WRITERS_SIGNATURES(fatal) - LOGGER_LEVEL_WRITERS_SIGNATURES(trace) -# undef LOGGER_LEVEL_WRITERS_SIGNATURES -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED - private: - std::string m_id; - base::TypedConfigurations* m_typedConfigurations; - base::type::stringstream_t m_stream; - std::string m_parentApplicationName; - bool m_isConfigured; - Configurations m_configurations; - std::map m_unflushedCount; - base::LogStreamsReferenceMap* m_logStreamsReference; - LogBuilderPtr m_logBuilder; - - friend class el::LogMessage; - friend class el::Loggers; - friend class el::Helpers; - friend class el::base::RegisteredLoggers; - friend class el::base::DefaultLogDispatchCallback; - friend class el::base::MessageBuilder; - friend class el::base::Writer; - friend class el::base::PErrorWriter; - friend class el::base::Storage; - friend class el::base::PerformanceTracker; - friend class el::base::LogDispatcher; - - Logger(void); - -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED - template - void log_(Level, int, const char*, const T&, const Args&...); - - template - inline void log_(Level, int, const T&); - - template - void log(Level, const char*, const T&, const Args&...); - - template - inline void log(Level, const T&); -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED - - void initUnflushedCount(void) { - m_unflushedCount.clear(); - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - m_unflushedCount.insert(std::make_pair(LevelHelper::castFromInt(lIndex), 0)); - return false; - }); - } - - inline base::type::stringstream_t& stream(void) { - return m_stream; - } - - void resolveLoggerFormatSpec(void) const { - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - base::LogFormat* logFormat = - const_cast(&m_typedConfigurations->logFormat(LevelHelper::castFromInt(lIndex))); - base::utils::Str::replaceFirstWithEscape(logFormat->m_format, base::consts::kLoggerIdFormatSpecifier, m_id); - return false; - }); - } - }; - namespace base { - /// @brief Loggers repository - class RegisteredLoggers : public base::utils::Registry { - public: - explicit RegisteredLoggers(const LogBuilderPtr& defaultLogBuilder) : - m_defaultLogBuilder(defaultLogBuilder) { - m_defaultConfigurations.setToDefault(); - } - - virtual ~RegisteredLoggers(void) { - unsafeFlushAll(); - } - - inline void setDefaultConfigurations(const Configurations& configurations) { - base::threading::ScopedLock scopedLock(lock()); - m_defaultConfigurations.setFromBase(const_cast(&configurations)); - } - - inline Configurations* defaultConfigurations(void) { - return &m_defaultConfigurations; - } - - Logger* get(const std::string& id, bool forceCreation = true) { - base::threading::ScopedLock scopedLock(lock()); - Logger* logger_ = base::utils::Registry::get(id); - if (logger_ == nullptr && forceCreation) { - bool validId = Logger::isValidId(id); - if (!validId) { - ELPP_ASSERT(validId, "Invalid logger ID [" << id << "]. Not registering this logger."); - return nullptr; - } - logger_ = new Logger(id, m_defaultConfigurations, &m_logStreamsReference); - logger_->m_logBuilder = m_defaultLogBuilder; - registerNew(id, logger_); - } - return logger_; - } - - bool remove(const std::string& id) { - if (id == "default") { - return false; - } - Logger* logger = base::utils::Registry::get(id); - if (logger != nullptr) { - unregister(logger); - } - return true; - } - - inline bool has(const std::string& id) { - return get(id, false) != nullptr; - } - - inline void unregister(Logger*& logger) { - base::threading::ScopedLock scopedLock(lock()); - base::utils::Registry::unregister(logger->id()); - } - - inline base::LogStreamsReferenceMap* logStreamsReference(void) { - return &m_logStreamsReference; - } - - inline void flushAll(void) { - base::threading::ScopedLock scopedLock(lock()); - unsafeFlushAll(); - } - - private: - LogBuilderPtr m_defaultLogBuilder; - Configurations m_defaultConfigurations; - base::LogStreamsReferenceMap m_logStreamsReference; - friend class el::base::Storage; - - inline void unsafeFlushAll(void) { - ELPP_INTERNAL_INFO(1, "Flushing all log files"); - for (base::LogStreamsReferenceMap::iterator it = m_logStreamsReference.begin(); - it != m_logStreamsReference.end(); ++it) { - if (it->second.get() == nullptr) continue; - it->second->flush(); - } - } - }; - /// @brief Represents registries for verbose logging - class VRegistry : base::NoCopy, public base::threading::ThreadSafe { - public: - explicit VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags) : m_level(level), m_pFlags(pFlags) { - } - - /// @brief Sets verbose level. Accepted range is 0-9 - inline void setLevel(base::type::VerboseLevel level) { - base::threading::ScopedLock scopedLock(lock()); - if (level < 0) - m_level = 0; - else if (level > 9) - m_level = base::consts::kMaxVerboseLevel; - else - m_level = level; - } - - inline base::type::VerboseLevel level(void) const { - return m_level; - } - - inline void clearModules(void) { - base::threading::ScopedLock scopedLock(lock()); - m_modules.clear(); - } - - void setModules(const char* modules) { - base::threading::ScopedLock scopedLock(lock()); - auto addSuffix = [](std::stringstream& ss, const char* sfx, const char* prev) { - if (prev != nullptr && base::utils::Str::endsWith(ss.str(), std::string(prev))) { - std::string chr(ss.str().substr(0, ss.str().size() - strlen(prev))); - ss.str(std::string("")); - ss << chr; - } - if (base::utils::Str::endsWith(ss.str(), std::string(sfx))) { - std::string chr(ss.str().substr(0, ss.str().size() - strlen(sfx))); - ss.str(std::string("")); - ss << chr; - } - ss << sfx; - }; - auto insert = [&](std::stringstream& ss, base::type::VerboseLevel level) { - if (!base::utils::hasFlag(LoggingFlag::DisableVModulesExtensions, *m_pFlags)) { - addSuffix(ss, ".h", nullptr); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".c", ".h"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cpp", ".c"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cc", ".cpp"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cxx", ".cc"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".-inl.h", ".cxx"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hxx", ".-inl.h"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hpp", ".hxx"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hh", ".hpp"); - } - m_modules.insert(std::make_pair(ss.str(), level)); - }; - bool isMod = true; - bool isLevel = false; - std::stringstream ss; - int level = -1; - for (; *modules; ++modules) { - switch (*modules) { - case '=': - isLevel = true; - isMod = false; - break; - case ',': - isLevel = false; - isMod = true; - if (!ss.str().empty() && level != -1) { - insert(ss, level); - ss.str(std::string("")); - level = -1; - } - break; - default: - if (isMod) { - ss << *modules; - } else if (isLevel) { - if (isdigit(*modules)) { - level = static_cast(*modules) - 48; - } - } - break; - } - } - if (!ss.str().empty() && level != -1) { - insert(ss, level); - } - } - - bool allowed(base::type::VerboseLevel vlevel, const char* file) { - base::threading::ScopedLock scopedLock(lock()); - if (m_modules.empty() || file == nullptr) { - return vlevel <= m_level; - } else { - std::map::iterator it = m_modules.begin(); - for (; it != m_modules.end(); ++it) { - if (base::utils::Str::wildCardMatch(file, it->first.c_str())) { - return vlevel <= it->second; - } - } - if (base::utils::hasFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified, *m_pFlags)) { - return true; - } - return false; - } - } - - inline const std::map& modules(void) const { - return m_modules; - } - - void setFromArgs(const base::utils::CommandLineArgs* commandLineArgs) { - if (commandLineArgs->hasParam("-v") || commandLineArgs->hasParam("--verbose") || - commandLineArgs->hasParam("-V") || commandLineArgs->hasParam("--VERBOSE")) { - setLevel(base::consts::kMaxVerboseLevel); - } else if (commandLineArgs->hasParamWithValue("--v")) { - setLevel(atoi(commandLineArgs->getParamValue("--v"))); - } else if (commandLineArgs->hasParamWithValue("--V")) { - setLevel(atoi(commandLineArgs->getParamValue("--V"))); - } else if ((commandLineArgs->hasParamWithValue("-vmodule")) && vModulesEnabled()) { - setModules(commandLineArgs->getParamValue("-vmodule")); - } else if (commandLineArgs->hasParamWithValue("-VMODULE") && vModulesEnabled()) { - setModules(commandLineArgs->getParamValue("-VMODULE")); - } - } - - /// @brief Whether or not vModules enabled - inline bool vModulesEnabled(void) { - return !base::utils::hasFlag(LoggingFlag::DisableVModules, *m_pFlags); - } - - private: - base::type::VerboseLevel m_level; - base::type::EnumType* m_pFlags; - std::map m_modules; - }; - } // namespace base - class LogMessage { - public: - LogMessage(Level level, const std::string& file, unsigned long int line, const std::string& func, - base::type::VerboseLevel verboseLevel, Logger* logger) : - m_level(level), m_file(file), m_line(line), m_func(func), - m_verboseLevel(verboseLevel), m_logger(logger), m_message(logger->stream().str()) { - } - inline Level level(void) const { return m_level; } - inline const std::string& file(void) const { return m_file; } - inline unsigned long int line(void) const { return m_line; } // NOLINT - inline const std::string& func(void) const { return m_func; } - inline base::type::VerboseLevel verboseLevel(void) const { return m_verboseLevel; } - inline Logger* logger(void) const { return m_logger; } - inline const base::type::string_t& message(void) const { return m_message; } - private: - Level m_level; - std::string m_file; - unsigned long int m_line; - std::string m_func; - base::type::VerboseLevel m_verboseLevel; - Logger* m_logger; - base::type::string_t m_message; - }; - namespace base { -#if ELPP_ASYNC_LOGGING - class AsyncLogItem { - public: - explicit AsyncLogItem(const LogMessage& logMessage, const LogDispatchData& data, const base::type::string_t& logLine) - : m_logMessage(logMessage), m_dispatchData(data), m_logLine(logLine) {} - virtual ~AsyncLogItem() {} - inline LogMessage* logMessage(void) { return &m_logMessage; } - inline LogDispatchData* data(void) { return &m_dispatchData; } - inline base::type::string_t logLine(void) { return m_logLine; } - private: - LogMessage m_logMessage; - LogDispatchData m_dispatchData; - base::type::string_t m_logLine; - }; - class AsyncLogQueue : public base::threading::ThreadSafe { - public: - virtual ~AsyncLogQueue() { - ELPP_INTERNAL_INFO(6, "~AsyncLogQueue"); - } - - inline AsyncLogItem next(void) { - base::threading::ScopedLock scopedLock(lock()); - AsyncLogItem result = m_queue.front(); - m_queue.pop(); - return result; - } - - inline void push(const AsyncLogItem& item) { - base::threading::ScopedLock scopedLock(lock()); - m_queue.push(item); - } - inline void pop(void) { - base::threading::ScopedLock scopedLock(lock()); - m_queue.pop(); - } - inline AsyncLogItem front(void) { - base::threading::ScopedLock scopedLock(lock()); - return m_queue.front(); - } - inline bool empty(void) { - base::threading::ScopedLock scopedLock(lock()); - return m_queue.empty(); - } - private: - std::queue m_queue; - }; - class IWorker { - public: - virtual ~IWorker() {} - virtual void start() = 0; - }; -#endif // ELPP_ASYNC_LOGGING - /// @brief Easylogging++ management storage - class Storage : base::NoCopy, public base::threading::ThreadSafe { - public: -#if ELPP_ASYNC_LOGGING - Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker) : -#else - explicit Storage(const LogBuilderPtr& defaultLogBuilder) : -#endif // ELPP_ASYNC_LOGGING - m_registeredHitCounters(new base::RegisteredHitCounters()), - m_registeredLoggers(new base::RegisteredLoggers(defaultLogBuilder)), - m_flags(0x0), - m_vRegistry(new base::VRegistry(0, &m_flags)), -#if ELPP_ASYNC_LOGGING - m_asyncLogQueue(new base::AsyncLogQueue()), - m_asyncDispatchWorker(asyncDispatchWorker), -#endif // ELPP_ASYNC_LOGGING - m_preRollOutCallback(base::defaultPreRollOutCallback) { - // Register default logger - m_registeredLoggers->get(std::string(base::consts::kDefaultLoggerId)); - // Register performance logger and reconfigure format - Logger* performanceLogger = m_registeredLoggers->get(std::string(base::consts::kPerformanceLoggerId)); - performanceLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%datetime %level %msg")); - performanceLogger->reconfigure(); -#if defined(ELPP_SYSLOG) - // Register syslog logger and reconfigure format - Logger* sysLogLogger = m_registeredLoggers->get(std::string(base::consts::kSysLogLoggerId)); - sysLogLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%level: %msg")); - sysLogLogger->reconfigure(); -#endif // defined(ELPP_SYSLOG) - addFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified); -#if ELPP_ASYNC_LOGGING - installLogDispatchCallback(std::string("AsyncLogDispatchCallback")); -#else - installLogDispatchCallback(std::string("DefaultLogDispatchCallback")); -#endif // ELPP_ASYNC_LOGGING - installPerformanceTrackingCallback(std::string("DefaultPerformanceTrackingCallback")); - ELPP_INTERNAL_INFO(1, "Easylogging++ has been initialized"); -#if ELPP_ASYNC_LOGGING - m_asyncDispatchWorker->start(); -#endif // ELPP_ASYNC_LOGGING - } - - virtual ~Storage(void) { - ELPP_INTERNAL_INFO(4, "Destroying storage"); -#if ELPP_ASYNC_LOGGING - ELPP_INTERNAL_INFO(5, "Replacing log dispatch callback to synchronous"); - uninstallLogDispatchCallback(std::string("AsyncLogDispatchCallback")); - installLogDispatchCallback(std::string("DefaultLogDispatchCallback")); - ELPP_INTERNAL_INFO(5, "Destroying asyncDispatchWorker"); - base::utils::safeDelete(m_asyncDispatchWorker); - ELPP_INTERNAL_INFO(5, "Destroying asyncLogQueue"); - base::utils::safeDelete(m_asyncLogQueue); -#endif // ELPP_ASYNC_LOGGING - ELPP_INTERNAL_INFO(5, "Destroying registeredHitCounters"); - base::utils::safeDelete(m_registeredHitCounters); - ELPP_INTERNAL_INFO(5, "Destroying registeredLoggers"); - base::utils::safeDelete(m_registeredLoggers); - ELPP_INTERNAL_INFO(5, "Destroying vRegistry"); - base::utils::safeDelete(m_vRegistry); - } - - inline bool validateEveryNCounter(const char* filename, unsigned long int lineNumber, std::size_t occasion) { - return hitCounters()->validateEveryN(filename, lineNumber, occasion); - } - - inline bool validateAfterNCounter(const char* filename, unsigned long int lineNumber, std::size_t n) { // NOLINT - return hitCounters()->validateAfterN(filename, lineNumber, n); - } - - inline bool validateNTimesCounter(const char* filename, unsigned long int lineNumber, std::size_t n) { // NOLINT - return hitCounters()->validateNTimes(filename, lineNumber, n); - } - - inline base::RegisteredHitCounters* hitCounters(void) const { - return m_registeredHitCounters; - } - - inline base::RegisteredLoggers* registeredLoggers(void) const { - return m_registeredLoggers; - } - - inline base::VRegistry* vRegistry(void) const { - return m_vRegistry; - } - -#if ELPP_ASYNC_LOGGING - inline base::AsyncLogQueue* asyncLogQueue(void) const { - return m_asyncLogQueue; - } -#endif // ELPP_ASYNC_LOGGING - - inline const base::utils::CommandLineArgs* commandLineArgs(void) const { - return &m_commandLineArgs; - } - - inline void addFlag(LoggingFlag flag) { - base::utils::addFlag(flag, &m_flags); - } - - inline void removeFlag(LoggingFlag flag) { - base::utils::removeFlag(flag, &m_flags); - } - - inline bool hasFlag(LoggingFlag flag) const { - return base::utils::hasFlag(flag, m_flags); - } - - inline base::type::EnumType flags(void) const { - return m_flags; - } - - inline void setFlags(base::type::EnumType flags) { - m_flags = flags; - } - - inline void setPreRollOutCallback(const PreRollOutCallback& callback) { - m_preRollOutCallback = callback; - } - - inline void unsetPreRollOutCallback(void) { - m_preRollOutCallback = base::defaultPreRollOutCallback; - } - - inline PreRollOutCallback& preRollOutCallback(void) { - return m_preRollOutCallback; - } - - inline bool hasCustomFormatSpecifier(const char* formatSpecifier) { - base::threading::ScopedLock scopedLock(lock()); - return std::find(m_customFormatSpecifiers.begin(), m_customFormatSpecifiers.end(), - formatSpecifier) != m_customFormatSpecifiers.end(); - } - - inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) { - if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) { - return; - } - base::threading::ScopedLock scopedLock(lock()); - m_customFormatSpecifiers.push_back(customFormatSpecifier); - } - - inline bool uninstallCustomFormatSpecifier(const char* formatSpecifier) { - base::threading::ScopedLock scopedLock(lock()); - std::vector::iterator it = std::find(m_customFormatSpecifiers.begin(), - m_customFormatSpecifiers.end(), formatSpecifier); - if (it != m_customFormatSpecifiers.end() && strcmp(formatSpecifier, it->formatSpecifier()) == 0) { - m_customFormatSpecifiers.erase(it); - return true; - } - return false; - } - - const std::vector* customFormatSpecifiers(void) const { - return &m_customFormatSpecifiers; - } - - inline void setLoggingLevel(Level level) { - m_loggingLevel = level; - } - - template - inline bool installLogDispatchCallback(const std::string& id) { - return installCallback(id, &m_logDispatchCallbacks); - } - - template - inline void uninstallLogDispatchCallback(const std::string& id) { - uninstallCallback(id, &m_logDispatchCallbacks); - } - template - inline T* logDispatchCallback(const std::string& id) { - return callback(id, &m_logDispatchCallbacks); - } - - template - inline bool installPerformanceTrackingCallback(const std::string& id) { - return installCallback(id, &m_performanceTrackingCallbacks); - } - - template - inline void uninstallPerformanceTrackingCallback(const std::string& id) { - uninstallCallback(id, &m_performanceTrackingCallbacks); - } - - template - inline T* performanceTrackingCallback(const std::string& id) { - return callback(id, &m_performanceTrackingCallbacks); - } - private: - base::RegisteredHitCounters* m_registeredHitCounters; - base::RegisteredLoggers* m_registeredLoggers; - base::type::EnumType m_flags; - base::VRegistry* m_vRegistry; -#if ELPP_ASYNC_LOGGING - base::AsyncLogQueue* m_asyncLogQueue; - base::IWorker* m_asyncDispatchWorker; -#endif // ELPP_ASYNC_LOGGING - base::utils::CommandLineArgs m_commandLineArgs; - PreRollOutCallback m_preRollOutCallback; - std::map m_logDispatchCallbacks; - std::map m_performanceTrackingCallbacks; - std::vector m_customFormatSpecifiers; - Level m_loggingLevel; - - friend class el::Helpers; - friend class el::base::DefaultLogDispatchCallback; - friend class el::LogBuilder; - friend class el::base::MessageBuilder; - friend class el::base::Writer; - friend class el::base::PerformanceTracker; - friend class el::base::LogDispatcher; - - void setApplicationArguments(int argc, char** argv) { - m_commandLineArgs.setArgs(argc, argv); - m_vRegistry->setFromArgs(commandLineArgs()); - // default log file -#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) - if (m_commandLineArgs.hasParamWithValue(base::consts::kDefaultLogFileParam)) { - Configurations c; - c.setGlobally(ConfigurationType::Filename, std::string(m_commandLineArgs.getParamValue(base::consts::kDefaultLogFileParam))); - registeredLoggers()->setDefaultConfigurations(c); - for (base::RegisteredLoggers::iterator it = registeredLoggers()->begin(); - it != registeredLoggers()->end(); ++it) { - it->second->configure(c); - } - } -#endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) -#if defined(ELPP_LOGGING_FLAGS_FROM_ARG) - if (m_commandLineArgs.hasParamWithValue(base::consts::kLoggingFlagsParam)) { - m_flags = atoi(m_commandLineArgs.getParamValue(base::consts::kLoggingFlagsParam)); - } -#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) - } - - inline void setApplicationArguments(int argc, const char** argv) { - setApplicationArguments(argc, const_cast(argv)); - } - - template - inline bool installCallback(const std::string& id, std::map* mapT) { - if (mapT->find(id) == mapT->end()) { - mapT->insert(std::make_pair(id, TPtr(new T()))); - return true; - } - return false; - } - - template - inline void uninstallCallback(const std::string& id, std::map* mapT) { - if (mapT->find(id) != mapT->end()) { - mapT->erase(id); - } - } - - template - inline T* callback(const std::string& id, std::map* mapT) { - typename std::map::iterator iter = mapT->find(id); - if (iter != mapT->end()) { - return static_cast(iter->second.get()); - } - return nullptr; - } - }; - extern ELPP_EXPORT base::type::StoragePointer elStorage; -#define ELPP el::base::elStorage - class DefaultLogDispatchCallback : public LogDispatchCallback { - protected: - void handle(const LogDispatchData* data) { - m_data = data; - dispatch(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(), - m_data->dispatchAction() == base::DispatchAction::NormalLog)); - } - private: - const LogDispatchData* m_data; - void dispatch(base::type::string_t&& logLine) { - if (m_data->dispatchAction() == base::DispatchAction::NormalLog) { - if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) { - base::type::fstream_t* fs = m_data->logMessage()->logger()->m_typedConfigurations->fileStream(m_data->logMessage()->level()); - if (fs != nullptr) { - fs->write(logLine.c_str(), logLine.size()); - if (fs->fail()) { - ELPP_INTERNAL_ERROR("Unable to write log to file [" - << m_data->logMessage()->logger()->m_typedConfigurations->filename(m_data->logMessage()->level()) << "].\n" - << "Few possible reasons (could be something else):\n" << " * Permission denied\n" - << " * Disk full\n" << " * Disk is not writable", true); - } else { - if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || (m_data->logMessage()->logger()->isFlushNeeded(m_data->logMessage()->level()))) { - m_data->logMessage()->logger()->flush(m_data->logMessage()->level(), fs); - } - } - } else { - ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(m_data->logMessage()->level()) << "] " - << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " - << m_data->logMessage()->logger()->id() << "]", false); - } - } - if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput(m_data->logMessage()->level())) { - if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) - m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, m_data->logMessage()->level()); - ELPP_COUT << ELPP_COUT_LINE(logLine); - } - } -#if defined(ELPP_SYSLOG) - else if (m_data->dispatchAction() == base::DispatchAction::SysLog) { - // Determine syslog priority - int sysLogPriority = 0; - if (m_data->logMessage()->level() == Level::Fatal) - sysLogPriority = LOG_EMERG; - else if (m_data->logMessage()->level() == Level::Error) - sysLogPriority = LOG_ERR; - else if (m_data->logMessage()->level() == Level::Warning) - sysLogPriority = LOG_WARNING; - else if (m_data->logMessage()->level() == Level::Info) - sysLogPriority = LOG_INFO; - else if (m_data->logMessage()->level() == Level::Debug) - sysLogPriority = LOG_DEBUG; - else - sysLogPriority = LOG_NOTICE; -# if defined(ELPP_UNICODE) - char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str()); - syslog(sysLogPriority, "%s", line); - free(line); -# else - syslog(sysLogPriority, "%s", logLine.c_str()); -# endif - } -#endif // defined(ELPP_SYSLOG) - } - }; -#if ELPP_ASYNC_LOGGING - class AsyncLogDispatchCallback : public LogDispatchCallback { - protected: - void handle(const LogDispatchData* data) { - base::type::string_t logLine = data->logMessage()->logger()->logBuilder()->build(data->logMessage(), data->dispatchAction() == base::DispatchAction::NormalLog); - if (data->dispatchAction() == base::DispatchAction::NormalLog && data->logMessage()->logger()->typedConfigurations()->toStandardOutput(data->logMessage()->level())) { - if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) - data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, data->logMessage()->level()); - ELPP_COUT << ELPP_COUT_LINE(logLine); - } - // Save resources and only queue if we want to write to file otherwise just ignore handler - if (data->logMessage()->logger()->typedConfigurations()->toFile(data->logMessage()->level())) { - ELPP->asyncLogQueue()->push(AsyncLogItem(*(data->logMessage()), *data, logLine)); - } - } - }; - class AsyncDispatchWorker : public base::IWorker, public base::threading::ThreadSafe { - public: - AsyncDispatchWorker() { - setContinueRunning(false); - } - - virtual ~AsyncDispatchWorker() { - setContinueRunning(false); - ELPP_INTERNAL_INFO(6, "Stopping dispatch worker - Cleaning log queue"); - clean(); - ELPP_INTERNAL_INFO(6, "Log queue cleaned"); - } - - inline bool clean(void) { - std::mutex m; - std::unique_lock lk(m); - cv.wait(lk, []{ return !ELPP->asyncLogQueue()->empty(); }); - emptyQueue(); - lk.unlock(); - cv.notify_one(); - return ELPP->asyncLogQueue()->empty(); - } - - inline void emptyQueue(void) { - while (!ELPP->asyncLogQueue()->empty()) { - AsyncLogItem data = ELPP->asyncLogQueue()->next(); - handle(&data); - base::threading::msleep(100); - } - } - - virtual inline void start(void) { - base::threading::msleep(5000); // 5s (why?) - setContinueRunning(true); - std::thread t1(&AsyncDispatchWorker::run, this); - t1.join(); - } - - void handle(AsyncLogItem* logItem) { - LogDispatchData* data = logItem->data(); - LogMessage* logMessage = logItem->logMessage(); - Logger* logger = logMessage->logger(); - base::TypedConfigurations* conf = logger->typedConfigurations(); - base::type::string_t logLine = logItem->logLine(); - if (data->dispatchAction() == base::DispatchAction::NormalLog) { - if (conf->toFile(logMessage->level())) { - base::type::fstream_t* fs = conf->fileStream(logMessage->level()); - if (fs != nullptr) { - fs->write(logLine.c_str(), logLine.size()); - if (fs->fail()) { - ELPP_INTERNAL_ERROR("Unable to write log to file [" - << conf->filename(logMessage->level()) << "].\n" - << "Few possible reasons (could be something else):\n" << " * Permission denied\n" - << " * Disk full\n" << " * Disk is not writable", true); - } else { - if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || (logger->isFlushNeeded(logMessage->level()))) { - logger->flush(logMessage->level(), fs); - } - } - } else { - ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(logMessage->level()) << "] " - << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " << logger->id() << "]", false); - } - } - } -# if defined(ELPP_SYSLOG) - else if (data->dispatchAction() == base::DispatchAction::SysLog) { - // Determine syslog priority - int sysLogPriority = 0; - if (logMessage->level() == Level::Fatal) - sysLogPriority = LOG_EMERG; - else if (logMessage->level() == Level::Error) - sysLogPriority = LOG_ERR; - else if (logMessage->level() == Level::Warning) - sysLogPriority = LOG_WARNING; - else if (logMessage->level() == Level::Info) - sysLogPriority = LOG_INFO; - else if (logMessage->level() == Level::Debug) - sysLogPriority = LOG_DEBUG; - else - sysLogPriority = LOG_NOTICE; -# if defined(ELPP_UNICODE) - char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str()); - syslog(sysLogPriority, "%s", line); - free(line); -# else - syslog(sysLogPriority, "%s", logLine.c_str()); -# endif - } -# endif // defined(ELPP_SYSLOG) - } - - void run(void) { - while (continueRunning()) { - emptyQueue(); - base::threading::msleep(10); // 10ms - } - } - - void setContinueRunning(bool value) { - base::threading::ScopedLock scopedLock(m_continueRunningMutex); - m_continueRunning = value; - } - - bool continueRunning(void) const { - return m_continueRunning; - } - private: - std::condition_variable cv; - bool m_continueRunning; - base::threading::Mutex m_continueRunningMutex; - }; -#endif // ELPP_ASYNC_LOGGING - } // namespace base - namespace base { - class DefaultLogBuilder : public LogBuilder { - public: - base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const { - base::TypedConfigurations* tc = logMessage->logger()->typedConfigurations(); - const base::LogFormat* logFormat = &tc->logFormat(logMessage->level()); - base::type::string_t logLine = logFormat->format(); - char buff[base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength] = ""; - const char* bufLim = buff + sizeof(buff); - if (logFormat->hasFlag(base::FormatFlags::AppName)) { - // App name - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kAppNameFormatSpecifier, - logMessage->logger()->parentApplicationName()); - } - if (logFormat->hasFlag(base::FormatFlags::ThreadId)) { - // Thread ID - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kThreadIdFormatSpecifier, - base::threading::getCurrentThreadId()); - } - if (logFormat->hasFlag(base::FormatFlags::DateTime)) { - // DateTime - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kDateTimeFormatSpecifier, - base::utils::DateTime::getDateTime(logFormat->dateTimeFormat().c_str(), - &tc->millisecondsWidth(logMessage->level()))); - } - if (logFormat->hasFlag(base::FormatFlags::Function)) { - // Function - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFunctionFormatSpecifier, logMessage->func()); - } - if (logFormat->hasFlag(base::FormatFlags::File)) { - // File - base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength); - base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::FileBase)) { - // FileBase - base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength); - base::utils::File::buildBaseFilename(logMessage->file(), buff); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileBaseFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::Line)) { - // Line - char* buf = base::utils::Str::clearBuff(buff, base::consts::kSourceLineMaxLength); - buf = base::utils::Str::convertAndAddToBuff(logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim, false); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLineFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::Location)) { - // Location - char* buf = base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength); - base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff); - buf = base::utils::Str::addToBuff(buff, buf, bufLim); - buf = base::utils::Str::addToBuff(":", buf, bufLim); - buf = base::utils::Str::convertAndAddToBuff(logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim, false); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLocationFormatSpecifier, std::string(buff)); - } - if (logMessage->level() == Level::Verbose && logFormat->hasFlag(base::FormatFlags::VerboseLevel)) { - // Verbose level - char* buf = base::utils::Str::clearBuff(buff, 1); - buf = base::utils::Str::convertAndAddToBuff(logMessage->verboseLevel(), 1, buf, bufLim, false); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kVerboseLevelFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::LogMessage)) { - // Log message - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kMessageFormatSpecifier, logMessage->message()); - } -#if !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS) - for (std::vector::const_iterator it = ELPP->customFormatSpecifiers()->begin(); - it != ELPP->customFormatSpecifiers()->end(); ++it) { - std::string fs(it->formatSpecifier()); - base::type::string_t wcsFormatSpecifier(fs.begin(), fs.end()); - base::utils::Str::replaceFirstWithEscape(logLine, wcsFormatSpecifier, std::string(it->resolver()())); - } -#endif // !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS) - if (appendNewLine) logLine += ELPP_LITERAL("\n"); - return logLine; - } - }; - /// @brief Dispatches log messages - class LogDispatcher : base::NoCopy { - public: - LogDispatcher(bool proceed, LogMessage&& logMessage, base::DispatchAction dispatchAction) : - m_proceed(proceed), - m_logMessage(std::move(logMessage)), - m_dispatchAction(std::move(dispatchAction)) { - } - - void dispatch(void) { - if (m_proceed && m_dispatchAction == base::DispatchAction::None) { - m_proceed = false; - } - if (!m_proceed) { - return; - } - // We minimize the time of ELPP's lock - this lock is released after log is written - base::threading::ScopedLock scopedLock(ELPP->lock()); - base::TypedConfigurations* tc = m_logMessage.logger()->m_typedConfigurations; - if (ELPP->hasFlag(LoggingFlag::StrictLogFileSizeCheck)) { - tc->validateFileRolling(m_logMessage.level(), ELPP->preRollOutCallback()); - } - LogDispatchCallback* callback = nullptr; - LogDispatchData data; - for (const std::pair& h - : ELPP->m_logDispatchCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - data.setLogMessage(&m_logMessage); - data.setDispatchAction(m_dispatchAction); - callback->acquireLock(); - callback->handle(&data); - callback->releaseLock(); - } - } - } - - private: - bool m_proceed; - LogMessage m_logMessage; - base::DispatchAction m_dispatchAction; - }; -#if defined(ELPP_STL_LOGGING) - /// @brief Workarounds to write some STL logs - /// - /// @detail There is workaround needed to loop through some stl containers. In order to do that, we need iterable containers - /// of same type and provide iterator interface and pass it on to writeIterator(). - /// Remember, this is passed by value in constructor so that we dont change original containers. - /// This operation is as expensive as Big-O(std::min(class_.size(), base::consts::kMaxLogPerContainer)) - namespace workarounds { - /// @brief Abstract IterableContainer template that provides interface for iterable classes of type T - template - class IterableContainer { - public: - typedef typename Container::iterator iterator; - typedef typename Container::const_iterator const_iterator; - IterableContainer(void) {} - virtual ~IterableContainer(void) {} - iterator begin(void) { return getContainer().begin(); } - iterator end(void) { return getContainer().end(); } - private: - virtual Container& getContainer(void) = 0; - }; - /// @brief Implements IterableContainer and provides iterable std::priority_queue class - template, typename Comparator = std::less> - class IterablePriorityQueue : public IterableContainer, public std::priority_queue { - public: - IterablePriorityQueue(std::priority_queue queue_) { - std::size_t count_ = 0; - while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) { - this->push(queue_.top()); - queue_.pop(); - } - } - private: - inline Container& getContainer(void) { - return this->c; - } - }; - /// @brief Implements IterableContainer and provides iterable std::queue class - template> - class IterableQueue : public IterableContainer, public std::queue { - public: - IterableQueue(std::queue queue_) { - std::size_t count_ = 0; - while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) { - this->push(queue_.front()); - queue_.pop(); - } - } - private: - inline Container& getContainer(void) { - return this->c; - } - }; - /// @brief Implements IterableContainer and provides iterable std::stack class - template> - class IterableStack : public IterableContainer, public std::stack { - public: - IterableStack(std::stack stack_) { - std::size_t count_ = 0; - while (++count_ < base::consts::kMaxLogPerContainer && !stack_.empty()) { - this->push(stack_.top()); - stack_.pop(); - } - } - private: - inline Container& getContainer(void) { - return this->c; - } - }; - } // namespace workarounds -#endif // defined(ELPP_STL_LOGGING) - // Log message builder - class MessageBuilder { - public: - MessageBuilder(void) : m_logger(nullptr), m_containerLogSeperator(ELPP_LITERAL("")) {} - void initialize(Logger* logger) { - m_logger = logger; - m_containerLogSeperator = ELPP->hasFlag(LoggingFlag::NewLineForContainer) ? - ELPP_LITERAL("\n ") : ELPP_LITERAL(", "); - } - -# define ELPP_SIMPLE_LOG(LOG_TYPE)\ -inline MessageBuilder& operator<<(LOG_TYPE msg) {\ -m_logger->stream() << msg;\ -if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {\ -m_logger->stream() << " ";\ -}\ -return *this;\ -} - - inline MessageBuilder& operator<<(const std::string& msg) { - return operator<<(msg.c_str()); - } - ELPP_SIMPLE_LOG(char) - ELPP_SIMPLE_LOG(bool) - ELPP_SIMPLE_LOG(signed short) - ELPP_SIMPLE_LOG(unsigned short) - ELPP_SIMPLE_LOG(signed int) - ELPP_SIMPLE_LOG(unsigned int) - ELPP_SIMPLE_LOG(signed long) - ELPP_SIMPLE_LOG(unsigned long) - ELPP_SIMPLE_LOG(float) - ELPP_SIMPLE_LOG(double) - ELPP_SIMPLE_LOG(char*) - ELPP_SIMPLE_LOG(const char*) - ELPP_SIMPLE_LOG(const void*) - ELPP_SIMPLE_LOG(long double) - inline MessageBuilder& operator<<(const std::wstring& msg) { - return operator<<(msg.c_str()); - } - inline MessageBuilder& operator<<(const wchar_t* msg) { - if (msg == nullptr) { - m_logger->stream() << base::consts::kNullPointer; - return *this; - } -# if defined(ELPP_UNICODE) - m_logger->stream() << msg; -# else - char* buff_ = base::utils::Str::wcharPtrToCharPtr(msg); - m_logger->stream() << buff_; - free(buff_); -# endif - if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) { - m_logger->stream() << " "; - } - return *this; - } - // ostream manipulators - inline MessageBuilder& operator<<(std::ostream& (*OStreamMani)(std::ostream&)) { - m_logger->stream() << OStreamMani; - return *this; - } -#define ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} - -#if defined(ELPP_STL_LOGGING) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::vector) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::list) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::deque) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::set) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::multiset) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::map) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::multimap) - template - inline MessageBuilder& operator<<(const std::queue& queue_) { - base::workarounds::IterableQueue iterableQueue_ = - static_cast >(queue_); - return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size()); - } - template - inline MessageBuilder& operator<<(const std::stack& stack_) { - base::workarounds::IterableStack iterableStack_ = - static_cast >(stack_); - return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size()); - } - template - inline MessageBuilder& operator<<(const std::priority_queue& priorityQueue_) { - base::workarounds::IterablePriorityQueue iterablePriorityQueue_ = - static_cast >(priorityQueue_); - return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size()); - } - template - inline MessageBuilder& operator<<(const std::pair& pair_) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(pair_.first)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(pair_.second)); - m_logger->stream() << ELPP_LITERAL(")"); - return *this; - } - template - inline MessageBuilder& operator<<(const std::bitset& bitset_) { - m_logger->stream() << ELPP_LITERAL("["); - operator << (bitset_.to_string()); - m_logger->stream() << ELPP_LITERAL("]"); - return *this; - } -# if defined(ELPP_LOG_STD_ARRAY) - template - inline MessageBuilder& operator<<(const std::array& array) { - return writeIterator(array.begin(), array.end(), array.size()); - } -# endif // defined(ELPP_LOG_STD_ARRAY) -# if defined(ELPP_LOG_UNORDERED_MAP) - ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_map) - ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_multimap) -# endif // defined(ELPP_LOG_UNORDERED_MAP) -# if defined(ELPP_LOG_UNORDERED_SET) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_set) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_multiset) -# endif // defined(ELPP_LOG_UNORDERED_SET) -#endif // defined(ELPP_STL_LOGGING) -#if defined(ELPP_QT_LOGGING) - inline MessageBuilder& operator<<(const QString& msg) { -# if defined(ELPP_UNICODE) - m_logger->stream() << msg.toStdWString(); -# else - m_logger->stream() << msg.toStdString(); -# endif // defined(ELPP_UNICODE) - return *this; - } - inline MessageBuilder& operator<<(const QByteArray& msg) { - return operator << (QString(msg)); - } - inline MessageBuilder& operator<<(const QStringRef& msg) { - return operator<<(msg.toString()); - } - inline MessageBuilder& operator<<(qint64 msg) { -# if defined(ELPP_UNICODE) - m_logger->stream() << QString::number(msg).toStdWString(); -# else - m_logger->stream() << QString::number(msg).toStdString(); -# endif // defined(ELPP_UNICODE) - return *this; - } - inline MessageBuilder& operator<<(quint64 msg) { -# if defined(ELPP_UNICODE) - m_logger->stream() << QString::number(msg).toStdWString(); -# else - m_logger->stream() << QString::number(msg).toStdString(); -# endif // defined(ELPP_UNICODE) - return *this; - } - inline MessageBuilder& operator<<(QChar msg) { - m_logger->stream() << msg.toLatin1(); - return *this; - } - inline MessageBuilder& operator<<(const QLatin1String& msg) { - m_logger->stream() << msg.latin1(); - return *this; - } - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QList) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QVector) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QQueue) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QSet) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QLinkedList) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QStack) - template - inline MessageBuilder& operator<<(const QPair& pair_) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(pair_.first)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(pair_.second)); - m_logger->stream() << ELPP_LITERAL(")"); - return *this; - } - template - inline MessageBuilder& operator<<(const QMap& map_) { - m_logger->stream() << ELPP_LITERAL("["); - QList keys = map_.keys(); - typename QList::const_iterator begin = keys.begin(); - typename QList::const_iterator end = keys.end(); - int max_ = static_cast(base::consts::kMaxLogPerContainer); // to prevent warning - for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(*begin)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(map_.value(*begin))); - m_logger->stream() << ELPP_LITERAL(")"); - m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL("")); - } - if (begin != end) { - m_logger->stream() << ELPP_LITERAL("..."); - } - m_logger->stream() << ELPP_LITERAL("]"); - return *this; - } - template - inline MessageBuilder& operator<<(const QMultiMap& map_) { - operator << (static_cast>(map_)); - return *this; - } - template - inline MessageBuilder& operator<<(const QHash& hash_) { - m_logger->stream() << ELPP_LITERAL("["); - QList keys = hash_.keys(); - typename QList::const_iterator begin = keys.begin(); - typename QList::const_iterator end = keys.end(); - int max_ = static_cast(base::consts::kMaxLogPerContainer); // prevent type warning - for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(*begin)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(hash_.value(*begin))); - m_logger->stream() << ELPP_LITERAL(")"); - m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL("")); - } - if (begin != end) { - m_logger->stream() << ELPP_LITERAL("..."); - } - m_logger->stream() << ELPP_LITERAL("]"); - return *this; - } - template - inline MessageBuilder& operator<<(const QMultiHash& multiHash_) { - operator << (static_cast>(multiHash_)); - return *this; - } -#endif // defined(ELPP_QT_LOGGING) -#if defined(ELPP_BOOST_LOGGING) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::vector) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::stable_vector) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::list) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::deque) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::map) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::flat_map) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::set) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::flat_set) -#endif // defined(ELPP_BOOST_LOGGING) - - /// @brief Macro used internally that can be used externally to make containers easylogging++ friendly - /// - /// @detail This macro expands to write an ostream& operator<< for container. This container is expected to - /// have begin() and end() methods that return respective iterators - /// @param ContainerType Type of container e.g, MyList from WX_DECLARE_LIST(int, MyList); in wxwidgets - /// @param SizeMethod Method used to get size of container. - /// @param ElementInstance Instance of element to be fed out. Insance name is "elem". See WXELPP_ENABLED macro - /// for an example usage -#define MAKE_CONTAINERELPP_FRIENDLY(ContainerType, SizeMethod, ElementInstance) \ -el::base::type::ostream_t& operator<<(el::base::type::ostream_t& ss, const ContainerType& container) {\ -const el::base::type::char_t* sep = ELPP->hasFlag(el::LoggingFlag::NewLineForContainer) ? \ -ELPP_LITERAL("\n ") : ELPP_LITERAL(", ");\ -ContainerType::const_iterator elem = container.begin();\ -ContainerType::const_iterator endElem = container.end();\ -std::size_t size_ = container.SizeMethod; \ -ss << ELPP_LITERAL("[");\ -for (std::size_t i = 0; elem != endElem && i < el::base::consts::kMaxLogPerContainer; ++i, ++elem) { \ -ss << ElementInstance;\ -ss << ((i < size_ - 1) ? sep : ELPP_LITERAL(""));\ -}\ -if (elem != endElem) {\ -ss << ELPP_LITERAL("...");\ -}\ -ss << ELPP_LITERAL("]");\ -return ss;\ -} -#if defined(ELPP_WXWIDGETS_LOGGING) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(wxVector) -# define ELPP_WX_PTR_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), *(*elem)) -# define ELPP_WX_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), (*elem)) -# define ELPP_WX_HASH_MAP_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), \ -ELPP_LITERAL("(") << elem->first << ELPP_LITERAL(", ") << elem->second << ELPP_LITERAL(")") -#else -# define ELPP_WX_PTR_ENABLED(ContainerType) -# define ELPP_WX_ENABLED(ContainerType) -# define ELPP_WX_HASH_MAP_ENABLED(ContainerType) -#endif // defined(ELPP_WXWIDGETS_LOGGING) - // Other classes - template - ELPP_SIMPLE_LOG(const Class&) -#undef ELPP_SIMPLE_LOG -#undef ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG - private: - Logger* m_logger; - const base::type::char_t* m_containerLogSeperator; - - template - inline MessageBuilder& writeIterator(Iterator begin_, Iterator end_, std::size_t size_) { - m_logger->stream() << ELPP_LITERAL("["); - for (std::size_t i = 0; begin_ != end_ && i < base::consts::kMaxLogPerContainer; ++i, ++begin_) { - operator << (*begin_); - m_logger->stream() << ((i < size_ - 1) ? m_containerLogSeperator : ELPP_LITERAL("")); - } - if (begin_ != end_) { - m_logger->stream() << ELPP_LITERAL("..."); - } - m_logger->stream() << ELPP_LITERAL("]"); - if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) { - m_logger->stream() << " "; - } - return *this; - } - }; - /// @brief Writes nothing - Used when certain log is disabled - class NullWriter : base::NoCopy { - public: - NullWriter(void) {} - - // Null manipulator - inline NullWriter& operator<<(std::ostream& (*)(std::ostream&)) { - return *this; - } - - template - inline NullWriter& operator<<(const T&) { - return *this; - } - }; - /// @brief Main entry point of each logging - class Writer : base::NoCopy { - public: - Writer(Level level, const char* file, unsigned long int line, - const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog, - base::type::VerboseLevel verboseLevel = 0) : - m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel), - m_proceed(false), m_dispatchAction(dispatchAction) { - } - - virtual ~Writer(void) { - processDispatch(); - } - - template - inline Writer& operator<<(const T& log) { -#if ELPP_LOGGING_ENABLED - if (m_proceed) { - m_messageBuilder << log; - } -#endif // ELPP_LOGGING_ENABLED - return *this; - } - - inline Writer& operator<<(std::ostream& (*log)(std::ostream&)) { -#if ELPP_LOGGING_ENABLED - if (m_proceed) { - m_messageBuilder << log; - } -#endif // ELPP_LOGGING_ENABLED - return *this; - } - - Writer& construct(Logger* logger, bool needLock = true) { - m_logger = logger; - initializeLogger(logger->id(), false, needLock); - m_messageBuilder.initialize(m_logger); - return *this; - } - - Writer& construct(int count, const char* loggerIds, ...) { - if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) { - va_list loggersList; - va_start(loggersList, loggerIds); - const char* id = loggerIds; - for (int i = 0; i < count; ++i) { - m_loggerIds.push_back(std::string(id)); - id = va_arg(loggersList, const char*); - } - va_end(loggersList); - initializeLogger(m_loggerIds.at(0)); - } else { - initializeLogger(std::string(loggerIds)); - } - m_messageBuilder.initialize(m_logger); - return *this; - } - protected: - Level m_level; - const char* m_file; - const unsigned long int m_line; - const char* m_func; - base::type::VerboseLevel m_verboseLevel; - Logger* m_logger; - bool m_proceed; - base::MessageBuilder m_messageBuilder; - base::DispatchAction m_dispatchAction; - std::vector m_loggerIds; - friend class el::Helpers; - - void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true) { - if (lookup) { - m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically)); - } - if (m_logger == nullptr) { - ELPP->acquireLock(); - if (!ELPP->registeredLoggers()->has(std::string(base::consts::kDefaultLoggerId))) { - // Somehow default logger has been unregistered. Not good! Register again - ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId)); - } - ELPP->releaseLock(); // Need to unlock it for next writer - Writer(Level::Debug, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) - << "Logger [" << loggerId << "] is not registered yet!"; - m_proceed = false; - } else { - if (needLock) { - m_logger->acquireLock(); // This should not be unlocked by checking m_proceed because - // m_proceed can be changed by lines below - } - if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) { - m_proceed = m_level == Level::Verbose ? m_logger->enabled(m_level) : - LevelHelper::castToInt(m_level) >= LevelHelper::castToInt(ELPP->m_loggingLevel); - } else { - m_proceed = m_logger->enabled(m_level); - } - } - } - - void processDispatch() { -#if ELPP_LOGGING_ENABLED - if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) { - bool firstDispatched = false; - base::type::string_t logMessage; - std::size_t i = 0; - do { - if (m_proceed) { - if (firstDispatched) { - m_logger->stream() << logMessage; - } else { - firstDispatched = true; - if (m_loggerIds.size() > 1) { - logMessage = m_logger->stream().str(); - } - } - triggerDispatch(); - } else if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } - if (i + 1 < m_loggerIds.size()) { - initializeLogger(m_loggerIds.at(i + 1)); - } - } while (++i < m_loggerIds.size()); - } else { - if (m_proceed) { - triggerDispatch(); - } else if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } - } -#else - if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } -#endif // ELPP_LOGGING_ENABLED - } - - void triggerDispatch(void) { - if (m_proceed) { - base::LogDispatcher(m_proceed, LogMessage(m_level, m_file, m_line, m_func, m_verboseLevel, - m_logger), m_dispatchAction).dispatch(); - } - if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } - if (m_proceed && m_level == Level::Fatal - && !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) { - base::Writer(Level::Warning, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) - << "Aborting application. Reason: Fatal log at [" << m_file << ":" << m_line << "]"; - std::stringstream reasonStream; - reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]" - << " If you wish to disable 'abort on fatal log' please use " - << "el::Helpers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog)"; - base::utils::abort(1, reasonStream.str()); - } - m_proceed = false; - } - }; - class PErrorWriter : public base::Writer { - public: - PErrorWriter(Level level, const char* file, unsigned long int line, - const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog, - base::type::VerboseLevel verboseLevel = 0) : - base::Writer(level, file, line, func, dispatchAction, verboseLevel) { - } - - virtual ~PErrorWriter(void) { - if (m_proceed) { -#if ELPP_COMPILER_MSVC - char buff[256]; - strerror_s(buff, 256, errno); - m_logger->stream() << ": " << buff << " [" << errno << "]"; -#else - m_logger->stream() << ": " << strerror(errno) << " [" << errno << "]"; -#endif - } - } - }; - } // namespace base - // Logging from Logger class. Why this is here? Because we have Storage and Writer class available -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED - template - void Logger::log_(Level level, int vlevel, const char* s, const T& value, const Args&... args) { - base::MessageBuilder b; - b.initialize(this); - while (*s) { - if (*s == base::consts::kFormatSpecifierChar) { - if (*(s + 1) == base::consts::kFormatSpecifierChar) { - ++s; - } else { - if (*(s + 1) == base::consts::kFormatSpecifierCharValue) { - ++s; - b << value; - log_(level, vlevel, ++s, args...); - return; - } - } - } - b << *s++; - } - ELPP_INTERNAL_ERROR("Too many arguments provided. Unable to handle. Please provide more format specifiers", false); - } - template - inline void Logger::log_(Level level, int vlevel, const T& log) { - if (level == Level::Verbose) { - if (ELPP->vRegistry()->allowed(vlevel, __FILE__)) { - base::Writer(Level::Verbose, "FILE", 0, "FUNCTION", - base::DispatchAction::NormalLog, vlevel).construct(this, false) << log; - } else { - stream().str(ELPP_LITERAL("")); - } - } else { - base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log; - } - } - template - void Logger::log(Level level, const char* s, const T& value, const Args&... args) { - base::threading::ScopedLock scopedLock(lock()); - log_(level, 0, s, value, args...); - } - template - inline void Logger::log(Level level, const T& log) { - base::threading::ScopedLock scopedLock(lock()); - log_(level, 0, log); - } -# if ELPP_VERBOSE_LOG - template - inline void Logger::verbose(int vlevel, const char* s, const T& value, const Args&... args) { - base::threading::ScopedLock scopedLock(lock()); - log_(el::Level::Verbose, vlevel, s, value, args...); - } - template - inline void Logger::verbose(int vlevel, const T& log) { - base::threading::ScopedLock scopedLock(lock()); - log_(el::Level::Verbose, vlevel, log); - } -# else - template - inline void Logger::verbose(int, const char*, const T&, const Args&...) { - return; - } - template - inline void Logger::verbose(int, const T&) { - return; - } -# endif // ELPP_VERBOSE_LOG -# define LOGGER_LEVEL_WRITERS(FUNCTION_NAME, LOG_LEVEL)\ -template \ -inline void Logger::FUNCTION_NAME(const char* s, const T& value, const Args&... args) {\ -log(LOG_LEVEL, s, value, args...);\ -}\ -template \ -inline void Logger::FUNCTION_NAME(const T& value) {\ -log(LOG_LEVEL, value);\ -} -# define LOGGER_LEVEL_WRITERS_DISABLED(FUNCTION_NAME, LOG_LEVEL)\ -template \ -inline void Logger::FUNCTION_NAME(const char*, const T&, const Args&...) {\ -return;\ -}\ -template \ -inline void Logger::FUNCTION_NAME(const T&) {\ -return;\ -} - -# if ELPP_INFO_LOG - LOGGER_LEVEL_WRITERS(info, Level::Info) -# else - LOGGER_LEVEL_WRITERS_DISABLED(info, Level::Info) -# endif // ELPP_INFO_LOG -# if ELPP_DEBUG_LOG - LOGGER_LEVEL_WRITERS(debug, Level::Debug) -# else - LOGGER_LEVEL_WRITERS_DISABLED(debug, Level::Debug) -# endif // ELPP_DEBUG_LOG -# if ELPP_WARNING_LOG - LOGGER_LEVEL_WRITERS(warn, Level::Warning) -# else - LOGGER_LEVEL_WRITERS_DISABLED(warn, Level::Warning) -# endif // ELPP_WARNING_LOG -# if ELPP_ERROR_LOG - LOGGER_LEVEL_WRITERS(error, Level::Error) -# else - LOGGER_LEVEL_WRITERS_DISABLED(error, Level::Error) -# endif // ELPP_ERROR_LOG -# if ELPP_FATAL_LOG - LOGGER_LEVEL_WRITERS(fatal, Level::Fatal) -# else - LOGGER_LEVEL_WRITERS_DISABLED(fatal, Level::Fatal) -# endif // ELPP_FATAL_LOG -# if ELPP_TRACE_LOG - LOGGER_LEVEL_WRITERS(trace, Level::Trace) -# else - LOGGER_LEVEL_WRITERS_DISABLED(trace, Level::Trace) -# endif // ELPP_TRACE_LOG -# undef LOGGER_LEVEL_WRITERS -# undef LOGGER_LEVEL_WRITERS_DISABLED -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED -#if ELPP_COMPILER_MSVC -# define ELPP_VARIADIC_FUNC_MSVC(variadicFunction, variadicArgs) variadicFunction variadicArgs -# define ELPP_VARIADIC_FUNC_MSVC_RUN(variadicFunction, ...) ELPP_VARIADIC_FUNC_MSVC(variadicFunction, (__VA_ARGS__)) -# define el_getVALength(...) ELPP_VARIADIC_FUNC_MSVC_RUN(el_resolveVALength, 0, ## __VA_ARGS__,\ -10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -#else -# if ELPP_COMPILER_CLANG -# define el_getVALength(...) el_resolveVALength(0, __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -# else -# define el_getVALength(...) el_resolveVALength(0, ## __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -# endif // ELPP_COMPILER_CLANG -#endif // ELPP_COMPILER_MSVC -#define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N -#define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_IF(writer, condition, level, dispatchAction, ...) if (condition) \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_EVERY_N(writer, occasion, level, dispatchAction, ...) \ -if (ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion)) \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_AFTER_N(writer, n, level, dispatchAction, ...) \ -if (ELPP->validateAfterNCounter(__FILE__, __LINE__, n)) \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_N_TIMES(writer, n, level, dispatchAction, ...) \ -if (ELPP->validateNTimesCounter(__FILE__, __LINE__, n)) \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#undef ELPP_CURR_FILE_PERFORMANCE_LOGGER -#if defined(ELPP_PERFORMANCE_LOGGER) -# define ELPP_CURR_FILE_PERFORMANCE_LOGGER ELPP_PERFORMANCE_LOGGER -#else -# define ELPP_CURR_FILE_PERFORMANCE_LOGGER el::base::consts::kPerformanceLoggerId -#endif - class PerformanceTrackingData { - public: - enum class DataType : base::type::EnumType { - Checkpoint = 1, Complete = 2 - }; - // Do not use constructor, will run into multiple definition error, use init(PerformanceTracker*) - explicit PerformanceTrackingData(DataType dataType) : m_performanceTracker(nullptr), - m_dataType(dataType), m_file(""), m_line(0), m_func("") {} - inline const std::string* blockName(void) const; - inline const struct timeval* startTime(void) const; - inline const struct timeval* endTime(void) const; - inline const struct timeval* lastCheckpointTime(void) const; - inline const base::PerformanceTracker* performanceTracker(void) const { return m_performanceTracker; } - inline PerformanceTrackingData::DataType dataType(void) const { return m_dataType; } - inline bool firstCheckpoint(void) const { return m_firstCheckpoint; } - inline std::string checkpointId(void) const { return m_checkpointId; } - inline const char* file(void) const { return m_file; } - inline unsigned long int line(void) const { return m_line; } - inline const char* func(void) const { return m_func; } - inline const base::type::string_t* formattedTimeTaken() const { return &m_formattedTimeTaken; } - inline const std::string& loggerId(void) const; - private: - base::PerformanceTracker* m_performanceTracker; - base::type::string_t m_formattedTimeTaken; - PerformanceTrackingData::DataType m_dataType; - bool m_firstCheckpoint; - std::string m_checkpointId; - const char* m_file; - unsigned long int m_line; - const char* m_func; - inline void init(base::PerformanceTracker* performanceTracker, bool firstCheckpoint = false) { - m_performanceTracker = performanceTracker; - m_firstCheckpoint = firstCheckpoint; - } - - friend class el::base::PerformanceTracker; - }; - namespace base { - /// @brief Represents performanceTracker block of code that conditionally adds performance status to log - /// either when goes outside the scope of when checkpoint() is called - class PerformanceTracker : public base::threading::ThreadSafe, public Loggable { - public: - PerformanceTracker(const std::string& blockName, - base::TimestampUnit timestampUnit = base::TimestampUnit::Millisecond, - const std::string& loggerId = std::string(ELPP_CURR_FILE_PERFORMANCE_LOGGER), - bool scopedLog = true, Level level = base::consts::kPerformanceTrackerDefaultLevel) : - m_blockName(blockName), m_timestampUnit(timestampUnit), m_loggerId(loggerId), m_scopedLog(scopedLog), - m_level(level), m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false) { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - // We store it locally so that if user happen to change configuration by the end of scope - // or before calling checkpoint, we still depend on state of configuraton at time of construction - el::Logger* loggerPtr = ELPP->registeredLoggers()->get(loggerId, false); - m_enabled = loggerPtr != nullptr && loggerPtr->m_typedConfigurations->performanceTracking(m_level); - if (m_enabled) { - base::utils::DateTime::gettimeofday(&m_startTime); - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - } - /// @brief Copy constructor - PerformanceTracker(const PerformanceTracker& t) : - m_blockName(t.m_blockName), m_timestampUnit(t.m_timestampUnit), m_loggerId(t.m_loggerId), m_scopedLog(t.m_scopedLog), - m_level(t.m_level), m_hasChecked(t.m_hasChecked), m_lastCheckpointId(t.m_lastCheckpointId), m_enabled(t.m_enabled), - m_startTime(t.m_startTime), m_endTime(t.m_endTime), m_lastCheckpointTime(t.m_lastCheckpointTime) { - } - virtual ~PerformanceTracker(void) { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - if (m_enabled) { - base::threading::ScopedLock scopedLock(lock()); - if (m_scopedLog) { - base::utils::DateTime::gettimeofday(&m_endTime); - base::type::string_t formattedTime = getFormattedTimeTaken(); - PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete); - data.init(this); - data.m_formattedTimeTaken = formattedTime; - PerformanceTrackingCallback* callback = nullptr; - for (const std::pair& h - : ELPP->m_performanceTrackingCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - callback->acquireLock(); - callback->handle(&data); - callback->releaseLock(); - } - } - } - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) - } - /// @brief A checkpoint for current performanceTracker block. - void checkpoint(const std::string& id = std::string(), const char* file = __FILE__, unsigned long int line = __LINE__, const char* func = "") { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - if (m_enabled) { - base::threading::ScopedLock scopedLock(lock()); - base::utils::DateTime::gettimeofday(&m_endTime); - base::type::string_t formattedTime = m_hasChecked ? getFormattedTimeTaken(m_lastCheckpointTime) : ELPP_LITERAL(""); - PerformanceTrackingData data(PerformanceTrackingData::DataType::Checkpoint); - data.init(this); - data.m_checkpointId = id; - data.m_file = file; - data.m_line = line; - data.m_func = func; - data.m_formattedTimeTaken = formattedTime; - PerformanceTrackingCallback* callback = nullptr; - for (const std::pair& h - : ELPP->m_performanceTrackingCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - callback->acquireLock(); - callback->handle(&data); - callback->releaseLock(); - } - } - base::utils::DateTime::gettimeofday(&m_lastCheckpointTime); - m_hasChecked = true; - m_lastCheckpointId = id; - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - ELPP_UNUSED(id); - ELPP_UNUSED(file); - ELPP_UNUSED(line); - ELPP_UNUSED(func); - } - inline Level level(void) const { return m_level; } - private: - std::string m_blockName; - base::TimestampUnit m_timestampUnit; - std::string m_loggerId; - bool m_scopedLog; - Level m_level; - bool m_hasChecked; - std::string m_lastCheckpointId; - bool m_enabled; - struct timeval m_startTime, m_endTime, m_lastCheckpointTime; - - PerformanceTracker(void); - - friend class el::PerformanceTrackingData; - friend class base::DefaultPerformanceTrackingCallback; - - const inline base::type::string_t getFormattedTimeTaken() const { - return getFormattedTimeTaken(m_startTime); - } - - const base::type::string_t getFormattedTimeTaken(struct timeval startTime) const { - if (ELPP->hasFlag(LoggingFlag::FixedTimeFormat)) { - base::type::stringstream_t ss; - ss << base::utils::DateTime::getTimeDifference(m_endTime, - startTime, m_timestampUnit) << " " << base::consts::kTimeFormats[static_cast(m_timestampUnit)].unit; - return ss.str(); - } - return base::utils::DateTime::formatTime(base::utils::DateTime::getTimeDifference(m_endTime, - startTime, m_timestampUnit), m_timestampUnit); - } - - virtual inline void log(el::base::type::ostream_t& os) const { - os << getFormattedTimeTaken(); - } - }; - class DefaultPerformanceTrackingCallback : public PerformanceTrackingCallback { - protected: - void handle(const PerformanceTrackingData* data) { - m_data = data; - base::type::stringstream_t ss; - if (m_data->dataType() == PerformanceTrackingData::DataType::Complete) { - ss << ELPP_LITERAL("Executed [") << m_data->blockName()->c_str() << ELPP_LITERAL("] in [") << *m_data->formattedTimeTaken() << ELPP_LITERAL("]"); - } else { - ss << ELPP_LITERAL("Performance checkpoint"); - if (!m_data->checkpointId().empty()) { - ss << ELPP_LITERAL(" [") << m_data->checkpointId().c_str() << ELPP_LITERAL("]"); - } - ss << ELPP_LITERAL(" for block [") << m_data->blockName()->c_str() << ELPP_LITERAL("] : [") << *m_data->performanceTracker(); - if (!ELPP->hasFlag(LoggingFlag::DisablePerformanceTrackingCheckpointComparison) && m_data->performanceTracker()->m_hasChecked) { - ss << ELPP_LITERAL(" ([") << *m_data->formattedTimeTaken() << ELPP_LITERAL("] from "); - if (m_data->performanceTracker()->m_lastCheckpointId.empty()) { - ss << ELPP_LITERAL("last checkpoint"); - } else { - ss << ELPP_LITERAL("checkpoint '") << m_data->performanceTracker()->m_lastCheckpointId.c_str() << ELPP_LITERAL("'"); - } - ss << ELPP_LITERAL(")]"); - } else { - ss << ELPP_LITERAL("]"); - } - } - el::base::Writer(m_data->performanceTracker()->level(), m_data->file(), m_data->line(), m_data->func()).construct(1, m_data->loggerId().c_str()) << ss.str(); - } - private: - const PerformanceTrackingData* m_data; - }; - } // namespace base - inline const std::string* PerformanceTrackingData::blockName() const { - return const_cast(&m_performanceTracker->m_blockName); - } - inline const struct timeval* PerformanceTrackingData::startTime() const { - return const_cast(&m_performanceTracker->m_startTime); - } - inline const struct timeval* PerformanceTrackingData::endTime() const { - return const_cast(&m_performanceTracker->m_endTime); - } - inline const struct timeval* PerformanceTrackingData::lastCheckpointTime() const { - return const_cast(&m_performanceTracker->m_lastCheckpointTime); - } - inline const std::string& PerformanceTrackingData::loggerId(void) const { return m_performanceTracker->m_loggerId; } - namespace base { - /// @brief Contains some internal debugging tools like crash handler and stack tracer - namespace debug { - class StackTrace : base::NoCopy { - public: - static const std::size_t kMaxStack = 64; - static const std::size_t kStackStart = 2; // We want to skip c'tor and StackTrace::generateNew() - class StackTraceEntry { - public: - StackTraceEntry(std::size_t index, const char* loc, const char* demang, const char* hex, const char* addr) { - m_index = index; - m_location = std::string(loc); - m_demangled = std::string(demang); - m_hex = std::string(hex); - m_addr = std::string(addr); - } - StackTraceEntry(std::size_t index, char* loc) { - m_index = index; - m_location = std::string(loc); - } - std::size_t m_index; - std::string m_location; - std::string m_demangled; - std::string m_hex; - std::string m_addr; - friend std::ostream& operator<<(std::ostream& ss, const StackTraceEntry& si) { - ss << "[" << si.m_index << "] " << si.m_location << (si.m_demangled.empty() ? "" : ":") << si.m_demangled - << (si.m_hex.empty() ? "" : "+") << si.m_hex << si.m_addr; - return ss; - } - - private: - StackTraceEntry(void); - }; - - StackTrace(void) { - generateNew(); - } - - virtual ~StackTrace(void) { - } - - inline std::vector& getLatestStack(void) { - return m_stack; - } - - friend inline std::ostream& operator<<(std::ostream& os, const StackTrace& st) { - std::vector::const_iterator it = st.m_stack.begin(); - while (it != st.m_stack.end()) { - os << " " << *it++ << "\n"; - } - return os; - } - - private: - std::vector m_stack; - - void generateNew(void) { -#if ELPP_STACKTRACE - m_stack.clear(); - void* stack[kMaxStack]; - std::size_t size = backtrace(stack, kMaxStack); - char** strings = backtrace_symbols(stack, size); - if (size > kStackStart) { // Skip StackTrace c'tor and generateNew - for (std::size_t i = kStackStart; i < size; ++i) { - char* mangName = nullptr; - char* hex = nullptr; - char* addr = nullptr; - for (char* c = strings[i]; *c; ++c) { - switch (*c) { - case '(': - mangName = c; - break; - case '+': - hex = c; - break; - case ')': - addr = c; - break; - default: - break; - } - } - // Perform demangling if parsed properly - if (mangName != nullptr && hex != nullptr && addr != nullptr && mangName < hex) { - *mangName++ = '\0'; - *hex++ = '\0'; - *addr++ = '\0'; - int status = 0; - char* demangName = abi::__cxa_demangle(mangName, 0, 0, &status); - // if demangling is successful, output the demangled function name - if (status == 0) { - // Success (see http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html) - StackTraceEntry entry(i - 1, strings[i], demangName, hex, addr); - m_stack.push_back(entry); - } else { - // Not successful - we will use mangled name - StackTraceEntry entry(i - 1, strings[i], mangName, hex, addr); - m_stack.push_back(entry); - } - free(demangName); - } else { - StackTraceEntry entry(i - 1, strings[i]); - m_stack.push_back(entry); - } - } - } - free(strings); -#else - ELPP_INTERNAL_INFO(1, "Stacktrace generation not supported for selected compiler"); -#endif // ELPP_STACKTRACE - } - }; - static std::string crashReason(int sig) { - std::stringstream ss; - bool foundReason = false; - for (int i = 0; i < base::consts::kCrashSignalsCount; ++i) { - if (base::consts::kCrashSignals[i].numb == sig) { - ss << "Application has crashed due to [" << base::consts::kCrashSignals[i].name << "] signal"; - if (ELPP->hasFlag(el::LoggingFlag::LogDetailedCrashReason)) { - ss << std::endl << - " " << base::consts::kCrashSignals[i].brief << std::endl << - " " << base::consts::kCrashSignals[i].detail; - } - foundReason = true; - } - } - if (!foundReason) { - ss << "Application has crashed due to unknown signal [" << sig << "]"; - } - return ss.str(); - } - /// @brief Logs reason of crash from sig - static void logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) { - std::stringstream ss; - ss << "CRASH HANDLED; "; - ss << crashReason(sig); -#if ELPP_STACKTRACE - if (stackTraceIfAvailable) { - ss << std::endl << " ======= Backtrace: =========" << std::endl << base::debug::StackTrace(); - } -#else - ELPP_UNUSED(stackTraceIfAvailable); -#endif // ELPP_STACKTRACE - ELPP_WRITE_LOG(el::base::Writer, level, base::DispatchAction::NormalLog, logger) << ss.str(); - } - static inline void crashAbort(int sig) { - base::utils::abort(sig); - } - /// @brief Default application crash handler - /// - /// @detail This function writes log using 'default' logger, prints stack trace for GCC based compilers and aborts program. - static inline void defaultCrashHandler(int sig) { - base::debug::logCrashReason(sig, true, Level::Fatal, base::consts::kDefaultLoggerId); - base::debug::crashAbort(sig); - } - /// @brief Handles unexpected crashes - class CrashHandler : base::NoCopy { - public: - typedef void (*Handler)(int); - - explicit CrashHandler(bool useDefault) { - if (useDefault) { - setHandler(defaultCrashHandler); - } - } - explicit CrashHandler(const Handler& cHandler) { - setHandler(cHandler); - } - void setHandler(const Handler& cHandler) { - m_handler = cHandler; -#if defined(ELPP_HANDLE_SIGABRT) - int i = 0; // SIGABRT is at base::consts::kCrashSignals[0] -#else - int i = 1; -#endif // defined(ELPP_HANDLE_SIGABRT) - for (; i < base::consts::kCrashSignalsCount; ++i) { - m_handler = signal(base::consts::kCrashSignals[i].numb, cHandler); - } - } - - private: - Handler m_handler; - }; - } // namespace debug - } // namespace base - extern base::debug::CrashHandler elCrashHandler; -#define MAKE_LOGGABLE(ClassType, ClassInstance, OutputStreamInstance) \ -el::base::type::ostream_t& operator<<(el::base::type::ostream_t& OutputStreamInstance, const ClassType& ClassInstance) - /// @brief Initializes syslog with process ID, options and facility. calls closelog() on d'tor - class SysLogInitializer { - public: - SysLogInitializer(const char* processIdent, int options = 0, int facility = 0) { -#if defined(ELPP_SYSLOG) - openlog(processIdent, options, facility); -#else - ELPP_UNUSED(processIdent); - ELPP_UNUSED(options); - ELPP_UNUSED(facility); -#endif // defined(ELPP_SYSLOG) - } - virtual ~SysLogInitializer(void) { -#if defined(ELPP_SYSLOG) - closelog(); -#endif // defined(ELPP_SYSLOG) - } - }; -#define ELPP_INITIALIZE_SYSLOG(id, opt, fac) el::SysLogInitializer elSyslogInit(id, opt, fac) - /// @brief Static helpers for developers - class Helpers : base::StaticClass { - public: - /// @brief Shares logging repository (base::Storage) - static inline void setStorage(base::type::StoragePointer storage) { - ELPP = storage; - } - /// @return Main storage repository - static inline base::type::StoragePointer storage() { - return ELPP; - } - /// @brief Sets application arguments and figures out whats active for logging and whats not. - static inline void setArgs(int argc, char** argv) { - ELPP->setApplicationArguments(argc, argv); - } - /// @copydoc setArgs(int argc, char** argv) - static inline void setArgs(int argc, const char** argv) { - ELPP->setApplicationArguments(argc, const_cast(argv)); - } - /// @brief Overrides default crash handler and installs custom handler. - /// @param crashHandler A functor with no return type that takes single int argument. - /// Handler is a typedef with specification: void (*Handler)(int) - static inline void setCrashHandler(const el::base::debug::CrashHandler::Handler& crashHandler) { - el::elCrashHandler.setHandler(crashHandler); - } - /// @brief Abort due to crash with signal in parameter - /// @param sig Crash signal - static inline void crashAbort(int sig, const char* sourceFile = "", unsigned int long line = 0) { - std::stringstream ss; - ss << base::debug::crashReason(sig).c_str(); - ss << " - [Called el::Helpers::crashAbort(" << sig << ")]"; - if (sourceFile != nullptr && strlen(sourceFile) > 0) { - ss << " - Source: " << sourceFile; - if (line > 0) - ss << ":" << line; - else - ss << " (line number not specified)"; - } - base::utils::abort(sig, ss.str()); - } - /// @brief Logs reason of crash as per sig - /// @param sig Crash signal - /// @param stackTraceIfAvailable Includes stack trace if available - /// @param level Logging level - /// @param logger Logger to use for logging - static inline void logCrashReason(int sig, bool stackTraceIfAvailable = false, - Level level = Level::Fatal, const char* logger = base::consts::kDefaultLoggerId) { - el::base::debug::logCrashReason(sig, stackTraceIfAvailable, level, logger); - } - /// @brief Installs pre rollout callback, this callback is triggered when log file is about to be rolled out - /// (can be useful for backing up) - static inline void installPreRollOutCallback(const PreRollOutCallback& callback) { - ELPP->setPreRollOutCallback(callback); - } - /// @brief Uninstalls pre rollout callback - static inline void uninstallPreRollOutCallback(void) { - ELPP->unsetPreRollOutCallback(); - } - /// @brief Installs post log dispatch callback, this callback is triggered when log is dispatched - template - static inline bool installLogDispatchCallback(const std::string& id) { - return ELPP->installLogDispatchCallback(id); - } - /// @brief Uninstalls log dispatch callback - template - static inline void uninstallLogDispatchCallback(const std::string& id) { - ELPP->uninstallLogDispatchCallback(id); - } - template - static inline T* logDispatchCallback(const std::string& id) { - return ELPP->logDispatchCallback(id); - } - /// @brief Installs post performance tracking callback, this callback is triggered when performance tracking is finished - template - static inline bool installPerformanceTrackingCallback(const std::string& id) { - return ELPP->installPerformanceTrackingCallback(id); - } - /// @brief Uninstalls post performance tracking handler - template - static inline void uninstallPerformanceTrackingCallback(const std::string& id) { - ELPP->uninstallPerformanceTrackingCallback(id); - } - template - static inline T* performanceTrackingCallback(const std::string& id) { - return ELPP->performanceTrackingCallback(id); - } - /// @brief Converts template to std::string - useful for loggable classes to log containers within log(std::ostream&) const - template - static std::string convertTemplateToStdString(const T& templ) { - el::Logger* logger = - ELPP->registeredLoggers()->get(el::base::consts::kDefaultLoggerId); - if (logger == nullptr) { - return std::string(); - } - base::MessageBuilder b; - b.initialize(logger); - logger->acquireLock(); - b << templ; -#if defined(ELPP_UNICODE) - std::string s = std::string(logger->stream().str().begin(), logger->stream().str().end()); -#else - std::string s = logger->stream().str(); -#endif // defined(ELPP_UNICODE) - logger->stream().str(ELPP_LITERAL("")); - logger->releaseLock(); - return s; - } - /// @brief Returns command line arguments (pointer) provided to easylogging++ - static inline const el::base::utils::CommandLineArgs* commandLineArgs(void) { - return ELPP->commandLineArgs(); - } - /// @brief Installs user defined format specifier and handler - static inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) { - ELPP->installCustomFormatSpecifier(customFormatSpecifier); - } - /// @brief Uninstalls user defined format specifier and handler - static inline bool uninstallCustomFormatSpecifier(const char* formatSpecifier) { - return ELPP->uninstallCustomFormatSpecifier(formatSpecifier); - } - /// @brief Returns true if custom format specifier is installed - static inline bool hasCustomFormatSpecifier(const char* formatSpecifier) { - return ELPP->hasCustomFormatSpecifier(formatSpecifier); - } - static inline void validateFileRolling(Logger* logger, Level level) { - if (logger == nullptr) return; - logger->m_typedConfigurations->validateFileRolling(level, ELPP->preRollOutCallback()); - } - }; - /// @brief Static helpers to deal with loggers and their configurations - class Loggers : base::StaticClass { - public: - /// @brief Gets existing or registers new logger - static inline Logger* getLogger(const std::string& identity, bool registerIfNotAvailable = true) { - base::threading::ScopedLock scopedLock(ELPP->lock()); - return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable); - } - /// @brief Unregisters logger - use it only when you know what you are doing, you may unregister - /// loggers initialized / used by third-party libs. - static inline bool unregisterLogger(const std::string& identity) { - base::threading::ScopedLock scopedLock(ELPP->lock()); - return ELPP->registeredLoggers()->remove(identity); - } - /// @brief Whether or not logger with id is registered - static inline bool hasLogger(const std::string& identity) { - base::threading::ScopedLock scopedLock(ELPP->lock()); - return ELPP->registeredLoggers()->has(identity); - } - /// @brief Reconfigures specified logger with new configurations - static inline Logger* reconfigureLogger(Logger* logger, const Configurations& configurations) { - if (!logger) return nullptr; - logger->configure(configurations); - return logger; - } - /// @brief Reconfigures logger with new configurations after looking it up using identity - static inline Logger* reconfigureLogger(const std::string& identity, const Configurations& configurations) { - return Loggers::reconfigureLogger(Loggers::getLogger(identity), configurations); - } - /// @brief Reconfigures logger's single configuration - static inline Logger* reconfigureLogger(const std::string& identity, ConfigurationType configurationType, - const std::string& value) { - Logger* logger = Loggers::getLogger(identity); - if (logger == nullptr) { - return nullptr; - } - logger->configurations()->set(Level::Global, configurationType, value); - logger->reconfigure(); - return logger; - } - /// @brief Reconfigures all the existing loggers with new configurations - static inline void reconfigureAllLoggers(const Configurations& configurations) { - for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin(); - it != ELPP->registeredLoggers()->end(); ++it) { - Loggers::reconfigureLogger(it->second, configurations); - } - } - /// @brief Reconfigures single configuration for all the loggers - static inline void reconfigureAllLoggers(ConfigurationType configurationType, const std::string& value) { - reconfigureAllLoggers(Level::Global, configurationType, value); - } - /// @brief Reconfigures single configuration for all the loggers for specified level - static inline void reconfigureAllLoggers(Level level, ConfigurationType configurationType, - const std::string& value) { - for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin(); - it != ELPP->registeredLoggers()->end(); ++it) { - Logger* logger = it->second; - logger->configurations()->set(level, configurationType, value); - logger->reconfigure(); - } - } - /// @brief Sets default configurations. This configuration is used for future (and conditionally for existing) loggers - static inline void setDefaultConfigurations(const Configurations& configurations, bool reconfigureExistingLoggers = false) { - ELPP->registeredLoggers()->setDefaultConfigurations(configurations); - if (reconfigureExistingLoggers) { - Loggers::reconfigureAllLoggers(configurations); - } - } - /// @brief Returns current default - static inline const Configurations* defaultConfigurations(void) { - return ELPP->registeredLoggers()->defaultConfigurations(); - } - /// @brief Returns log stream reference pointer if needed by user - static inline const base::LogStreamsReferenceMap* logStreamsReference(void) { - return ELPP->registeredLoggers()->logStreamsReference(); - } - /// @brief Default typed configuration based on existing defaultConf - static base::TypedConfigurations defaultTypedConfigurations(void) { - return base::TypedConfigurations( - ELPP->registeredLoggers()->defaultConfigurations(), - ELPP->registeredLoggers()->logStreamsReference()); - } - /// @brief Populates all logger IDs in current repository. - /// @param [out] targetList List of fill up. - static inline std::vector* populateAllLoggerIds(std::vector* targetList) { - targetList->clear(); - for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->list().begin(); - it != ELPP->registeredLoggers()->list().end(); ++it) { - targetList->push_back(it->first); - } - return targetList; - } - /// @brief Sets configurations from global configuration file. - static void configureFromGlobal(const char* globalConfigurationFilePath) { - std::ifstream gcfStream(globalConfigurationFilePath, std::ifstream::in); - ELPP_ASSERT(gcfStream.is_open(), "Unable to open global configuration file [" << globalConfigurationFilePath - << "] for parsing."); - std::string line = std::string(); - std::stringstream ss; - Logger* logger = nullptr; - auto configure = [&](void) { - ELPP_INTERNAL_INFO(8, "Configuring logger: '" << logger->id() << "' with configurations \n" << ss.str() - << "\n--------------"); - Configurations c; - c.parseFromText(ss.str()); - logger->configure(c); - }; - while (gcfStream.good()) { - std::getline(gcfStream, line); - ELPP_INTERNAL_INFO(1, "Parsing line: " << line); - base::utils::Str::trim(line); - if (Configurations::Parser::isComment(line)) continue; - Configurations::Parser::ignoreComments(&line); - base::utils::Str::trim(line); - if (line.size() > 2 && base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLoggerId))) { - if (!ss.str().empty() && logger != nullptr) { - configure(); - } - ss.str(std::string("")); - line = line.substr(2); - base::utils::Str::trim(line); - if (line.size() > 1) { - ELPP_INTERNAL_INFO(1, "Getting logger: '" << line << "'"); - logger = getLogger(line); - } - } else { - ss << line << "\n"; - } - } - if (!ss.str().empty() && logger != nullptr) { - configure(); - } - } - /// @brief Configures loggers using command line arg. Ensure you have already set command line args, - /// @return False if invalid argument or argument with no value provided, true if attempted to configure logger. - /// If true is returned that does not mean it has been configured successfully, it only means that it - /// has attempeted to configure logger using configuration file provided in argument - static inline bool configureFromArg(const char* argKey) { -#if defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS) - ELPP_UNUSED(argKey); -#else - if (!Helpers::commandLineArgs()->hasParamWithValue(argKey)) { - return false; - } - configureFromGlobal(Helpers::commandLineArgs()->getParamValue(argKey)); -#endif // defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS) - return true; - } - /// @brief Flushes all loggers for all levels - Be careful if you dont know how many loggers are registered - static inline void flushAll(void) { - ELPP->registeredLoggers()->flushAll(); - } - /// @brief Adds logging flag used internally. - static inline void addFlag(LoggingFlag flag) { - ELPP->addFlag(flag); - } - /// @brief Removes logging flag used internally. - static inline void removeFlag(LoggingFlag flag) { - ELPP->removeFlag(flag); - } - /// @brief Determines whether or not certain flag is active - static inline bool hasFlag(LoggingFlag flag) { - return ELPP->hasFlag(flag); - } - /// @brief Adds flag and removes it when scope goes out - class ScopedAddFlag { - public: - ScopedAddFlag(LoggingFlag flag) : m_flag(flag) { Loggers::addFlag(m_flag); } - ~ScopedAddFlag(void) { Loggers::removeFlag(m_flag); } - private: - LoggingFlag m_flag; - }; - /// @brief Removes flag and add it when scope goes out - class ScopedRemoveFlag { - public: - ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) { Loggers::removeFlag(m_flag); } - ~ScopedRemoveFlag(void) { Loggers::addFlag(m_flag); } - private: - LoggingFlag m_flag; - }; - /// @brief Sets hierarchy for logging. Needs to enable logging flag (HierarchicalLogging) - static inline void setLoggingLevel(Level level) { - ELPP->setLoggingLevel(level); - } - /// @brief Sets verbose level on the fly - static inline void setVerboseLevel(base::type::VerboseLevel level) { - ELPP->vRegistry()->setLevel(level); - } - /// @brief Gets current verbose level - static inline base::type::VerboseLevel verboseLevel(void) { - return ELPP->vRegistry()->level(); - } - /// @brief Sets vmodules as specified (on the fly) - static inline void setVModules(const char* modules) { - if (ELPP->vRegistry()->vModulesEnabled()) { - ELPP->vRegistry()->setModules(modules); - } - } - /// @brief Clears vmodules - static inline void clearVModules(void) { - ELPP->vRegistry()->clearModules(); - } - }; - class VersionInfo : base::StaticClass { - public: - /// @brief Current version number - static inline const std::string version(void) { return std::string("9.84"); } - /// @brief Release date of current version - static inline const std::string releaseDate(void) { return std::string("29-07-2016 1221hrs"); } - }; -} // namespace el -#undef VLOG_IS_ON -/// @brief Determines whether verbose logging is on for specified level current file. -#define VLOG_IS_ON(verboseLevel) (ELPP->vRegistry()->allowed(verboseLevel, __FILE__)) -#undef TIMED_BLOCK -#undef TIMED_SCOPE -#undef TIMED_FUNC -#undef ELPP_MIN_UNIT -#if defined(ELPP_PERFORMANCE_MICROSECONDS) -# define ELPP_MIN_UNIT el::base::TimestampUnit::Microsecond -#else -# define ELPP_MIN_UNIT el::base::TimestampUnit::Millisecond -#endif // (defined(ELPP_PERFORMANCE_MICROSECONDS)) -/// @brief Performance tracked scope. Performance gets written when goes out of scope using -/// 'performance' logger. -/// -/// @detail Please note in order to check the performance at a certain time you can use obj.checkpoint(); -/// @see el::base::PerformanceTracker -/// @see el::base::PerformanceTracker::checkpoint -// Note: Do not surround this definition with null macro because of obj instance -#define TIMED_SCOPE(obj, blockname) el::base::PerformanceTracker obj(blockname, ELPP_MIN_UNIT) -#define TIMED_BLOCK(obj, blockName) for (struct { int i; el::base::PerformanceTracker timer; } obj = { 0, \ -el::base::PerformanceTracker(blockName, ELPP_MIN_UNIT) }; obj.i < 1; ++obj.i) -/// @brief Performance tracked function. Performance gets written when goes out of scope using -/// 'performance' logger. -/// -/// @detail Please note in order to check the performance at a certain time you can use obj.checkpoint(); -/// @see el::base::PerformanceTracker -/// @see el::base::PerformanceTracker::checkpoint -#define TIMED_FUNC(obj) TIMED_SCOPE(obj, ELPP_FUNC) -#undef PERFORMANCE_CHECKPOINT -#undef PERFORMANCE_CHECKPOINT_WITH_ID -#define PERFORMANCE_CHECKPOINT(obj) obj.checkpoint(std::string(), __FILE__, __LINE__, ELPP_FUNC) -#define PERFORMANCE_CHECKPOINT_WITH_ID(obj, id) obj.checkpoint(id, __FILE__, __LINE__, ELPP_FUNC) -#undef ELPP_COUNTER -#undef ELPP_COUNTER_POS -/// @brief Gets hit counter for file/line -#define ELPP_COUNTER (ELPP->hitCounters()->getCounter(__FILE__, __LINE__)) -/// @brief Gets hit counter position for file/line, -1 if not registered yet -#define ELPP_COUNTER_POS (ELPP_COUNTER == nullptr ? -1 : ELPP_COUNTER->hitCounts()) -// Undef levels to support LOG(LEVEL) -#undef INFO -#undef WARNING -#undef DEBUG -#undef ERROR -#undef FATAL -#undef TRACE -#undef VERBOSE -// Undef existing -#undef CINFO -#undef CWARNING -#undef CDEBUG -#undef CFATAL -#undef CERROR -#undef CTRACE -#undef CVERBOSE -#undef CINFO_IF -#undef CWARNING_IF -#undef CDEBUG_IF -#undef CERROR_IF -#undef CFATAL_IF -#undef CTRACE_IF -#undef CVERBOSE_IF -#undef CINFO_EVERY_N -#undef CWARNING_EVERY_N -#undef CDEBUG_EVERY_N -#undef CERROR_EVERY_N -#undef CFATAL_EVERY_N -#undef CTRACE_EVERY_N -#undef CVERBOSE_EVERY_N -#undef CINFO_AFTER_N -#undef CWARNING_AFTER_N -#undef CDEBUG_AFTER_N -#undef CERROR_AFTER_N -#undef CFATAL_AFTER_N -#undef CTRACE_AFTER_N -#undef CVERBOSE_AFTER_N -#undef CINFO_N_TIMES -#undef CWARNING_N_TIMES -#undef CDEBUG_N_TIMES -#undef CERROR_N_TIMES -#undef CFATAL_N_TIMES -#undef CTRACE_N_TIMES -#undef CVERBOSE_N_TIMES -// Normal logs -#if ELPP_INFO_LOG -# define CINFO(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE(writer, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel)) writer(\ -el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#else -# define CVERBOSE(writer, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// Conditional logs -#if ELPP_INFO_LOG -# define CINFO_IF(writer, condition_, dispatchAction, ...) \ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel) && (condition_)) writer( \ -el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#else -# define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// Occasional logs -#if ELPP_INFO_LOG -# define CINFO_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...)\ -CVERBOSE_IF(writer, ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion), vlevel, dispatchAction, __VA_ARGS__) -#else -# define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// After N logs -#if ELPP_INFO_LOG -# define CINFO_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...)\ -CVERBOSE_IF(writer, ELPP->validateAfterNCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__) -#else -# define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// N Times logs -#if ELPP_INFO_LOG -# define CINFO_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...)\ -CVERBOSE_IF(writer, ELPP->validateNTimesCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__) -#else -# define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// -// Custom Loggers - Requires (level, dispatchAction, loggerId/s) -// -// undef existing -#undef CLOG -#undef CLOG_VERBOSE -#undef CVLOG -#undef CLOG_IF -#undef CLOG_VERBOSE_IF -#undef CVLOG_IF -#undef CLOG_EVERY_N -#undef CVLOG_EVERY_N -#undef CLOG_AFTER_N -#undef CVLOG_AFTER_N -#undef CLOG_N_TIMES -#undef CVLOG_N_TIMES -// Normal logs -#define CLOG(LEVEL, ...)\ -C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG(vlevel, ...) CVERBOSE(el::base::Writer, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -// Conditional logs -#define CLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_IF(condition, vlevel, ...)\ -CVERBOSE_IF(el::base::Writer, condition, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -// Hit counts based logs -#define CLOG_EVERY_N(n, LEVEL, ...)\ -C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_EVERY_N(n, vlevel, ...)\ -CVERBOSE_EVERY_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CLOG_AFTER_N(n, LEVEL, ...)\ -C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_AFTER_N(n, vlevel, ...)\ -CVERBOSE_AFTER_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CLOG_N_TIMES(n, LEVEL, ...)\ -C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_N_TIMES(n, vlevel, ...)\ -CVERBOSE_N_TIMES(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -// -// Default Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros -// -// undef existing -#undef LOG -#undef VLOG -#undef LOG_IF -#undef VLOG_IF -#undef LOG_EVERY_N -#undef VLOG_EVERY_N -#undef LOG_AFTER_N -#undef VLOG_AFTER_N -#undef LOG_N_TIMES -#undef VLOG_N_TIMES -#undef ELPP_CURR_FILE_LOGGER_ID -#if defined(ELPP_DEFAULT_LOGGER) -# define ELPP_CURR_FILE_LOGGER_ID ELPP_DEFAULT_LOGGER -#else -# define ELPP_CURR_FILE_LOGGER_ID el::base::consts::kDefaultLoggerId -#endif -#undef ELPP_TRACE -#define ELPP_TRACE CLOG(TRACE, ELPP_CURR_FILE_LOGGER_ID) -// Normal logs -#define LOG(LEVEL) CLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG(vlevel) CVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Conditional logs -#define LOG_IF(condition, LEVEL) CLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_IF(condition, vlevel) CVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Hit counts based logs -#define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_EVERY_N(n, vlevel) CVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define LOG_AFTER_N(n, LEVEL) CLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_AFTER_N(n, vlevel) CVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define LOG_N_TIMES(n, LEVEL) CLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_N_TIMES(n, vlevel) CVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Generic PLOG() -#undef CPLOG -#undef CPLOG_IF -#undef PLOG -#undef PLOG_IF -#undef DCPLOG -#undef DCPLOG_IF -#undef DPLOG -#undef DPLOG_IF -#define CPLOG(LEVEL, ...)\ -C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CPLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::PErrorWriter, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define DCPLOG(LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define DCPLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::PErrorWriter, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define PLOG(LEVEL) CPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define PLOG_IF(condition, LEVEL) CPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DPLOG(LEVEL) DCPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DPLOG_IF(condition, LEVEL) DCPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -// Generic SYSLOG() -#undef CSYSLOG -#undef CSYSLOG_IF -#undef CSYSLOG_EVERY_N -#undef CSYSLOG_AFTER_N -#undef CSYSLOG_N_TIMES -#undef SYSLOG -#undef SYSLOG_IF -#undef SYSLOG_EVERY_N -#undef SYSLOG_AFTER_N -#undef SYSLOG_N_TIMES -#undef DCSYSLOG -#undef DCSYSLOG_IF -#undef DCSYSLOG_EVERY_N -#undef DCSYSLOG_AFTER_N -#undef DCSYSLOG_N_TIMES -#undef DSYSLOG -#undef DSYSLOG_IF -#undef DSYSLOG_EVERY_N -#undef DSYSLOG_AFTER_N -#undef DSYSLOG_N_TIMES -#if defined(ELPP_SYSLOG) -# define CSYSLOG(LEVEL, ...)\ -C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_EVERY_N(n, LEVEL, ...) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_AFTER_N(n, LEVEL, ...) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_N_TIMES(n, LEVEL, ...) C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define SYSLOG(LEVEL) CSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_IF(condition, LEVEL) CSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_EVERY_N(n, LEVEL) CSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_AFTER_N(n, LEVEL) CSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_N_TIMES(n, LEVEL) CSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define DCSYSLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::Writer, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_EVERY_N(n, LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_AFTER_N(n, LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_N_TIMES(n, LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DSYSLOG(LEVEL) DCSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_IF(condition, LEVEL) DCSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_EVERY_N(n, LEVEL) DCSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_AFTER_N(n, LEVEL) DCSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_N_TIMES(n, LEVEL) DCSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId) -#else -# define CSYSLOG(LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter() -# define SYSLOG(LEVEL) el::base::NullWriter() -# define SYSLOG_IF(condition, LEVEL) el::base::NullWriter() -# define SYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter() -# define SYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter() -# define SYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter() -# define DCSYSLOG(LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter() -# define DSYSLOG(LEVEL) el::base::NullWriter() -# define DSYSLOG_IF(condition, LEVEL) el::base::NullWriter() -# define DSYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter() -# define DSYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter() -# define DSYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter() -#endif // defined(ELPP_SYSLOG) -// -// Custom Debug Only Loggers - Requires (level, loggerId/s) -// -// undef existing -#undef DCLOG -#undef DCVLOG -#undef DCLOG_IF -#undef DCVLOG_IF -#undef DCLOG_EVERY_N -#undef DCVLOG_EVERY_N -#undef DCLOG_AFTER_N -#undef DCVLOG_AFTER_N -#undef DCLOG_N_TIMES -#undef DCVLOG_N_TIMES -// Normal logs -#define DCLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG(LEVEL, __VA_ARGS__) -#define DCLOG_VERBOSE(vlevel, ...) if (ELPP_DEBUG_LOG) CLOG_VERBOSE(vlevel, __VA_ARGS__) -#define DCVLOG(vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG(vlevel, __VA_ARGS__) -// Conditional logs -#define DCLOG_IF(condition, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_IF(condition, LEVEL, __VA_ARGS__) -#define DCVLOG_IF(condition, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_IF(condition, vlevel, __VA_ARGS__) -// Hit counts based logs -#define DCLOG_EVERY_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_EVERY_N(n, LEVEL, __VA_ARGS__) -#define DCVLOG_EVERY_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_EVERY_N(n, vlevel, __VA_ARGS__) -#define DCLOG_AFTER_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_AFTER_N(n, LEVEL, __VA_ARGS__) -#define DCVLOG_AFTER_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_AFTER_N(n, vlevel, __VA_ARGS__) -#define DCLOG_N_TIMES(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_N_TIMES(n, LEVEL, __VA_ARGS__) -#define DCVLOG_N_TIMES(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_N_TIMES(n, vlevel, __VA_ARGS__) -// -// Default Debug Only Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros -// -// undef existing -#undef DLOG -#undef DVLOG -#undef DLOG_IF -#undef DVLOG_IF -#undef DLOG_EVERY_N -#undef DVLOG_EVERY_N -#undef DLOG_AFTER_N -#undef DVLOG_AFTER_N -#undef DLOG_N_TIMES -#undef DVLOG_N_TIMES -// Normal logs -#define DLOG(LEVEL) DCLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG(vlevel) DCVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Conditional logs -#define DLOG_IF(condition, LEVEL) DCLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_IF(condition, vlevel) DCVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Hit counts based logs -#define DLOG_EVERY_N(n, LEVEL) DCLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_EVERY_N(n, vlevel) DCVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define DLOG_AFTER_N(n, LEVEL) DCLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_AFTER_N(n, vlevel) DCVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define DLOG_N_TIMES(n, LEVEL) DCLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_N_TIMES(n, vlevel) DCVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Check macros -#undef CCHECK -#undef CPCHECK -#undef CCHECK_EQ -#undef CCHECK_NE -#undef CCHECK_LT -#undef CCHECK_GT -#undef CCHECK_LE -#undef CCHECK_GE -#undef CCHECK_BOUNDS -#undef CCHECK_NOTNULL -#undef CCHECK_STRCASEEQ -#undef CCHECK_STRCASENE -#undef CHECK -#undef PCHECK -#undef CHECK_EQ -#undef CHECK_NE -#undef CHECK_LT -#undef CHECK_GT -#undef CHECK_LE -#undef CHECK_GE -#undef CHECK_BOUNDS -#undef CHECK_NOTNULL -#undef CHECK_STRCASEEQ -#undef CHECK_STRCASENE -#define CCHECK(condition, ...) CLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] " -#define CPCHECK(condition, ...) CPLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] " -#define CHECK(condition) CCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#define PCHECK(condition) CPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#define CCHECK_EQ(a, b, ...) CCHECK(a == b, __VA_ARGS__) -#define CCHECK_NE(a, b, ...) CCHECK(a != b, __VA_ARGS__) -#define CCHECK_LT(a, b, ...) CCHECK(a < b, __VA_ARGS__) -#define CCHECK_GT(a, b, ...) CCHECK(a > b, __VA_ARGS__) -#define CCHECK_LE(a, b, ...) CCHECK(a <= b, __VA_ARGS__) -#define CCHECK_GE(a, b, ...) CCHECK(a >= b, __VA_ARGS__) -#define CCHECK_BOUNDS(val, min, max, ...) CCHECK(val >= min && val <= max, __VA_ARGS__) -#define CHECK_EQ(a, b) CCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_NE(a, b) CCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_LT(a, b) CCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_GT(a, b) CCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_LE(a, b) CCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_GE(a, b) CCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_BOUNDS(val, min, max) CCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID) -#define CCHECK_NOTNULL(ptr, ...) CCHECK((ptr) != nullptr, __VA_ARGS__) -#define CCHECK_STREQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " == " << #str2 << "] " -#define CCHECK_STRNE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " != " << #str2 << "] " -#define CCHECK_STRCASEEQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " == " << #str2 << "] " -#define CCHECK_STRCASENE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " != " << #str2 << "] " -#define CHECK_NOTNULL(ptr) CCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STREQ(str1, str2) CCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STRNE(str1, str2) CCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STRCASEEQ(str1, str2) CCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STRCASENE(str1, str2) CCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#undef DCCHECK -#undef DCCHECK_EQ -#undef DCCHECK_NE -#undef DCCHECK_LT -#undef DCCHECK_GT -#undef DCCHECK_LE -#undef DCCHECK_GE -#undef DCCHECK_BOUNDS -#undef DCCHECK_NOTNULL -#undef DCCHECK_STRCASEEQ -#undef DCCHECK_STRCASENE -#undef DCPCHECK -#undef DCHECK -#undef DCHECK_EQ -#undef DCHECK_NE -#undef DCHECK_LT -#undef DCHECK_GT -#undef DCHECK_LE -#undef DCHECK_GE -#undef DCHECK_BOUNDS_ -#undef DCHECK_NOTNULL -#undef DCHECK_STRCASEEQ -#undef DCHECK_STRCASENE -#undef DPCHECK -#define DCCHECK(condition, ...) if (ELPP_DEBUG_LOG) CCHECK(condition, __VA_ARGS__) -#define DCCHECK_EQ(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_EQ(a, b, __VA_ARGS__) -#define DCCHECK_NE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_NE(a, b, __VA_ARGS__) -#define DCCHECK_LT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LT(a, b, __VA_ARGS__) -#define DCCHECK_GT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GT(a, b, __VA_ARGS__) -#define DCCHECK_LE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LE(a, b, __VA_ARGS__) -#define DCCHECK_GE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GE(a, b, __VA_ARGS__) -#define DCCHECK_BOUNDS(val, min, max, ...) if (ELPP_DEBUG_LOG) CCHECK_BOUNDS(val, min, max, __VA_ARGS__) -#define DCCHECK_NOTNULL(ptr, ...) if (ELPP_DEBUG_LOG) CCHECK_NOTNULL((ptr), __VA_ARGS__) -#define DCCHECK_STREQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STREQ(str1, str2, __VA_ARGS__) -#define DCCHECK_STRNE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRNE(str1, str2, __VA_ARGS__) -#define DCCHECK_STRCASEEQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASEEQ(str1, str2, __VA_ARGS__) -#define DCCHECK_STRCASENE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASENE(str1, str2, __VA_ARGS__) -#define DCPCHECK(condition, ...) if (ELPP_DEBUG_LOG) CPCHECK(condition, __VA_ARGS__) -#define DCHECK(condition) DCCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_EQ(a, b) DCCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_NE(a, b) DCCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_LT(a, b) DCCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_GT(a, b) DCCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_LE(a, b) DCCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_GE(a, b) DCCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_BOUNDS(val, min, max) DCCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_NOTNULL(ptr) DCCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STREQ(str1, str2) DCCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STRNE(str1, str2) DCCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STRCASEEQ(str1, str2) DCCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STRCASENE(str1, str2) DCCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DPCHECK(condition) DCPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#if defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING) -# define ELPP_USE_DEF_CRASH_HANDLER false -#else -# define ELPP_USE_DEF_CRASH_HANDLER true -#endif // defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING) -#define ELPP_CRASH_HANDLER_INIT -#define ELPP_INIT_EASYLOGGINGPP(val) \ -ELPP_INITI_BASIC_DECLR \ -namespace el { \ -namespace base { \ -el::base::type::StoragePointer elStorage(val); \ -} \ -el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER); \ -} - -#if ELPP_ASYNC_LOGGING -# define INITIALIZE_EASYLOGGINGPP\ -ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()),\ -new el::base::AsyncDispatchWorker()))\ - -#else -# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()))) -#endif // ELPP_ASYNC_LOGGING -#define INITIALIZE_NULL_EASYLOGGINGPP\ -ELPP_INITI_BASIC_DECLR\ -namespace el {\ -namespace base {\ -el::base::type::StoragePointer elStorage;\ -}\ -el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\ -} -// NOTE: no ELPP_INITI_BASIC_DECLR when sharing - causes double free corruption on external symbols -#define SHARE_EASYLOGGINGPP(initializedStorage)\ -namespace el {\ -namespace base {\ -el::base::type::StoragePointer elStorage(initializedStorage);\ -}\ -el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\ -} - -#if defined(ELPP_UNICODE) -# define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv); std::locale::global(std::locale("")) -#else -# define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv) -#endif // defined(ELPP_UNICODE) -#endif // EASYLOGGINGPP_H \ No newline at end of file diff --git a/internal/tinyxml2-3.0.0/CMakeLists.txt b/internal/tinyxml2-3.0.0/CMakeLists.txt deleted file mode 100644 index e8d0abb..0000000 --- a/internal/tinyxml2-3.0.0/CMakeLists.txt +++ /dev/null @@ -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 $) diff --git a/internal/tinyxml2-3.0.0/Makefile b/internal/tinyxml2-3.0.0/Makefile deleted file mode 100644 index aab6293..0000000 --- a/internal/tinyxml2-3.0.0/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -all: xmltest -xmltest: xmltest.cpp tinyxml2.cpp tinyxml2.h -test: clean xmltest - ./xmltest -clean: - rm -f *.o xmltest diff --git a/po/ar.po b/po/ar.po index 642cb11..b0b822e 100644 --- a/po/ar.po +++ b/po/ar.po @@ -455,8 +455,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "الإعدادات المحملة غير متواÙقة مع --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "الدليل \"%s\" غير موجود. هل ينبغي إنشاؤه؟ (yØŒ n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "الدليل \"%s\" غير موجود. هل ينبغي إنشاؤه؟ (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/be.po b/po/be.po index d4272c4..1d0860d 100644 --- a/po/be.po +++ b/po/be.po @@ -419,8 +419,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "ДырÑÐºÑ‚Ð¾Ñ€Ñ‹Ñ \"%s\" не Ñ–Ñнуе.Ці Ñ‚Ñ€Ñба Ñе Ñтварыць? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "ДырÑÐºÑ‚Ð¾Ñ€Ñ‹Ñ \"%s\" не Ñ–Ñнуе.Ці Ñ‚Ñ€Ñба Ñе Ñтварыць? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/bg.po b/po/bg.po index cc8dbee..c51cb83 100644 --- a/po/bg.po +++ b/po/bg.po @@ -446,8 +446,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "ДиректориÑта \"%s\" не ÑъщеÑтвува. Да бъде ли Ñъздадена? (д,н) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "ДиректориÑта \"%s\" не ÑъщеÑтвува. Да бъде ли Ñъздадена? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/bs.po b/po/bs.po index 139ad6f..3e96025 100644 --- a/po/bs.po +++ b/po/bs.po @@ -418,7 +418,7 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " msgstr "" msgid "" diff --git a/po/ca.po b/po/ca.po index 7b5fde8..7f7db30 100644 --- a/po/ca.po +++ b/po/ca.po @@ -450,9 +450,9 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " msgstr "" -"El directori \"%s\" no existeix. Desitges crear el nou directori? (y,n) " +"El directori \"%s\" no existeix. Desitges crear el nou directori? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/cs.po b/po/cs.po index ee4271b..07dfd10 100644 --- a/po/cs.po +++ b/po/cs.po @@ -450,8 +450,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Adresář \"%s\" neexistuje, má být vytvoÅ™en? (\"y\"-ano, \"n\"-ne) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Adresář \"%s\" neexistuje, má být vytvoÅ™en? (\"y\"-ano, \"N\"-ne) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/da.po b/po/da.po index 9b83479..e76bd87 100644 --- a/po/da.po +++ b/po/da.po @@ -451,8 +451,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Mappen \"%s\" eksisterer ikke. Skal den oprettes? (y, n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Mappen \"%s\" eksisterer ikke. Skal den oprettes? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/de.po b/po/de.po index 855db15..46b0cfe 100644 --- a/po/de.po +++ b/po/de.po @@ -517,8 +517,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "Die geladene Konfiguration ist mit --reverse nicht kompatibel\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Das Verzeichnis »%s« existiert nicht. Soll es angelegt werden? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Das Verzeichnis »%s« existiert nicht. Soll es angelegt werden? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/de_AT.po b/po/de_AT.po index add1a6c..1a632cf 100644 --- a/po/de_AT.po +++ b/po/de_AT.po @@ -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" diff --git a/po/de_CH.po b/po/de_CH.po index b2a728e..deb0fdc 100644 --- a/po/de_CH.po +++ b/po/de_CH.po @@ -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" diff --git a/po/de_DE.po b/po/de_DE.po index 93e6d9b..d618671 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -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" diff --git a/po/el.po b/po/el.po index 6205618..d07031c 100644 --- a/po/el.po +++ b/po/el.po @@ -443,8 +443,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Ο φάκελος \"%s\" δεν υπάÏχει. Îα τον δημιουÏγήσω? (y/n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Ο φάκελος \"%s\" δεν υπάÏχει. Îα τον δημιουÏγήσω? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/encfs.pot b/po/encfs.pot index 7ace7a0..4fc4c3a 100644 --- a/po/encfs.pot +++ b/po/encfs.pot @@ -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: " diff --git a/po/eo.po b/po/eo.po index 8761167..2598bca 100644 --- a/po/eo.po +++ b/po/eo.po @@ -423,8 +423,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "La dosierujo \"%s\" ne ekzistas. Ĉu Äi estu kreota? " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "La dosierujo \"%s\" ne ekzistas. Ĉu Äi estu kreota? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/es.po b/po/es.po index d830da6..d939b6f 100644 --- a/po/es.po +++ b/po/es.po @@ -512,8 +512,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "La configuración cargada no es compatible con --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "El directorio \"%s\" no existe. ¿Debería ser creado? (S,N) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "El directorio \"%s\" no existe. ¿Debería ser creado? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/es_ES.po b/po/es_ES.po index 794cdf9..2637b94 100644 --- a/po/es_ES.po +++ b/po/es_ES.po @@ -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" diff --git a/po/es_PE.po b/po/es_PE.po index b953360..4b9a1bc 100644 --- a/po/es_PE.po +++ b/po/es_PE.po @@ -420,7 +420,7 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " msgstr "" msgid "" diff --git a/po/et.po b/po/et.po index aa75a9a..368940a 100644 --- a/po/et.po +++ b/po/et.po @@ -415,7 +415,7 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " msgstr "" msgid "" diff --git a/po/fi.po b/po/fi.po index c3b7233..6de098f 100644 --- a/po/fi.po +++ b/po/fi.po @@ -482,8 +482,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Hakemistoa \"%s\" ei ole olemassa. Luodaanko se? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Hakemistoa \"%s\" ei ole olemassa. Luodaanko se? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/fr.po b/po/fr.po index a65148d..7f6f528 100644 --- a/po/fr.po +++ b/po/fr.po @@ -493,8 +493,8 @@ msgstr "" "La configuration chargée n'est pas compatible avec l'option --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Le répertoire \"%s\" n'existe pas. Doit-il être créé ? (y/n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Le répertoire \"%s\" n'existe pas. Doit-il être créé ? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/fr_FR.po b/po/fr_FR.po index 9310b1f..9053cc5 100644 --- a/po/fr_FR.po +++ b/po/fr_FR.po @@ -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" diff --git a/po/gl.po b/po/gl.po index 27e9e0a..296c9cc 100644 --- a/po/gl.po +++ b/po/gl.po @@ -484,8 +484,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "A configuración cargada non é compatíbel con --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "O directorio \"%s\" non existe. Debería crealo? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "O directorio \"%s\" non existe. Debería crealo? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/he.po b/po/he.po index cae4d3e..24a384c 100644 --- a/po/he.po +++ b/po/he.po @@ -477,8 +477,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "התצורה שנטענה ××™× ×” תו×מת ל --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "התקייה \"%s\" ××™× ×” קיימת. ×”×× ×œ×™×¦×•×¨ ×ותה? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "התקייה \"%s\" ××™× ×” קיימת. ×”×× ×œ×™×¦×•×¨ ×ותה? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/hr.po b/po/hr.po index 394b710..efa2298 100644 --- a/po/hr.po +++ b/po/hr.po @@ -415,7 +415,7 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " msgstr "" msgid "" diff --git a/po/hu.po b/po/hu.po index 2e61e6a..39b5c7f 100644 --- a/po/hu.po +++ b/po/hu.po @@ -485,8 +485,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "A \"%s\" könyvtár nem létezik. Létrehozzam? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "A \"%s\" könyvtár nem létezik. Létrehozzam? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/id.po b/po/id.po index 8f33c59..16042c2 100644 --- a/po/id.po +++ b/po/id.po @@ -432,9 +432,9 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " msgstr "" -"Tidak ada direktori \"%s\", perlukah membuat direktori tersebut? (ya, tidak) " +"Tidak ada direktori \"%s\", perlukah membuat direktori tersebut? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/it.po b/po/it.po index 1449456..0a479c8 100644 --- a/po/it.po +++ b/po/it.po @@ -521,8 +521,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "La configurazione caricata non è compatibile con --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "La directory \"%s\" non esiste. Deve essere creata? (y/n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "La directory \"%s\" non esiste. Deve essere creata? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/ja.po b/po/ja.po index 45fd464..eccefb4 100644 --- a/po/ja.po +++ b/po/ja.po @@ -452,8 +452,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "ディレクトリ \"%s\" ãŒå­˜åœ¨ã—ã¾ã›ã‚“。作æˆã—ã¾ã™ã‹? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "ディレクトリ \"%s\" ãŒå­˜åœ¨ã—ã¾ã›ã‚“。作æˆã—ã¾ã™ã‹? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/ko.po b/po/ko.po index 0d1a2dc..7088012 100644 --- a/po/ko.po +++ b/po/ko.po @@ -420,7 +420,7 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " msgstr "" msgid "" diff --git a/po/lv.po b/po/lv.po index cd07a54..1d7e811 100644 --- a/po/lv.po +++ b/po/lv.po @@ -475,8 +475,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Mape \"%s\" neeksistÄ“. Vai radÄ«t to? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Mape \"%s\" neeksistÄ“. Vai radÄ«t to? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/nb.po b/po/nb.po index ab1e19c..18e4f25 100644 --- a/po/nb.po +++ b/po/nb.po @@ -447,8 +447,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "Innstillingene som er lastet er ikke kompatible med --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Katalogen \"%s\" eksisterer ikke. Skal den opprettes? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Katalogen \"%s\" eksisterer ikke. Skal den opprettes? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/nds.po b/po/nds.po index 3d885b3..b59645a 100644 --- a/po/nds.po +++ b/po/nds.po @@ -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" diff --git a/po/nl.po b/po/nl.po index dbce047..b530e37 100644 --- a/po/nl.po +++ b/po/nl.po @@ -486,8 +486,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "De geladen configuratie is niet compatibel met --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "De map \"%s\" bestaat niet. Moet deze aangemaakt worden? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "De map \"%s\" bestaat niet. Moet deze aangemaakt worden? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/nn.po b/po/nn.po index 790870f..17bf65c 100644 --- a/po/nn.po +++ b/po/nn.po @@ -426,8 +426,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 "Katalogen \"%s\" eksisterer ikkje. Skal den opprettas? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Katalogen \"%s\" eksisterer ikkje. Skal den opprettas? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/oc.po b/po/oc.po index 9b94c0f..9bea5dd 100644 --- a/po/oc.po +++ b/po/oc.po @@ -490,8 +490,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "La configuracion cargada es pas compatibla amb l'opcion --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Lo repertòri \"%s\" existís pas. Deu èsser creat ? (ò/n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Lo repertòri \"%s\" existís pas. Deu èsser creat ? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/pl.po b/po/pl.po index 5264ef3..e27dab8 100644 --- a/po/pl.po +++ b/po/pl.po @@ -455,8 +455,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "ZaÅ‚adowana konfiguracja jest niekompatybilna z --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Katalog \"%s\" nie istnieje. Utworzyć? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Katalog \"%s\" nie istnieje. Utworzyć? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/pt.po b/po/pt.po index 4ca33a7..1570b90 100644 --- a/po/pt.po +++ b/po/pt.po @@ -511,8 +511,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "A configuração carregada não é compatível com --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "A directoria \"%s\" não existe. Criar? (s,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "A directoria \"%s\" não existe. Criar? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/pt_BR.po b/po/pt_BR.po index e177846..daf4a88 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -497,8 +497,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "A configuração carregada não é compatível com --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "O diretório \"%s\" não existe. Ele deve ser criado? (y, n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "O diretório \"%s\" não existe. Ele deve ser criado? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/pt_PT.po b/po/pt_PT.po index 8a55c7a..da45315 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -456,8 +456,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 directoria \"%s\" não existe. Deverá ser criada? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "A directoria \"%s\" não existe. Deverá ser criada? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/ro.po b/po/ro.po index dd323e0..55e672a 100644 --- a/po/ro.po +++ b/po/ro.po @@ -473,8 +473,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "ConfiguraÅ£ia încărcată nu este compatibilă cu --reverse\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Directorul \"%s\" nu există. Ar trebui creat ? (y/n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Directorul \"%s\" nu există. Ar trebui creat ? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/ru.po b/po/ru.po index 114e83b..33ad129 100644 --- a/po/ru.po +++ b/po/ru.po @@ -503,8 +503,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" diff --git a/po/sk.po b/po/sk.po index 78d555f..99ab47b 100644 --- a/po/sk.po +++ b/po/sk.po @@ -427,8 +427,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 "PrieÄinok \"%s\" neexistuje. Má byÅ¥ vytvorený ? (y,n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "PrieÄinok \"%s\" neexistuje. Má byÅ¥ vytvorený ? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/sr.po b/po/sr.po index abc01c3..882accc 100644 --- a/po/sr.po +++ b/po/sr.po @@ -423,8 +423,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Директоријум „%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" diff --git a/po/sv.po b/po/sv.po index fb6b372..8ed482e 100644 --- a/po/sv.po +++ b/po/sv.po @@ -452,8 +452,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "Katalogen \"%s\" finns ej. Ska den skapas? (j/n) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "Katalogen \"%s\" finns ej. Ska den skapas? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/ta.po b/po/ta.po index 01de8c2..b6108c6 100644 --- a/po/ta.po +++ b/po/ta.po @@ -413,7 +413,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 "" diff --git a/po/tr.po b/po/tr.po index 3958967..042b5f5 100644 --- a/po/tr.po +++ b/po/tr.po @@ -477,8 +477,8 @@ msgid "The configuration loaded is not compatible with --reverse\n" msgstr "Yüklenen ayarlar --reverse ile uyumlu deÄŸil\n" #, c-format -msgid "The directory \"%s\" does not exist. Should it be created? (y,n) " -msgstr "\"%s\" dizini mevcut deÄŸil. Yaratılmasını ister misiniz? (e,h) " +msgid "The directory \"%s\" does not exist. Should it be created? (y,N) " +msgstr "\"%s\" dizini mevcut deÄŸil. Yaratılmasını ister misiniz? (y,N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/uk.po b/po/uk.po index 18b14c7..b729b5d 100644 --- a/po/uk.po +++ b/po/uk.po @@ -458,8 +458,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" diff --git a/po/vi.po b/po/vi.po index 1576038..5fb6210 100644 --- a/po/vi.po +++ b/po/vi.po @@ -441,10 +441,10 @@ 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 "" -"ChÆ°a có thÆ° mục \"%s\" trong hệ thống. Bạn có muốn tạo thÆ° mục đó không? (c," -"k) " +"ChÆ°a có thÆ° mục \"%s\" trong hệ thống. Bạn có muốn tạo thÆ° mục đó không? (y," +"N) " msgid "" "The external initialization-vector chaining option has been\n" diff --git a/po/zh_CN.po b/po/zh_CN.po index 3491670..e85920f 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -464,8 +464,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" diff --git a/po/zh_HK.po b/po/zh_HK.po index 332008d..b23844e 100644 --- a/po/zh_HK.po +++ b/po/zh_HK.po @@ -437,8 +437,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" diff --git a/po/zh_TW.po b/po/zh_TW.po index 87f64c2..fcb0ca1 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -413,7 +413,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 "" diff --git a/test.sh b/test.sh index 4b57724..66b4b14 100755 --- a/test.sh +++ b/test.sh @@ -1,10 +1,10 @@ -#!/bin/bash +#!/bin/bash -eux -set -eux +# Make sure we are in the directory this script is in. +cd "$(dirname "$0")" -if [ ! -d build ] -then - ./build.sh -fi +# This is very noisy so run it silently at first. Run it again with +# output if the first run fails. +./build/checkops &> /dev/null || ./build/checkops -perl -MTest::Harness -e '$$Test::Harness::verbose=1; runtests @ARGV;' tests/*.t.pl +perl -MTest::Harness -e '$$Test::Harness::debug=1; runtests @ARGV;' tests/*.t.pl diff --git a/tests/normal.t.pl b/tests/normal.t.pl index 841c60a..5011c09 100755 --- a/tests/normal.t.pl +++ b/tests/normal.t.pl @@ -2,7 +2,7 @@ # Test EncFS normal and paranoid mode -use Test::More tests => 104; +use Test::More tests => 122; use File::Path; use File::Copy; use File::Temp; @@ -12,6 +12,35 @@ require("tests/common.pl"); my $tempDir = $ENV{'TMPDIR'} || "/tmp"; +if($^O eq "linux" and $tempDir eq "/tmp") { + # On Linux, /tmp is often a tmpfs mount that does not support + # extended attributes. Use /var/tmp instead. + $tempDir = "/var/tmp"; +} + +# Find attr binary +# Linux +my $setattr = "attr -s encfs -V hello"; +my $getattr = "attr -g encfs"; +if(system("which xattr > /dev/null 2>&1") == 0) +{ + # Mac OS X + $setattr = "xattr -sw encfs hello"; + $getattr = "xattr -sp encfs"; +} +if(system("which lsextattr > /dev/null 2>&1") == 0) +{ + # FreeBSD + $setattr = "setextattr -h user encfs hello"; + $getattr = "getextattr -h user encfs"; +} +# Do we support xattr ? +my $have_xattr = 1; +if(system("./build/encfs --verbose --version 2>&1 | grep -q HAVE_XATTR") != 0) +{ + $have_xattr = 0; +} + # test filesystem in standard config mode &runTests('standard'); @@ -22,6 +51,7 @@ my $tempDir = $ENV{'TMPDIR'} || "/tmp"; sub runTests { my $mode = shift; + print STDERR "\nrunTests: mode=$mode\n"; &newWorkingDir; @@ -47,7 +77,9 @@ sub runTests &internalModification; &grow; &umask0777; + &create_unmount_remount; + &configFromPipe; &cleanup; } @@ -189,13 +221,13 @@ sub truncate sub fileCreation { # create a file - qx(df -ah > "$crypt/df.txt" 2> /dev/null); - ok( -f "$crypt/df.txt", "file created" ); + qx(date > "$crypt/df.txt"); + ok( -f "$crypt/df.txt", "file created" ) || BAIL_OUT("file create failed"); # ensure there is an encrypted version. my $c = encName("df.txt"); cmp_ok( length($c), '>', 8, "encrypted name ok" ); - ok( -f "$raw/$c", "encrypted file created" ); + ok( -f "$raw/$c", "encrypted file $raw/$c created" ); # check contents my $count = qx(grep -c crypt-$$ "$crypt/df.txt"); @@ -267,7 +299,7 @@ sub encName return $enc; } -# Test symlinks & hardlinks +# Test symlinks & hardlinks, and extended attributes sub links { my $hardlinkTests = shift; @@ -292,6 +324,15 @@ sub links ok( link("$crypt/data", "$crypt/data.2"), "hard link"); checkContents("$crypt/data.2", $contents, "hardlink read"); }; + + # extended attributes + my $return_code = ($have_xattr) ? system("$setattr $crypt/data") : 0; + is($return_code, 0, "extended attributes can be set (return code was $return_code)"); + $return_code = ($have_xattr) ? system("$getattr $crypt/data") : 0; + is($return_code, 0, "extended attributes can be get (return code was $return_code)"); + # this is suppused to fail, so get rid of the error message + $return_code = ($have_xattr) ? system("$getattr $crypt/data-rel 2> /dev/null") : 1; + isnt($return_code, 0, "extended attributes operations do not follow symlinks (return code was $return_code)"); } # Test mount @@ -305,11 +346,19 @@ sub mount mkdir($crypt) || BAIL_OUT("Could not create $crypt: $!"); delete $ENV{"ENCFS6_CONFIG"}; + remount($args); + ok( $? == 0, "encfs command returns 0") || BAIL_OUT(""); + ok( -f "$raw/.encfs6.xml", "created control file") || BAIL_OUT(""); +} + +# Helper function +# Mount without any prior checks +sub remount +{ + my $args = shift; my $cmdline = "./build/encfs --extpass=\"echo test\" $args $raw $crypt 2>&1"; # This makes sure we get to see stderr ^ - my $status = system($cmdline); - ok( $status == 0, "encfs command returns 0") || BAIL_OUT(""); - ok( -f "$raw/.encfs6.xml", "created control file") || BAIL_OUT(""); + system($cmdline); } # Helper function @@ -334,3 +383,50 @@ sub umask0777 close($fh); umask($old); } + +# Test that we can read the configuration from a named pipe +# Regression test for https://github.com/vgough/encfs/issues/253 +sub configFromPipe +{ + portable_unmount($crypt); + rename("$raw/.encfs6.xml", "$raw/.encfs6.xml.orig"); + system("mkfifo $raw/.encfs6.xml"); + my $child = fork(); + unless ($child) { + &remount("--standard"); + exit; + } + system("cat $raw/.encfs6.xml.orig > $raw/.encfs6.xml"); + waitpid($child, 0); + ok( 0 == $?, "encfs mount with named pipe based config failed"); +} + +sub create_unmount_remount +{ + my $crypt = "$workingDir/create_remount.crypt"; + my $mnt = "$workingDir/create_remount.mnt"; + mkdir($crypt) || BAIL_OUT($!); + mkdir($mnt) || BAIL_OUT($!); + + system("./build/encfs --standard --extpass=\"echo test\" $crypt $mnt 2>&1"); + ok( $? == 0, "encfs command returns 0") || return; + ok( -f "$crypt/.encfs6.xml", "created control file") || return; + + # Write some text + my $contents = "hello world\n"; + ok( open(OUT, "> $mnt/test_file_1"), "write content"); + print OUT $contents; + close OUT; + + # Unmount + portable_unmount($mnt); + + # Mount again + system("./build/encfs --extpass=\"echo test\" $crypt $mnt 2>&1"); + ok( $? == 0, "encfs command returns 0") || return; + + # Check if content is still there + checkContents("$mnt/test_file_1", $contents); + + portable_unmount($mnt); +} diff --git a/tests/reverse.t.pl b/tests/reverse.t.pl index 9e359bc..d8277a9 100755 --- a/tests/reverse.t.pl +++ b/tests/reverse.t.pl @@ -3,7 +3,7 @@ # Test EncFS --reverse mode use warnings; -use Test::More tests => 26; +use Test::More tests => 25; use File::Path; use File::Temp; use IO::Handle; @@ -13,6 +13,32 @@ require("tests/common.pl"); my $tempDir = $ENV{'TMPDIR'} || "/tmp"; +if($^O eq "linux" and $tempDir eq "/tmp") { + # On Linux, /tmp is often a tmpfs mount that does not support + # extended attributes. Use /var/tmp instead. + $tempDir = "/var/tmp"; +} + +# Find attr binary +# Linux +my @binattr = ("attr", "-l"); +if(system("which xattr > /dev/null 2>&1") == 0) +{ + # Mac OS X + @binattr = ("xattr", "-s"); +} +if(system("which lsextattr > /dev/null 2>&1") == 0) +{ + # FreeBSD + @binattr = ("lsextattr", "-h", "user"); +} +# Do we support xattr ? +my $have_xattr = 1; +if(system("./build/encfs --verbose --version 2>&1 | grep -q HAVE_XATTR") != 0) +{ + $have_xattr = 0; +} + # Helper function # Create a new empty working directory sub newWorkingDir @@ -84,6 +110,8 @@ sub symlink_test $dec = readlink("$decrypted/symlink"); ok( $dec eq $target, "symlink to '$target'") or print("# (original) $target' != '$dec' (decrypted)\n"); + my $return_code = ($have_xattr) ? system(@binattr, "$decrypted/symlink") : 0; + is($return_code, 0, "symlink to '$target' extended attributes can be read (return code was $return_code)"); unlink("$plain/symlink"); } @@ -129,6 +157,11 @@ sub grow { last unless $ok; } ok($ok, "ciphertext and decrypted size of file grown to $i bytes"); + close($pfh); + close($vfh); + close($cfh); + close($dfh); + unlink("$plain/grow"); } sub largeRead { @@ -179,7 +212,7 @@ symlink_test("foo"); # relative symlink_test("/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/15/17/18"); # long symlink_test("!§\$%&/()\\<>#+="); # special characters symlink_test("$plain/foo"); -writesDenied(); +# writesDenied(); # disabled as writes are allowed when (uniqueIV == false), we would need a specific reverse conf with (uniqueIV == true). # Umount and delete files cleanup(); diff --git a/tests/stress_tests/fsstress-encfs.sh b/tests/stress_tests/fsstress-encfs.sh new file mode 100755 index 0000000..2ec52d3 --- /dev/null +++ b/tests/stress_tests/fsstress-encfs.sh @@ -0,0 +1,74 @@ +#!/bin/bash -eu +# +# Mount an EncFS filesystem in /tmp and run fsstress against it +# in an infinite loop, only exiting on errors. +# +# You need to have https://github.com/rfjakob/fuse-xfstests or +# https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git +# (which fsstress) downloaded and compiled at $HOME/fuse-xfststs . + +cd "$(dirname "$0")" +MYNAME=$(basename $0) + +# fsstress binary +FSSTRESS=$HOME/fuse-xfstests/ltp/fsstress +if [ ! -x $FSSTRESS ] +then + echo "$MYNAME: fsstress binary not found at $FSSTRESS" + echo "Please clone and compile https://github.com/rfjakob/fuse-xfstests" + exit 1 +fi + +# Backing directory +DIR=$(mktemp -d /tmp/fsstress-encfs.XXX) +# Mountpoint +MNT="$DIR.mnt" +mkdir $MNT + +# Mount +../../build/encfs -f --extpass "echo test" --standard $DIR $MNT & +disown + +sleep 0.5 +echo -n "Waiting for mount: " +while ! grep "$MNT fuse" /proc/self/mounts > /dev/null +do + sleep 1 + echo -n x +done +echo " ok" + +# Cleanup trap +trap "kill %1 ; cd / ; fusermount -u -z $MNT ; rm -rf $DIR $MNT" EXIT + +echo "Starting fsstress loop" +N=1 +while true +do + # Note: EncFS does not seem to support the FS_IOC_GETFLAGS ioctl that + # fsstress is using. To get rid of the error messages we set "-f getattr=0" + # in all fsstress calls. + echo $N + mkdir $MNT/fsstress.1 + echo -n " fsstress.1 " + $FSSTRESS -r -m 8 -n 1000 -d $MNT/fsstress.1 -f getattr=0 & + wait + + mkdir $MNT/fsstress.2 + echo -n " fsstress.2 " + $FSSTRESS -p 20 -r -m 8 -n 1000 -d $MNT/fsstress.2 -f getattr=0 & + wait + + mkdir $MNT/fsstress.3 + echo -n " fsstress.3 " + $FSSTRESS -p 4 -z -f rmdir=10 -f link=10 -f creat=10 -f mkdir=10 \ + -f rename=30 -f stat=30 -f unlink=30 -f truncate=20 -m 8 \ + -n 1000 -d $MNT/fsstress.3 -f getattr=0 & + wait + + echo " rm" + rm -R $MNT/* + + let N=$N+1 +done + diff --git a/vendor/README.md b/vendor/README.md new file mode 100644 index 0000000..72a8776 --- /dev/null +++ b/vendor/README.md @@ -0,0 +1,24 @@ +# Vendored Packages + +Some external dependencies are vendored here. Use +[git-vendor](https://github.com/brettlangdon/git-vendor) to view, +add, or update vendored packages. + +For example: + +```sh +$ git-vendor list +easylogging@master: + name: easylogging + dir: vendor/github.com/muflihun/easyloggingpp + repo: https://github.com/muflihun/easyloggingpp + ref: master + commit: e2b86551a5ba1d63b21b57a2bae1ddb0b0e5135e + +tinyxml2@master: + name: tinyxml2 + dir: vendor/github.com/leethomason/tinyxml2 + repo: https://github.com/leethomason/tinyxml2.git + ref: master + commit: 1979f3c87e68f489c7f6d88532aae4d76d9d3a78 +``` \ No newline at end of file diff --git a/internal/tinyxml2-3.0.0/.gitignore b/vendor/github.com/leethomason/tinyxml2/.gitignore similarity index 70% rename from internal/tinyxml2-3.0.0/.gitignore rename to vendor/github.com/leethomason/tinyxml2/.gitignore index a765577..ca32242 100644 --- a/internal/tinyxml2-3.0.0/.gitignore +++ b/vendor/github.com/leethomason/tinyxml2/.gitignore @@ -5,9 +5,14 @@ ipch/ resources/out/ tinyxml2/tinyxml2-cbp/bin/ tinyxml2/tinyxml2-cbp/obj/ +tinyxml2/bin/ +tinyxml2/temp/ *.sdf *.suo *.opensdf *.user *.depend -*.layout \ No newline at end of file +*.layout +*.o +*.vc.db +*.vc.opendb \ No newline at end of file diff --git a/vendor/github.com/leethomason/tinyxml2/.travis.yml b/vendor/github.com/leethomason/tinyxml2/.travis.yml new file mode 100644 index 0000000..0634ccb --- /dev/null +++ b/vendor/github.com/leethomason/tinyxml2/.travis.yml @@ -0,0 +1,15 @@ +language: cpp + +os: + - linux + - osx + +compiler: + - g++ + - clang + +before_script: cmake . + +script: + - make -j3 + - make test diff --git a/vendor/github.com/leethomason/tinyxml2/CMakeLists.txt b/vendor/github.com/leethomason/tinyxml2/CMakeLists.txt new file mode 100644 index 0000000..cec4470 --- /dev/null +++ b/vendor/github.com/leethomason/tinyxml2/CMakeLists.txt @@ -0,0 +1,176 @@ +IF(BIICODE) + ADD_BIICODE_TARGETS() + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/resources) + file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/resources DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + ENDIF() + RETURN() +ENDIF(BIICODE) +cmake_minimum_required(VERSION 2.6 FATAL_ERROR) +cmake_policy(VERSION 2.6) +if(POLICY CMP0063) + cmake_policy(SET CMP0063 OLD) +endif() + +project(tinyxml2) +include(GNUInstallDirs) +include(CTest) +#enable_testing() + +#CMAKE_BUILD_TOOL + +################################ +# set lib version here + +set(GENERIC_LIB_VERSION "5.0.1") +set(GENERIC_LIB_SOVERSION "5") + +################################ +# Add definitions + +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") + +################################ +# Add targets +# By Default shared libray is being built +# To build static libs also - Do cmake . -DBUILD_STATIC_LIBS:BOOL=ON +# User can choose not to build shared library by using cmake -DBUILD_SHARED_LIBS:BOOL=OFF +# To build only static libs use cmake . -DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_STATIC_LIBS:BOOL=ON +# To build the tests, use cmake . -DBUILD_TESTS:BOOL=ON +# To disable the building of the tests, use cmake . -DBUILD_TESTS:BOOL=OFF + +option(BUILD_SHARED_LIBS "build as shared library" ON) +option(BUILD_STATIC_LIBS "build as static library" OFF) +option(BUILD_TESTS "build xmltest (deprecated: Use BUILD_TESTING)" ON) + +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) + +# to distinguish between debug and release lib +set(CMAKE_DEBUG_POSTFIX "d") + +if(BUILD_SHARED_LIBS) +add_library(tinyxml2 SHARED tinyxml2.cpp tinyxml2.h) + +set_target_properties(tinyxml2 PROPERTIES + COMPILE_DEFINITIONS "TINYXML2_EXPORT" + VERSION "${GENERIC_LIB_VERSION}" + SOVERSION "${GENERIC_LIB_SOVERSION}") + + +if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") + target_include_directories(tinyxml2 PUBLIC + $ + $) + + if(MSVC) + target_compile_definitions(tinyxml2 PUBLIC -D_CRT_SECURE_NO_WARNINGS) + endif(MSVC) +else() + include_directories(${PROJECT_SOURCE_DIR}) + + if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + endif(MSVC) +endif() + +# export targets for find_package config mode +export(TARGETS tinyxml2 + FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake) + +install(TARGETS tinyxml2 + EXPORT ${CMAKE_PROJECT_NAME}Targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() + +if(BUILD_STATIC_LIBS) +add_library(tinyxml2_static STATIC tinyxml2.cpp tinyxml2.h) +set_target_properties(tinyxml2_static PROPERTIES + COMPILE_DEFINITONS "TINYXML2_EXPORT" + VERSION "${GENERIC_LIB_VERSION}" + SOVERSION "${GENERIC_LIB_SOVERSION}") +set_target_properties( tinyxml2_static PROPERTIES OUTPUT_NAME tinyxml2 ) + +target_compile_definitions(tinyxml2_static PUBLIC -D_CRT_SECURE_NO_WARNINGS) + +if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") + target_include_directories(tinyxml2_static PUBLIC + $ + $) + + if(MSVC) + target_compile_definitions(tinyxml2_static PUBLIC -D_CRT_SECURE_NO_WARNINGS) + endif(MSVC) +else() + include_directories(${PROJECT_SOURCE_DIR}) + + if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + endif(MSVC) +endif() + +# export targets for find_package config mode +export(TARGETS tinyxml2_static + FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake) + +install(TARGETS tinyxml2_static + EXPORT ${CMAKE_PROJECT_NAME}Targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() + +if(BUILD_TESTING AND BUILD_TESTS) + add_executable(xmltest xmltest.cpp) + if(BUILD_SHARED_LIBS) + add_dependencies(xmltest tinyxml2) + target_link_libraries(xmltest tinyxml2) + else(BUILD_STATIC_LIBS) + add_dependencies(xmltest tinyxml2_static) + target_link_libraries(xmltest tinyxml2_static) + endif() + + # Copy test resources and create test output directory + add_custom_command(TARGET xmltest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources $/resources + COMMAND ${CMAKE_COMMAND} -E make_directory $/resources/out + COMMENT "Configuring xmltest resources directory: ${CMAKE_BINARY_DIR}/resources" + ) + + add_test(NAME xmltest COMMAND xmltest) +endif() + +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) + +# uninstall target +if(NOT TARGET uninstall) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) +endif() + +file(WRITE + ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake + "include(\${CMAKE_CURRENT_LIST_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\n") + +install(FILES + ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake + DESTINATION lib/cmake/${CMAKE_PROJECT_NAME}) + +install(EXPORT ${CMAKE_PROJECT_NAME}Targets + DESTINATION lib/cmake/${CMAKE_PROJECT_NAME}) diff --git a/vendor/github.com/leethomason/tinyxml2/Makefile b/vendor/github.com/leethomason/tinyxml2/Makefile new file mode 100644 index 0000000..eba6fef --- /dev/null +++ b/vendor/github.com/leethomason/tinyxml2/Makefile @@ -0,0 +1,19 @@ +all: xmltest staticlib + +rebuild: clean all + +xmltest: xmltest.cpp libtinyxml2.a + +clean: + $(RM) *.o xmltest libtinyxml2.a + +test: clean xmltest + ./xmltest + +staticlib: libtinyxml2.a + +libtinyxml2.a: tinyxml2.o + $(AR) $(ARFLAGS)s $@ $^ + +tinyxml2.o: tinyxml2.cpp tinyxml2.h + diff --git a/vendor/github.com/leethomason/tinyxml2/TinyXML2_small.png b/vendor/github.com/leethomason/tinyxml2/TinyXML2_small.png new file mode 100644 index 0000000..6e84b35 Binary files /dev/null and b/vendor/github.com/leethomason/tinyxml2/TinyXML2_small.png differ diff --git a/vendor/github.com/leethomason/tinyxml2/appveyor.yml b/vendor/github.com/leethomason/tinyxml2/appveyor.yml new file mode 100644 index 0000000..0c60b67 --- /dev/null +++ b/vendor/github.com/leethomason/tinyxml2/appveyor.yml @@ -0,0 +1,7 @@ +before_build: + - cmake . + +build_script: + - msbuild tinyxml2.sln /m /p:Configuration=Release /t:ALL_BUILD + - cd Release + - xmltest.exe diff --git a/vendor/github.com/leethomason/tinyxml2/biicode.conf b/vendor/github.com/leethomason/tinyxml2/biicode.conf new file mode 100644 index 0000000..5dca6b1 --- /dev/null +++ b/vendor/github.com/leethomason/tinyxml2/biicode.conf @@ -0,0 +1,7 @@ +# Biicode configuration file + +[paths] + / + +[dependencies] + xmltest.cpp + resources/*.xml \ No newline at end of file diff --git a/vendor/github.com/leethomason/tinyxml2/cmake_uninstall.cmake.in b/vendor/github.com/leethomason/tinyxml2/cmake_uninstall.cmake.in new file mode 100644 index 0000000..2c34c81 --- /dev/null +++ b/vendor/github.com/leethomason/tinyxml2/cmake_uninstall.cmake.in @@ -0,0 +1,21 @@ +if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif(NOT "${rm_retval}" STREQUAL 0) + else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) \ No newline at end of file diff --git a/internal/tinyxml2-3.0.0/contrib/html5-printer.cpp b/vendor/github.com/leethomason/tinyxml2/contrib/html5-printer.cpp similarity index 98% rename from internal/tinyxml2-3.0.0/contrib/html5-printer.cpp rename to vendor/github.com/leethomason/tinyxml2/contrib/html5-printer.cpp index 3205ccd..7728b69 100644 --- a/internal/tinyxml2-3.0.0/contrib/html5-printer.cpp +++ b/vendor/github.com/leethomason/tinyxml2/contrib/html5-printer.cpp @@ -65,7 +65,7 @@ public: protected: virtual void CloseElement () { if (_elementJustOpened && !isVoidElement (_stack.PeekTop())) { - SealElement(); + SealElementIfJustOpened(); } XMLPrinter::CloseElement(); } diff --git a/vendor/github.com/leethomason/tinyxml2/dox b/vendor/github.com/leethomason/tinyxml2/dox new file mode 100644 index 0000000..601feed --- /dev/null +++ b/vendor/github.com/leethomason/tinyxml2/dox @@ -0,0 +1,2324 @@ +# Doxyfile 1.8.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "TinyXML-2" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 5.0.1 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = NO + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = tinyxml2.h \ + xmltest.cpp \ + readme.md + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = . + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = readme.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more acurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# compiled with the --with-libclang option. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = docs + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /