├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake ├── FindLibgcrypt.cmake ├── FindPOCO.cmake ├── Finddokan.cmake ├── Findfuse.cmake └── config.h.in ├── resources ├── ToIco.sh └── umbrella.svg ├── src ├── FS │ ├── CFilesystem.cpp │ ├── CFilesystem.h │ ├── CPath.cpp │ ├── CPath.h │ ├── ContainerFS │ │ ├── ContainerFS.cpp │ │ └── ContainerFS.h │ └── SimpleFS │ │ ├── CFragment.cpp │ │ ├── CFragment.h │ │ ├── CPrintCheckRepair.cpp │ │ ├── CPrintCheckRepair.h │ │ ├── CSimpleFS.cpp │ │ ├── CSimpleFS.h │ │ ├── CSimpleFSDirectory.cpp │ │ ├── CSimpleFSDirectory.h │ │ ├── CSimpleFSInode.cpp │ │ └── CSimpleFSInode.h ├── IO │ ├── CBlockIO.cpp │ ├── CBlockIO.h │ ├── CCacheIO.cpp │ ├── CCacheIO.h │ ├── CEncrypt.cpp │ ├── CEncrypt.h │ ├── CNetBlockIO.cpp │ ├── CNetBlockIO.h │ ├── CNetReadWriteBuffer.cpp │ └── CNetReadWriteBuffer.h ├── client │ ├── CStatusView.cpp │ ├── CStatusView.h │ ├── ParallelTest.cpp │ ├── ParallelTest.h │ └── main.cpp ├── fuse │ ├── dokanoper.cpp │ ├── dokanoper.h │ ├── fuseoper.cpp │ └── fuseoper.h ├── interface │ ├── CFSHandler.cpp │ └── CFSHandler.h ├── server │ └── coverfsserver.cpp ├── utils │ ├── Logger.cpp │ ├── Logger.h │ └── StringUtils.h └── webapp │ ├── CConfigFile.cpp │ ├── CConfigFile.h │ ├── CoverFS.config │ ├── webapp.cpp │ └── webapp.h ├── ssl ├── dh1024.pem ├── gen.sh ├── openssl.cnf ├── server.crt ├── server.csr └── server.key ├── templates ├── configuration.html ├── css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap-theme.min.css.map │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ ├── bootstrap.min.css.map │ └── style.css ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── footer.html ├── header.html ├── js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── jquery-3.2.1.min.js │ └── npm.js ├── log.html └── status.html └── tests └── checkfragment.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | #CMake 31 | CMakeCache.txt 32 | CMakeFiles 33 | CMakeScripts 34 | Makefile 35 | cmake_install.cmake 36 | install_manifest.txt 37 | CTestTestfile.cmake 38 | build -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | dist: trusty 4 | 5 | language: cpp 6 | 7 | compiler: gcc 8 | 9 | os: linux 10 | 11 | addons: 12 | apt: 13 | packages: 14 | - libboost-all-dev 15 | - libpoco-dev 16 | - libgcrypt20 17 | - libgcrypt20-dev 18 | - libfuse-dev 19 | - fuse 20 | - libfuse2 21 | - g++-5 22 | sources: 23 | - ubuntu-toolchain-r-test 24 | 25 | before_install: 26 | - sudo apt-get -q update 27 | - sudo apt-get install -y libgcrypt20 libgcrypt20-dev 28 | 29 | install: 30 | - export CXX="g++-5" CC="gcc-5" 31 | 32 | script: 33 | - mkdir build && cd build && cmake .. && make 34 | 35 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_LEGACY_CYGWIN_WIN32 0) 2 | 3 | #MINGW64 compile with CXX=g++ CC=gcc cmake .. 4 | 5 | project (CoverFS) 6 | set(PROJECT_VERSION "0.91") 7 | 8 | cmake_minimum_required(VERSION 3.0.0) 9 | cmake_policy(SET CMP0054 NEW) 10 | 11 | 12 | enable_language(CXX) 13 | set(CMAKE_CXX_STANDARD 14) 14 | set(CMAKE_CXX_STANDARD_REQUIRED on) 15 | 16 | set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${PROJECT_VERSION}) 17 | 18 | 19 | MESSAGE( STATUS "CMAKE_SYSTEM_NAME: " ${CMAKE_SYSTEM_NAME} ) 20 | 21 | if (WIN32) 22 | MESSAGE( STATUS "SYSTEM: WIN32") 23 | endif () 24 | if (UNIX) 25 | MESSAGE( STATUS "SYSTEM: UNIX") 26 | endif () 27 | if (CYGWIN) 28 | MESSAGE( STATUS "SYSTEM: CYGWIN") 29 | endif () 30 | if (MINGW) 31 | MESSAGE( STATUS "SYSTEM: MINGW") 32 | endif () 33 | if (MSYS) 34 | MESSAGE( STATUS "SYSTEM: MSYS") 35 | endif () 36 | if (APPLE) 37 | MESSAGE( STATUS "SYSTEM: APPLE") 38 | endif () 39 | 40 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake ) 41 | 42 | add_definitions(-std=c++14 -Wall -O2 -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE) 43 | 44 | set(CPP_FILES 45 | src/utils/Logger.cpp 46 | src/IO/CBlockIO.cpp 47 | src/IO/CCacheIO.cpp 48 | src/IO/CEncrypt.cpp 49 | src/IO/CNetBlockIO.cpp 50 | src/IO/CNetReadWriteBuffer.cpp 51 | src/FS/CFilesystem.cpp 52 | src/FS/SimpleFS/CSimpleFS.cpp 53 | src/FS/SimpleFS/CSimpleFSDirectory.cpp 54 | src/FS/SimpleFS/CSimpleFSInode.cpp 55 | src/FS/SimpleFS/CFragment.cpp 56 | src/FS/SimpleFS/CPrintCheckRepair.cpp 57 | src/FS/ContainerFS/ContainerFS.cpp 58 | src/FS/ContainerFS/ContainerFS.h 59 | src/interface/CFSHandler.cpp 60 | src/client/ParallelTest.cpp 61 | src/client/CStatusView.cpp 62 | src/client/main.cpp 63 | src/FS/CPath.cpp 64 | src/FS/CPath.h 65 | ) 66 | 67 | set(THREADS_PREFER_PTHREAD_FLAG ON) 68 | find_package(Threads REQUIRED) 69 | find_package(Boost COMPONENTS system REQUIRED) 70 | find_package(OpenSSL REQUIRED) 71 | find_package(Libgcrypt REQUIRED) 72 | find_package(POCO) 73 | 74 | if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") 75 | MESSAGE( STATUS "Add FUSE Library" ) 76 | find_package(fuse REQUIRED) 77 | add_definitions(${FUSE_DEFINITIONS}) 78 | include_directories(${FUSE_INCLUDE_DIRS}) 79 | set(CPP_FILES ${CPP_FILES} src/fuse/fuseoper.cpp) 80 | set(FUSE_LIB ${FUSE_LIBRARIES}) 81 | endif () 82 | if ("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN") 83 | MESSAGE( STATUS "Add Dokan Library") 84 | find_package(dokan REQUIRED) 85 | set(CPP_FILES ${CPP_FILES} src/fuse/dokanoper.cpp) 86 | include_directories(${DOKAN_INCLUDE_DIR}) 87 | set(FUSE_LIB ${DOKAN_LIB_DIR}) 88 | endif () 89 | if ("${CMAKE_SYSTEM_NAME}" STREQUAL "MSYS" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "MINGW" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "MINGW64_NT-10.0") 90 | MESSAGE( STATUS "Add Dokan Library") 91 | find_package(dokan REQUIRED) 92 | set(CPP_FILES ${CPP_FILES} src/fuse/dokanoper.cpp) 93 | include_directories(${DOKAN_INCLUDE_DIR}) 94 | set(FUSE_LIB ${DOKAN_LIB_DIR}) 95 | set(PLATFORM_LIBS ws2_32 wsock32) 96 | endif () 97 | 98 | include_directories(${Boost_INCLUDE_DIRS} ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/src/utils) 99 | 100 | if (Poco_FOUND) 101 | set(HAVE_POCO TRUE) 102 | set(POCO_LIB PocoNet PocoUtil PocoFoundation PocoXML) 103 | set(CPP_FILES ${CPP_FILES} src/webapp/CConfigFile.cpp src/webapp/webapp.cpp) 104 | add_definitions(-DPOCO_WIN32_UTF8) 105 | endif () 106 | 107 | configure_file( 108 | ${PROJECT_SOURCE_DIR}/cmake/config.h.in 109 | ${PROJECT_BINARY_DIR}/config.h 110 | ) 111 | 112 | add_executable(coverfsserver src/server/coverfsserver.cpp src/utils/Logger.cpp) 113 | add_executable(coverfs ${CPP_FILES}) 114 | add_executable(checkfragment tests/checkfragment.cpp) 115 | 116 | target_link_libraries (coverfs ${Boost_SYSTEM_LIBRARY_RELEASE} pthread ssl crypto gcrypt ${FUSE_LIB} ${POCO_LIB} ${PLATFORM_LIBS}) 117 | target_link_libraries (coverfsserver ${Boost_SYSTEM_LIBRARY_RELEASE} pthread ssl crypto ${PLATFORM_LIBS}) 118 | target_link_libraries (checkfragment ${Boost_SYSTEM_LIBRARY_RELEASE} pthread ${PLATFORM_LIBS}) 119 | 120 | add_custom_command( 121 | TARGET coverfs POST_BUILD 122 | COMMAND "${CMAKE_COMMAND}" -E create_symlink ${PROJECT_SOURCE_DIR}/ssl ${PROJECT_BINARY_DIR}/ssl 123 | COMMAND "${CMAKE_COMMAND}" -E create_symlink ${PROJECT_SOURCE_DIR}/templates ${PROJECT_BINARY_DIR}/templates 124 | COMMENT "Copying to build directory" 125 | ) 126 | 127 | add_custom_target(dist 128 | COMMAND git archive --prefix=${ARCHIVE_NAME}/ HEAD 129 | | bzip2 > ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.bz2 130 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) 131 | 132 | add_custom_target(release 133 | COMMAND 134 | rm -f ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.zip 135 | && 136 | zip -j ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.zip 137 | ${PROJECT_BINARY_DIR}/coverfs.exe 138 | ${PROJECT_BINARY_DIR}/coverfsserver.exe 139 | /mingw64/bin/libgcrypt-20.dll 140 | /mingw64/bin/libPocoFoundation.dll 141 | /mingw64/bin/libPocoNet.dll 142 | /mingw64/bin/libPocoXML.dll 143 | /mingw64/bin/libPocoJSON.dll 144 | /mingw64/bin/libPocoUtil.dll 145 | /mingw64/bin/libeay32.dll 146 | /mingw64/bin/ssleay32.dll 147 | /mingw64/bin/libgcc_s_seh-1.dll 148 | /mingw64/bin/libstdc++-6.dll 149 | /mingw64/bin/libwinpthread-1.dll 150 | /mingw64/bin/libpcre-1.dll 151 | /mingw64/bin/libgpg-error-0.dll 152 | /mingw64/bin/libexpat-1.dll 153 | /mingw64/bin/zlib1.dll 154 | && zip -r ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.zip 155 | ssl 156 | templates 157 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 158 | ) 159 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CoverFS 2 | ======= 3 | 4 | Zero-knowledge client-side encrypted network filesystem. 5 | 6 | This program offers an encrypted container, which can be accessed remotely. 7 | 8 | Features 9 | * The data is stored in a single file (container) database 10 | * Client side zero-knowledge encryption (CBC AES block encryption, PBKDF2 password hashing) 11 | * Secure SSL connection 12 | * Windows and Linux support 13 | * File access based on FUSE (Linux) or Dokan (Windows) (file system in user space) 14 | * Several backends for block filesystem 15 | - remote storage (needs a program which runs on the server) 16 | - local file 17 | - RAM 18 | * In-memory encrypted data caching 19 | * Asynchronous reading and writing for maximum performance 20 | * Full filesystem layout is loaded in the beginning to limit read and write access afterwards 21 | * Random access of files 22 | * Automatic growing container (but no shrinking yet) 23 | * No local storage of files 24 | 25 | Limits 26 | * Filesystem layout not final 27 | * Several Posix features like dates are missing 28 | * Only one user at a time 29 | * Limited check disk utility. Limited repair options. 30 | * No XTS block encryption yet 31 | * No change of password allowed after creation yet 32 | * Background job for automatic defragmentation missing 33 | 34 | Build CoverFS 35 | ============= 36 | 37 | Dependencies: 38 | * fuse (dokan on Windows) 39 | * boost 40 | * openssl 41 | * libgcrypt 42 | * pthread 43 | * make build system 44 | * cygwin build environment under Windows 45 | 46 | 47 | Create a build directory and run `cmake path/to/repository` to build the binaries or build directly in the repository by running `cmake .`. Afterwards run `make` to compile. 48 | 49 | 50 | Run CoverFS 51 | =========== 52 | 53 | On the server run `./coverfsserver [port]` where [port] is the port the server should listen to. 54 | On the client run `./coverfs --host [host] [mountpoint]` where [mountpoint] folder which will contain the content of the filesystem and [host] is the name of the host where coverfsserver is executed. 55 | Type `--help` for more options. The standard port is 62000. 56 | 57 | The first time you run `coverfs` you are asked for a password for the new filesystem. The filesystem is stored in the file `cfscontainer` on the server. 58 | 59 | Optional but highly recommened: 60 | 61 | To retrieve a unique set of keys for the SSL encryption run "gen.sh" in the "ssl" directory. Then copy the 62 | content of the folder into the SSL folder of the server and the client. Otherwise the connection is vulnerable against 63 | man-in-the middle attacks. 64 | 65 | 66 | Filesystem Design 67 | ================= 68 | 69 | The block size is 4096 bytes and the filesystem is encrypted by this block size. The first block is not encrypted but contains data 70 | like password hashes and keys for decrypting the volume. 71 | 72 | Overall container layout: 73 | ``` 74 | | Encryption block | Superblock | Basic layout table block | Further layout tables and blocks containing directory structure and data | 75 | |----------------------------------------------------------|--------------------------------------------------------------------------| 76 | | This layout is the same for each filesystem | This is specific to the content | 77 | ``` 78 | 79 | The tables contain a list of descriptors which define the content of certain fragments in the container. 80 | ``` 81 | | inode id | size | ofs in container | 82 | |----------|--------|------------------| 83 | | 4 byte | 4 byte | 8 byte | 84 | ``` 85 | 86 | So each descriptor can define the content up to a size of 4 GB. 87 | 88 | The "basic layout table" contains only the descriptors of one fixed id (=-2) which defines the position of the "further layout tables" 89 | 90 | * inode id = 0 is the id of the root directory structure 91 | * inode id = -1 defines a descriptor which is not used and can be overwritten 92 | * inode id = -2 contains the layout tables of the whole filesystem 93 | * inode id = -3 defines the super block 94 | * inode id = -4 defines an invalid or unknown id like the parent dir of the root directory 95 | 96 | 97 | FAQ 98 | === 99 | 100 | Why the name CoverFS? 101 | --------------------- 102 | FS = Filesystem 103 | 104 | Cover = to hide, to mask, to obfuscate, to cloud, covert, covered by clouds 105 | 106 | 107 | Is it secure? 108 | ------------- 109 | Encryption is difficult to implement correctly and I am no expert in that field. I think I made no obvious 110 | mistakes but the code needs to be checked by more experienced people. 111 | And even then, without a broad range of users and professional attackers who fail, I can 112 | never claim to be safe. 113 | 114 | 115 | What about filesystem corruption? 116 | --------------------------------- 117 | 118 | The filesystem structure is simple and optimized in order to minimize read and write access. 119 | It is build on the principle, that the filesystem is always consistent no matter of the writing order. 120 | But there is no guarantee, that no data will be lost. 121 | 122 | Also a complete file system structure checking and correction tool is not implemented yet. 123 | My small test suite works, but I haven't used it much under real conditions. 124 | 125 | 126 | What does zero-knowledge mean? 127 | ------------------------------ 128 | 129 | A zero knowledge storage hides also meta-data such as file sizes, file names and directory structures from the server operator. 130 | Most of the storage providers preserve this information on the server and therefore can't be true "zero-knowledge" services. 131 | Of course this is only possible with client-side encryption. 132 | 133 | However, CoverFS might reveal coarse information by analyzing certain access patterns such as 134 | overall size of the encrypted filesystem and coarse number of entries in a directory. 135 | 136 | 137 | Are similar tools available? 138 | ---------------------------- 139 | Take a look here: 140 | 141 | https://en.wikipedia.org/wiki/Comparison_of_online_backup_services 142 | 143 | https://en.wikipedia.org/wiki/Comparison_of_file_hosting_services 144 | 145 | -------------------------------------------------------------------------------- /cmake/FindLibgcrypt.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find GCrypt 2 | # Once done this will define 3 | # 4 | # GCRYPT_FOUND - system has GCrypt 5 | # GCRYPT_INCLUDE_DIRS - the GCrypt include directory 6 | # GCRYPT_LIBRARIES - Link these to use GCrypt 7 | # GCRYPT_DEFINITIONS - Compiler switches required for using GCrypt 8 | # 9 | #============================================================================= 10 | # Copyright (c) 2009-2011 Andreas Schneider 11 | # 12 | # Distributed under the OSI-approved BSD License (the "License"); 13 | # see accompanying file Copyright.txt for details. 14 | # 15 | # This software is distributed WITHOUT ANY WARRANTY; without even the 16 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 17 | # See the License for more information. 18 | #============================================================================= 19 | # 20 | 21 | if (GCRYPT_LIBRARIES AND GCRYPT_INCLUDE_DIRS) 22 | # in cache already 23 | # set(GCRYPT_FOUND TRUE) 24 | else (GCRYPT_LIBRARIES AND GCRYPT_INCLUDE_DIRS) 25 | 26 | set(_GCRYPT_ROOT_PATHS 27 | "$ENV{PROGRAMFILES}/libgcrypt" 28 | ) 29 | 30 | find_path(GCRYPT_ROOT_DIR 31 | NAMES 32 | include/gcrypt.h 33 | PATHS 34 | ${_GCRYPT_ROOT_PATHS} 35 | ) 36 | mark_as_advanced(ZLIB_ROOT_DIR) 37 | 38 | find_path(GCRYPT_INCLUDE_DIR 39 | NAMES 40 | gcrypt.h 41 | PATHS 42 | /usr/local/include 43 | /opt/local/include 44 | /sw/include 45 | /usr/lib/sfw/include 46 | /mingw64/include 47 | ${GCRYPT_ROOT_DIR}/include 48 | ) 49 | set(GCRYPT_INCLUDE_DIRS ${GCRYPT_INCLUDE_DIR}) 50 | 51 | find_library(GCRYPT_LIBRARY 52 | NAMES 53 | gcrypt 54 | gcrypt11 55 | libgcrypt-11 56 | PATHS 57 | /opt/local/lib 58 | /sw/lib 59 | /usr/sfw/lib/64 60 | /usr/sfw/lib 61 | /mingw64/lib 62 | ${GCRYPT_ROOT_DIR}/lib 63 | ) 64 | set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY}) 65 | 66 | include(FindPackageHandleStandardArgs) 67 | find_package_handle_standard_args(GCrypt DEFAULT_MSG GCRYPT_LIBRARIES GCRYPT_INCLUDE_DIRS) 68 | 69 | # show the GCRYPT_INCLUDE_DIRS and GCRYPT_LIBRARIES variables only in the advanced view 70 | mark_as_advanced(GCRYPT_INCLUDE_DIRS GCRYPT_LIBRARIES) 71 | 72 | endif (GCRYPT_LIBRARIES AND GCRYPT_INCLUDE_DIRS) -------------------------------------------------------------------------------- /cmake/FindPOCO.cmake: -------------------------------------------------------------------------------- 1 | # - finds the Poco C++ libraries 2 | # This module finds the Applied Informatics Poco libraries. 3 | # It supports the following components: 4 | # 5 | # Util (loaded by default) 6 | # Foundation (loaded by default) 7 | # XML 8 | # Zip 9 | # Crypto 10 | # Data 11 | # Net 12 | # NetSSL_OpenSSL 13 | # OSP 14 | # 15 | # Usage: 16 | # set(ENV{Poco_DIR} path/to/poco/sdk) 17 | # find_package(Poco REQUIRED OSP Data Crypto) 18 | # 19 | # On completion, the script defines the following variables: 20 | # 21 | # - Compound variables: 22 | # Poco_FOUND 23 | # - true if all requested components were found. 24 | # Poco_LIBRARIES 25 | # - contains release (and debug if available) libraries for all requested components. 26 | # It has the form "optimized LIB1 debug LIBd1 optimized LIB2 ...", ready for use with the target_link_libraries command. 27 | # Poco_INCLUDE_DIRS 28 | # - Contains include directories for all requested components. 29 | # 30 | # - Component variables: 31 | # Poco_Xxx_FOUND 32 | # - Where Xxx is the properly cased component name (eg. 'Util', 'OSP'). 33 | # True if a component's library or debug library was found successfully. 34 | # Poco_Xxx_LIBRARY 35 | # - Library for component Xxx. 36 | # Poco_Xxx_LIBRARY_DEBUG 37 | # - debug library for component Xxx 38 | # Poco_Xxx_INCLUDE_DIR 39 | # - include directory for component Xxx 40 | # 41 | # - OSP BundleCreator variables: (i.e. bundle.exe on windows, bundle on unix-likes) 42 | # (is only discovered if OSP is a requested component) 43 | # Poco_OSP_Bundle_EXECUTABLE_FOUND 44 | # - true if the bundle-creator executable was found. 45 | # Poco_OSP_Bundle_EXECUTABLE 46 | # - the path to the bundle-creator executable. 47 | # 48 | # Author: Andreas Stahl andreas.stahl@tu-dresden.de 49 | 50 | set(Poco_HINTS 51 | /usr/local 52 | /mingw64 53 | ${Poco_DIR} 54 | $ENV{Poco_DIR} 55 | ) 56 | 57 | if(NOT Poco_ROOT_DIR) 58 | # look for the root directory, first for the source-tree variant 59 | find_path(Poco_ROOT_DIR 60 | NAMES Foundation/include/Poco/Poco.h 61 | HINTS ${Poco_HINTS} 62 | ) 63 | if(NOT Poco_ROOT_DIR) 64 | # this means poco may have a different directory structure, maybe it was installed, let's check for that 65 | message(STATUS "Looking for Poco install directory structure.") 66 | find_path(Poco_ROOT_DIR 67 | NAMES include/Poco/Poco.h 68 | HINTS ${Poco_HINTS} 69 | ) 70 | if(NOT Poco_ROOT_DIR) 71 | # poco was still not found -> Fail 72 | if(Poco_FIND_REQUIRED) 73 | message(FATAL_ERROR "Poco: Could not find Poco install directory") 74 | endif() 75 | if(NOT Poco_FIND_QUIETLY) 76 | message(STATUS "Poco: Could not find Poco install directory") 77 | endif() 78 | return() 79 | else() 80 | # poco was found with the make install directory structure 81 | message(STATUS "Assuming Poco install directory structure at ${Poco_ROOT_DIR}.") 82 | set(Poco_INSTALLED true) 83 | endif() 84 | endif() 85 | endif() 86 | 87 | # add dynamic library directory 88 | if(WIN32 OR MSYS OR MINGW) 89 | SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".dll") 90 | #find_path(Poco_RUNTIME_LIBRARY_DIRS 91 | # NAMES PocoFoundation.dll 92 | # HINTS ${Poco_ROOT_DIR} 93 | # PATH_SUFFIXES 94 | # bin 95 | # lib 96 | #) 97 | endif() 98 | 99 | # if installed directory structure, set full include dir 100 | if(Poco_INSTALLED) 101 | set(Poco_INCLUDE_DIRS ${Poco_ROOT_DIR}/include/ CACHE PATH "The global include path for Poco") 102 | endif() 103 | 104 | # append the default minimum components to the list to find 105 | list(APPEND components 106 | ${Poco_FIND_COMPONENTS} 107 | # default components: 108 | "Util" 109 | "Foundation" 110 | ) 111 | list(REMOVE_DUPLICATES components) # remove duplicate defaults 112 | 113 | foreach( component ${components} ) 114 | # include directory for the component 115 | if(NOT Poco_${component}_INCLUDE_DIR) 116 | find_path(Poco_${component}_INCLUDE_DIR 117 | NAMES 118 | Poco/${component}.h # e.g. Foundation.h 119 | Poco/${component}/${component}.h # e.g. OSP/OSP.h Util/Util.h 120 | HINTS 121 | ${Poco_ROOT_DIR} 122 | PATH_SUFFIXES 123 | include 124 | ${component}/include 125 | ) 126 | endif() 127 | if(NOT Poco_${component}_INCLUDE_DIR) 128 | message(FATAL_ERROR "Poco_${component}_INCLUDE_DIR NOT FOUND") 129 | else() 130 | list(APPEND Poco_INCLUDE_DIRS ${Poco_${component}_INCLUDE_DIR}) 131 | endif() 132 | 133 | # release library 134 | if(NOT Poco_${component}_LIBRARY) 135 | find_library( 136 | Poco_${component}_LIBRARY 137 | NAMES Poco${component} 138 | HINTS ${Poco_ROOT_DIR} 139 | PATH_SUFFIXES 140 | lib 141 | bin 142 | ) 143 | if(Poco_${component}_LIBRARY) 144 | message(STATUS "Found Poco ${component}: ${Poco_${component}_LIBRARY}") 145 | endif() 146 | endif() 147 | if(Poco_${component}_LIBRARY) 148 | list(APPEND Poco_LIBRARIES "optimized" ${Poco_${component}_LIBRARY} ) 149 | mark_as_advanced(Poco_${component}_LIBRARY) 150 | endif() 151 | 152 | # debug library 153 | if(NOT Poco_${component}_LIBRARY_DEBUG) 154 | find_library( 155 | Poco_${component}_LIBRARY_DEBUG 156 | Names Poco${component}d 157 | HINTS ${Poco_ROOT_DIR} 158 | PATH_SUFFIXES 159 | lib 160 | bin 161 | ) 162 | if(Poco_${component}_LIBRARY_DEBUG) 163 | message(STATUS "Found Poco ${component} (debug): ${Poco_${component}_LIBRARY_DEBUG}") 164 | endif() 165 | endif(NOT Poco_${component}_LIBRARY_DEBUG) 166 | if(Poco_${component}_LIBRARY_DEBUG) 167 | list(APPEND Poco_LIBRARIES "debug" ${Poco_${component}_LIBRARY_DEBUG}) 168 | mark_as_advanced(Poco_${component}_LIBRARY_DEBUG) 169 | endif() 170 | 171 | # mark component as found or handle not finding it 172 | if(Poco_${component}_LIBRARY_DEBUG OR Poco_${component}_LIBRARY) 173 | set(Poco_${component}_FOUND TRUE) 174 | elseif(NOT Poco_FIND_QUIETLY) 175 | message(FATAL_ERROR "Could not find Poco component ${component}!") 176 | endif() 177 | endforeach() 178 | 179 | if(DEFINED Poco_LIBRARIES) 180 | set(Poco_FOUND true) 181 | endif() 182 | 183 | message(STATUS "Found Poco: ${Poco_LIBRARIES}") 184 | -------------------------------------------------------------------------------- /cmake/Finddokan.cmake: -------------------------------------------------------------------------------- 1 | #set(DOKAN_ROOT_PATHS "$ENV{PROGRAMFILES}/Dokan") 2 | 3 | #MESSAGE( STATUS "DOKAN_ROOT_PATH: " ${DOKAN_ROOT_PATHS} ) 4 | 5 | set(DOKAN_FOUND TRUE) 6 | 7 | set(DOKAN_ROOT_PATHS "/cygdrive/c/Program Files/Dokan/Dokan Library-1.0.3" 8 | "/c/Program Files/Dokan/Dokan Library-1.0.3" 9 | "c:/Program Files/Dokan/Dokan Library-1.0.3") 10 | 11 | find_path(DOKAN_INCLUDE_DIR 12 | NAMES 13 | dokan/dokan.h 14 | PATHS 15 | ${DOKAN_ROOT_PATHS} 16 | PATH_SUFFIXES 17 | include 18 | ) 19 | 20 | 21 | if(NOT DOKAN_INCLUDE_DIRS) 22 | set(DOKAN_FOUND FALSE) 23 | endif(NOT DOKAN_INCLUDE_DIRS) 24 | 25 | SET(CMAKE_FIND_LIBRARY_PREFIXES "") 26 | SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".dll") 27 | 28 | find_library(DOKAN_LIB_DIR 29 | NAMES 30 | dokan1 31 | PATHS 32 | ${DOKAN_ROOT_PATHS} 33 | ) 34 | 35 | if(NOT DOKAN_LIB_DIRS) 36 | set(DOKAN_FOUND FALSE) 37 | endif(NOT DOKAN_LIB_DIRS) 38 | 39 | MESSAGE( STATUS "DOKAN_INCLUDE_DIR: " ${DOKAN_INCLUDE_DIR} ) 40 | MESSAGE( STATUS "DOKAN_LIB_DIR: " ${DOKAN_LIB_DIR} ) -------------------------------------------------------------------------------- /cmake/Findfuse.cmake: -------------------------------------------------------------------------------- 1 | # This module can find FUSE Library 2 | # 3 | # Requirements: 4 | # - CMake >= 2.8.3 5 | # 6 | # The following variables will be defined for your use: 7 | # - FUSE_FOUND : was FUSE found? 8 | # - FUSE_INCLUDE_DIRS : FUSE include directory 9 | # - FUSE_LIBRARIES : FUSE library 10 | # - FUSE_DEFINITIONS : FUSE cflags 11 | # - FUSE_VERSION : complete version of FUSE (major.minor) 12 | # - FUSE_MAJOR_VERSION : major version of FUSE 13 | # - FUSE_MINOR_VERSION : minor version of FUSE 14 | # 15 | # Example Usage: 16 | # 17 | # 1. Copy this file in the root of your project source directory 18 | # 2. Then, tell CMake to search this non-standard module in your project directory by adding to your CMakeLists.txt: 19 | # set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) 20 | # 3. Finally call find_package() once, here are some examples to pick from 21 | # 22 | # Require FUSE 2.6 or later 23 | # find_package(FUSE 2.6 REQUIRED) 24 | # 25 | # if(FUSE_FOUND) 26 | # add_definitions(${FUSE_DEFINITIONS}) 27 | # include_directories(${FUSE_INCLUDE_DIRS}) 28 | # add_executable(myapp myapp.c) 29 | # target_link_libraries(myapp ${FUSE_LIBRARIES}) 30 | # endif() 31 | 32 | #============================================================================= 33 | # Copyright (c) 2012, julp 34 | # 35 | # Distributed under the OSI-approved BSD License 36 | # 37 | # This software is distributed WITHOUT ANY WARRANTY; without even the 38 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 39 | #============================================================================= 40 | 41 | cmake_minimum_required(VERSION 2.8.3) 42 | 43 | ########## Private ########## 44 | function(fusedebug _varname) 45 | if(FUSE_DEBUG) 46 | message("${_varname} = ${${_varname}}") 47 | endif(FUSE_DEBUG) 48 | endfunction(fusedebug) 49 | 50 | ########## Public ########## 51 | set(FUSE_FOUND TRUE) 52 | set(FUSE_LIBRARIES ) 53 | set(FUSE_DEFINITIONS ) 54 | set(FUSE_INCLUDE_DIRS ) 55 | 56 | find_package(PkgConfig) 57 | 58 | set(PC_FUSE_INCLUDE_DIRS ) 59 | set(PC_FUSE_LIBRARY_DIRS ) 60 | if(PKG_CONFIG_FOUND) 61 | pkg_check_modules(PC_FUSE "fuse" QUIET) 62 | if(PC_FUSE_FOUND) 63 | # fusedebug(PC_FUSE_LIBRARIES) 64 | # fusedebug(PC_FUSE_LIBRARY_DIRS) 65 | # fusedebug(PC_FUSE_LDFLAGS) 66 | # fusedebug(PC_FUSE_LDFLAGS_OTHER) 67 | # fusedebug(PC_FUSE_INCLUDE_DIRS) 68 | # fusedebug(PC_FUSE_CFLAGS) 69 | # fusedebug(PC_FUSE_CFLAGS_OTHER) 70 | set(FUSE_DEFINITIONS "${PC_FUSE_CFLAGS_OTHER}") 71 | endif(PC_FUSE_FOUND) 72 | endif(PKG_CONFIG_FOUND) 73 | 74 | find_path( 75 | FUSE_INCLUDE_DIRS 76 | NAMES fuse_common.h fuse_lowlevel.h fuse.h 77 | PATHS "${PC_FUSE_INCLUDE_DIRS}" 78 | DOC "Include directories for FUSE" 79 | ) 80 | 81 | if(NOT FUSE_INCLUDE_DIRS) 82 | set(FUSE_FOUND FALSE) 83 | endif(NOT FUSE_INCLUDE_DIRS) 84 | 85 | find_library( 86 | FUSE_LIBRARIES 87 | NAMES "fuse" 88 | PATHS "${PC_FUSE_LIBRARY_DIRS}" 89 | DOC "Libraries for FUSE" 90 | ) 91 | 92 | if(NOT FUSE_LIBRARIES) 93 | set(FUSE_FOUND FALSE) 94 | endif(NOT FUSE_LIBRARIES) 95 | 96 | if(FUSE_FOUND) 97 | if(EXISTS "${FUSE_INCLUDE_DIRS}/fuse_common.h") 98 | file(READ "${FUSE_INCLUDE_DIRS}/fuse_common.h" _contents) 99 | string(REGEX REPLACE ".*# *define *FUSE_MAJOR_VERSION *([0-9]+).*" "\\1" FUSE_MAJOR_VERSION "${_contents}") 100 | string(REGEX REPLACE ".*# *define *FUSE_MINOR_VERSION *([0-9]+).*" "\\1" FUSE_MINOR_VERSION "${_contents}") 101 | set(FUSE_VERSION "${FUSE_MAJOR_VERSION}.${FUSE_MINOR_VERSION}") 102 | endif() 103 | 104 | include(CheckCSourceCompiles) 105 | # Backup CMAKE_REQUIRED_* 106 | set(OLD_CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}") 107 | set(OLD_CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}") 108 | set(OLD_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") 109 | # Add FUSE compilation flags 110 | set(CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}" "${FUSE_INCLUDE_DIRS}") 111 | set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}" "${FUSE_LIBRARIES}") 112 | set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}" "${FUSE_DEFINITIONS}") 113 | check_c_source_compiles("#include 114 | #include 115 | #include 116 | #include 117 | #include 118 | #include 119 | 120 | int main(void) { 121 | return 0; 122 | }" FUSE_CFLAGS_CHECK) 123 | if(NOT FUSE_CFLAGS_CHECK) 124 | set(FUSE_DEFINITIONS "-D_FILE_OFFSET_BITS=64") 125 | # Should we run again previous test to assume the failure was due to missing definition -D_FILE_OFFSET_BITS=64? 126 | endif(NOT FUSE_CFLAGS_CHECK) 127 | # Restore CMAKE_REQUIRED_* 128 | set(CMAKE_REQUIRED_INCLUDES "${OLD_CMAKE_REQUIRED_INCLUDES}") 129 | set(CMAKE_REQUIRED_LIBRARIES "${OLD_CMAKE_REQUIRED_LIBRARIES}") 130 | set(CMAKE_REQUIRED_DEFINITIONS "${OLD_CMAKE_REQUIRED_DEFINITIONS}") 131 | endif(FUSE_FOUND) 132 | 133 | if(FUSE_INCLUDE_DIRS) 134 | include(FindPackageHandleStandardArgs) 135 | if(FUSE_FIND_REQUIRED AND NOT FUSE_FIND_QUIETLY) 136 | find_package_handle_standard_args(FUSE REQUIRED_VARS FUSE_LIBRARIES FUSE_INCLUDE_DIRS VERSION_VAR FUSE_VERSION) 137 | else() 138 | find_package_handle_standard_args(FUSE "FUSE not found" FUSE_LIBRARIES FUSE_INCLUDE_DIRS) 139 | endif() 140 | else(FUSE_INCLUDE_DIRS) 141 | if(FUSE_FIND_REQUIRED AND NOT FUSE_FIND_QUIETLY) 142 | message(FATAL_ERROR "Could not find FUSE include directory") 143 | endif() 144 | endif(FUSE_INCLUDE_DIRS) 145 | 146 | mark_as_advanced( 147 | FUSE_INCLUDE_DIRS 148 | FUSE_LIBRARIES 149 | ) 150 | 151 | # IN (args) 152 | fusedebug("FUSE_FIND_COMPONENTS") 153 | fusedebug("FUSE_FIND_REQUIRED") 154 | fusedebug("FUSE_FIND_QUIETLY") 155 | fusedebug("FUSE_FIND_VERSION") 156 | # OUT 157 | # Found 158 | fusedebug("FUSE_FOUND") 159 | # Definitions 160 | fusedebug("FUSE_DEFINITIONS") 161 | # Linking 162 | fusedebug("FUSE_INCLUDE_DIRS") 163 | fusedebug("FUSE_LIBRARIES") 164 | # Version 165 | fusedebug("FUSE_MAJOR_VERSION") 166 | fusedebug("FUSE_MINOR_VERSION") 167 | fusedebug("FUSE_VERSION") 168 | 169 | -------------------------------------------------------------------------------- /cmake/config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated by cmake from config.h.in */ 2 | 3 | #define PROJECT_VERSION @PROJECT_VERSION@ 4 | 5 | #cmakedefine HAVE_POCO 6 | -------------------------------------------------------------------------------- /resources/ToIco.sh: -------------------------------------------------------------------------------- 1 | cat umbrella.svg > umbrella_temp.svg 2 | convert -background transparent -density 256x256 -define icon:auto-resize -trim umbrella_temp.svg umbrella_green.ico 3 | 4 | cat umbrella.svg | \ 5 | sed 's/88C057/C03758/' | \ 6 | sed 's/75A64B/962B35/' > umbrella_temp.svg 7 | 8 | convert -background transparent -density 256x256 -define icon:auto-resize -trim umbrella_temp.svg umbrella_red.ico 9 | 10 | cat umbrella.svg | \ 11 | sed 's/88C057/C0C050/' | \ 12 | sed 's/75A64B/A0A030/' > umbrella_temp.svg 13 | 14 | convert -background transparent -density 256x256 -define icon:auto-resize -trim umbrella_temp.svg umbrella_yellow.ico 15 | 16 | 17 | rm umbrella_temp.svg 18 | -------------------------------------------------------------------------------- /resources/umbrella.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/FS/CFilesystem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include"CFilesystem.h" 5 | 6 | CDirectoryIterator::~CDirectoryIterator() {} 7 | 8 | CDirectory::~CDirectory() {} 9 | 10 | CInode::~CInode() { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/FS/CFilesystem.h: -------------------------------------------------------------------------------- 1 | #ifndef CFILESYSTEM_H 2 | #define CFILESYSTEM_H 3 | 4 | #include 5 | #include 6 | #include "CPath.h" 7 | 8 | class CStatFS 9 | { 10 | public: 11 | int f_bsize; 12 | int f_frsize; 13 | int f_namemax; 14 | int64_t f_blocks; 15 | int64_t f_bfree; 16 | int64_t f_bavail; 17 | int64_t f_files; 18 | }; 19 | 20 | enum class INODETYPE : int32_t {undefined=0, dir=1, file=2, special=3}; 21 | 22 | class CInode 23 | { 24 | public: 25 | virtual ~CInode(); 26 | 27 | virtual int64_t Read(int8_t *d, int64_t ofs, int64_t size)=0; 28 | virtual void Write(const int8_t *d, int64_t ofs, int64_t size)=0; 29 | virtual void Truncate(int64_t size, bool dozero)=0; 30 | virtual int64_t GetSize()=0; 31 | virtual int32_t GetId()=0; 32 | virtual INODETYPE GetType()=0; 33 | }; 34 | using CInodePtr = std::shared_ptr; 35 | 36 | class CDirectoryEntry 37 | { 38 | public: 39 | CDirectoryEntry(const std::string _name, int32_t _id) : name(_name), id(_id) {} 40 | CDirectoryEntry() {} 41 | std::string name; 42 | int32_t id; 43 | 44 | }; 45 | 46 | 47 | class CDirectoryIterator 48 | { 49 | public: 50 | virtual ~CDirectoryIterator(); 51 | 52 | virtual bool HasNext()=0; 53 | virtual CDirectoryEntry Next()=0; 54 | 55 | private: 56 | CDirectoryEntry de; 57 | }; 58 | using CDirectoryIteratorPtr = std::unique_ptr; 59 | 60 | class CDirectory 61 | { 62 | public: 63 | virtual ~CDirectory(); 64 | 65 | virtual CDirectoryIteratorPtr GetIterator()=0; 66 | virtual int MakeDirectory(const std::string& name)=0; 67 | virtual int MakeFile(const std::string& name)=0; 68 | virtual int32_t GetId()=0; 69 | virtual bool IsEmpty()=0; 70 | }; 71 | using CDirectoryPtr = std::shared_ptr; 72 | 73 | class CFilesystem 74 | { 75 | public: 76 | virtual CInodePtr OpenNode(const CPath &path)=0; 77 | virtual CInodePtr OpenNode(int id)=0; 78 | 79 | virtual CDirectoryPtr OpenDir(const CPath &path)=0; 80 | virtual CDirectoryPtr OpenDir(int id)=0; 81 | 82 | virtual CInodePtr OpenFile(const CPath &path)=0; 83 | virtual CInodePtr OpenFile(int id)=0; 84 | 85 | virtual void Rename(const CPath &path, CDirectoryPtr newdir, const std::string &filename)=0; 86 | virtual void Unlink(const CPath &path)=0; 87 | virtual void StatFS(CStatFS *buf)=0; 88 | 89 | virtual void PrintInfo()=0; 90 | virtual void PrintFragments()=0; 91 | virtual void Check()=0; 92 | }; 93 | using CFilesystemPtr = std::shared_ptr; 94 | 95 | #endif -------------------------------------------------------------------------------- /src/FS/CPath.cpp: -------------------------------------------------------------------------------- 1 | #include "CPath.h" 2 | 3 | CPath::CPath(std::vector &_splitpath) : splitpath(_splitpath) {} 4 | 5 | CPath::CPath(const std::string &path) 6 | { 7 | std::vector d; 8 | std::string s; 9 | 10 | assert(!path.empty()); 11 | 12 | unsigned int idx = 0; 13 | 14 | while (idx < path.size()) 15 | { 16 | if ((path[idx] == '/') || (path[idx] == '\\')) 17 | { 18 | if (!s.empty()) 19 | { 20 | d.push_back(s); 21 | s = ""; 22 | } 23 | idx++; 24 | continue; 25 | } 26 | s += path[idx]; 27 | idx++; 28 | } 29 | if (!s.empty()) d.push_back(s); 30 | /* 31 | for(unsigned int i=0; i& CPath::GetPath() const { 38 | return splitpath; 39 | } 40 | -------------------------------------------------------------------------------- /src/FS/CPath.h: -------------------------------------------------------------------------------- 1 | #ifndef CPATH_H 2 | #define CPATH_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | class CPath 10 | { 11 | public: 12 | CPath(std::vector &_splitpath); 13 | CPath(const std::string &path); 14 | 15 | const std::vector& GetPath() const; 16 | 17 | private: 18 | std::vector splitpath; 19 | }; 20 | 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/FS/ContainerFS/ContainerFS.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by sebastian on 09.05.18. 3 | // 4 | 5 | #include "ContainerFS.h" 6 | #include "../CFilesystem.h" 7 | 8 | #define ROOTDIRINODE 1 9 | #define CONTAINERNODE 2 10 | 11 | // ---------------------------------------------------- 12 | 13 | ContainerFS::ContainerFS(const std::shared_ptr &_bio) : bio(_bio) 14 | { 15 | } 16 | 17 | ContainerFS::~ContainerFS() 18 | = default; 19 | 20 | 21 | // ---------------------------------------------------- 22 | 23 | 24 | CInodePtr ContainerFS::OpenNode(int id) 25 | { 26 | if (id == ROOTDIRINODE) 27 | { 28 | return std::make_shared(bio); 29 | } 30 | if (id == CONTAINERNODE) 31 | { 32 | return std::make_shared(bio); 33 | } 34 | throw ENOENT; 35 | } 36 | 37 | CDirectoryPtr ContainerFS::OpenDir(int id) 38 | { 39 | if (id == ROOTDIRINODE) 40 | { 41 | return std::make_shared(); 42 | } 43 | throw ENOENT; 44 | 45 | } 46 | 47 | CInodePtr ContainerFS::OpenFile(int id) 48 | { 49 | if (id == CONTAINERNODE) 50 | { 51 | return std::make_shared(bio); 52 | } 53 | throw ENOENT; 54 | } 55 | 56 | // ---------------------------------------------------- 57 | 58 | void ContainerFS::Rename(const CPath &path, CDirectoryPtr newdir, const std::string &filename) 59 | { 60 | throw EPERM; 61 | } 62 | 63 | void ContainerFS::Unlink(const CPath &path) 64 | { 65 | throw EPERM; 66 | } 67 | 68 | void ContainerFS::StatFS(CStatFS *buf) 69 | { 70 | buf->f_bsize = bio->blocksize; 71 | buf->f_frsize = bio->blocksize; 72 | buf->f_namemax = 64; 73 | 74 | int64_t totalsize = bio->GetFilesize() + (100LL * 0x40000000LL); // add always 100GB 75 | buf->f_blocks = totalsize/bio->blocksize; 76 | 77 | buf->f_bfree = 0; 78 | buf->f_bavail = 0; 79 | buf->f_files = 1; 80 | } 81 | 82 | // ---------------------------------------------------- 83 | 84 | CInodePtr ContainerFS::OpenNode(const CPath &path) 85 | { 86 | if (path.GetPath().size() == 0) 87 | return OpenNode(ROOTDIRINODE); 88 | if ((path.GetPath().size() == 1) && (path.GetPath()[0] == "container")) 89 | return OpenNode(CONTAINERNODE); 90 | 91 | throw ENOENT; 92 | } 93 | 94 | CDirectoryPtr ContainerFS::OpenDir(const CPath &path) 95 | { 96 | if (path.GetPath().size() == 0) 97 | return OpenDir(ROOTDIRINODE); 98 | throw ENOENT; 99 | } 100 | 101 | CInodePtr ContainerFS::OpenFile(const CPath &path) 102 | { 103 | if (path.GetPath().size() == 0) 104 | return OpenFile(ROOTDIRINODE); 105 | if ((path.GetPath().size() == 1) && (path.GetPath()[0] == "container")) 106 | return OpenFile(CONTAINERNODE); 107 | throw ENOENT; 108 | } 109 | 110 | // ---------------------------------------------------- 111 | 112 | void ContainerFS::PrintInfo() 113 | { 114 | } 115 | 116 | void ContainerFS::PrintFragments() 117 | { 118 | } 119 | 120 | void ContainerFS::Check() 121 | { 122 | } 123 | 124 | // ---------------------------------------------------- 125 | 126 | CDirectoryIteratorPtr ContainerFSDirectory::GetIterator() 127 | { 128 | return std::make_unique(); 129 | } 130 | 131 | int ContainerFSDirectory::MakeDirectory(const std::string &name) 132 | { 133 | throw ENOENT; 134 | } 135 | 136 | int ContainerFSDirectory::MakeFile(const std::string &name) 137 | { 138 | throw ENOENT; 139 | } 140 | 141 | int32_t ContainerFSDirectory::GetId() 142 | { 143 | return ROOTDIRINODE; 144 | } 145 | 146 | bool ContainerFSDirectory::IsEmpty() 147 | { 148 | return false; 149 | } 150 | 151 | // ---------------------------------------------------- 152 | 153 | ContainerFSInode::ContainerFSInode(const std::shared_ptr &bio) : bio(bio) {} 154 | 155 | int64_t ContainerFSInode::Read(int8_t *d, int64_t ofs, int64_t size) 156 | { 157 | bio->Read(ofs+bio->blocksize, size, d); 158 | return size; 159 | } 160 | 161 | void ContainerFSInode::Write(const int8_t *d, int64_t ofs, int64_t size) 162 | { 163 | bio->Write(ofs+bio->blocksize, size, d); 164 | } 165 | 166 | void ContainerFSInode::Truncate(int64_t size, bool dozero) 167 | { 168 | throw EPERM; 169 | } 170 | 171 | int64_t ContainerFSInode::GetSize() 172 | { 173 | return bio->GetFilesize()-bio->blocksize; 174 | } 175 | 176 | int32_t ContainerFSInode::GetId() 177 | { 178 | return CONTAINERNODE; 179 | } 180 | 181 | INODETYPE ContainerFSInode::GetType() 182 | { 183 | return INODETYPE::file; 184 | } 185 | 186 | // ---------------------------------------------------- 187 | 188 | bool ContainerFSDirectoryIterator::HasNext() { 189 | return index==0; 190 | } 191 | 192 | CDirectoryEntry ContainerFSDirectoryIterator::Next() { 193 | index++; 194 | return CDirectoryEntry("container", CONTAINERNODE); 195 | } 196 | -------------------------------------------------------------------------------- /src/FS/ContainerFS/ContainerFS.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTAINERFS_H 2 | #define CONTAINERFS_H 3 | 4 | 5 | #include 6 | #include "../CFilesystem.h" 7 | #include "../../IO/CCacheIO.h" 8 | 9 | class ContainerFS : public CFilesystem 10 | { 11 | 12 | public: 13 | 14 | explicit ContainerFS(const std::shared_ptr &_bio); 15 | ~ContainerFS(); 16 | 17 | CInodePtr OpenNode(int id) override; 18 | CInodePtr OpenNode(const CPath &path) override; 19 | 20 | CDirectoryPtr OpenDir(int id) override; 21 | CDirectoryPtr OpenDir(const CPath &path) override; 22 | 23 | CInodePtr OpenFile(int id) override; 24 | CInodePtr OpenFile(const CPath &path) override; 25 | 26 | void PrintInfo() override; 27 | void PrintFragments() override; 28 | void Check() override; 29 | 30 | void Rename(const CPath &path, CDirectoryPtr newdir, const std::string &filename) override; 31 | void Unlink(const CPath &path) override; 32 | void StatFS(CStatFS *buf) override; 33 | 34 | private: 35 | std::shared_ptr bio; 36 | }; 37 | 38 | 39 | class ContainerFSDirectory : public CDirectory 40 | { 41 | public: 42 | CDirectoryIteratorPtr GetIterator() override; 43 | 44 | int MakeDirectory(const std::string &name) override; 45 | int MakeFile(const std::string &name) override; 46 | int32_t GetId() override; 47 | bool IsEmpty() override; 48 | }; 49 | 50 | class ContainerFSInode : public CInode 51 | { 52 | public: 53 | explicit ContainerFSInode(const std::shared_ptr &bio); 54 | 55 | int64_t Read(int8_t *d, int64_t ofs, int64_t size) override; 56 | void Write(const int8_t *d, int64_t ofs, int64_t size) override; 57 | void Truncate(int64_t size, bool dozero) override; 58 | int64_t GetSize() override; 59 | int32_t GetId() override; 60 | INODETYPE GetType() override; 61 | 62 | private: 63 | std::shared_ptr bio; 64 | }; 65 | 66 | 67 | class ContainerFSDirectoryIterator : public CDirectoryIterator 68 | { 69 | public: 70 | bool HasNext() override; 71 | 72 | CDirectoryEntry Next() override; 73 | private: 74 | int index=0; 75 | 76 | }; 77 | 78 | #endif //COVERFS_CONTAINERFS_H 79 | -------------------------------------------------------------------------------- /src/FS/SimpleFS/CFragment.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include"Logger.h" 6 | #include"CFragment.h" 7 | 8 | void CFragmentList::Load() 9 | { 10 | unsigned int nfragmentblocks = 5; 11 | unsigned int nentries = bio->blocksize*nfragmentblocks/CFragmentDesc::SIZEONDISK; 12 | LOG(LogLevel::INFO) << " number of blocks containing fragments: " << nfragmentblocks << " with " << nentries << " entries"; 13 | 14 | fragmentblocks.clear(); 15 | for(unsigned int i=0; iGetBlock(i+2)); 17 | 18 | ofssort.assign(nentries, 0); 19 | for(unsigned int i=0; iblocksize / CFragmentDesc::SIZEONDISK; 26 | CBLOCKPTR block = fragmentblocks[i]; 27 | int8_t* buf = block->GetBufRead(); 28 | for(int j=0; jReleaseBuf(); 33 | } 34 | SortOffsets(); 35 | } 36 | 37 | void CFragmentList::Create() 38 | { 39 | unsigned int nfragmentblocks = 5; 40 | unsigned int nentries = bio->blocksize*nfragmentblocks/16; 41 | LOG(LogLevel::INFO) << " number of blocks containing fragments: " << nfragmentblocks << " with " << nentries << " entries"; 42 | // --- 43 | fragmentblocks.clear(); 44 | for(unsigned int i=0; iGetBlock(i+2)); 47 | } 48 | // --- 49 | 50 | ofssort.assign(nentries, 0); 51 | for(unsigned int i=0; iblocksize*2); 58 | fragments[1] = CFragmentDesc(INODETYPE::special, CFragmentDesc::TABLEID, 2, bio->blocksize*nfragmentblocks); 59 | 60 | SortOffsets(); 61 | 62 | for(unsigned int i=0; iSync(); 66 | } 67 | 68 | 69 | void CFragmentList::StoreFragment(int idx) 70 | { 71 | int nidsperblock = bio->blocksize / 16; 72 | CBLOCKPTR block = fragmentblocks[idx/nidsperblock]; 73 | int8_t* buf = block->GetBufReadWrite(); 74 | fragments[idx].ToDisk( &buf[(idx%nidsperblock) * CFragmentDesc::SIZEONDISK] ); 75 | block->ReleaseBuf(); 76 | } 77 | 78 | void CFragmentList::FreeAllFragments(std::vector &ff) 79 | { 80 | std::lock_guard lock(fragmentsmtx); 81 | for (int f : ff) 82 | { 83 | fragments[f].id = CFragmentDesc::FREEID; 84 | fragments[f].type = INODETYPE::undefined; 85 | StoreFragment(f); 86 | } 87 | SortOffsets(); 88 | bio->Sync(); 89 | } 90 | 91 | void CFragmentList::GetFragmentIdxList(int32_t id, std::vector &list, int64_t &size) 92 | { 93 | size = 0; 94 | list.clear(); 95 | std::lock_guard lock(fragmentsmtx); 96 | for(unsigned int i=0; i lock(fragmentsmtx); 107 | for (auto &fragment : fragments) 108 | { 109 | if (fragment.id != id) continue; 110 | return fragment.type; 111 | } 112 | return INODETYPE::undefined; 113 | } 114 | 115 | 116 | int CFragmentList::ReserveNewFragment(INODETYPE type) 117 | { 118 | std::lock_guard lock(fragmentsmtx); 119 | 120 | int idmax = -1; 121 | for (auto &fragment : fragments) 122 | { 123 | if (fragment.id > idmax) idmax = fragment.id; 124 | } 125 | int id = idmax+1; 126 | LOG(LogLevel::DEEP) << "Reserve new id " << id << " of type " << (int)type; 127 | 128 | for(unsigned int i=0; i lock(fragmentsmtx); // locked elsewhere 149 | 150 | int storeidx = -1; 151 | // first find a free id 152 | for(unsigned int i=lastidx+1; iblocksize); 171 | if (fragments[idx2].size == 0) break; 172 | if (fragments[idx2].id == CFragmentDesc::FREEID) break; 173 | 174 | int64_t hole = (fragments[idx2].ofs - nextofs)*bio->blocksize; 175 | assert(hole >= 0); 176 | 177 | // prevent fragmentation 178 | if ((hole > 0x100000) || (hole > maxsize/4)) 179 | { 180 | fragments[storeidx].id = id; 181 | fragments[storeidx].size = std::min({maxsize, hole, (int64_t)0xFFFFFFFFL}); 182 | fragments[storeidx].ofs = nextofs; 183 | fragments[storeidx].type = type; 184 | return storeidx; 185 | } 186 | } 187 | 188 | // No hole found, so put it at the end 189 | //printf("no hole found\n"); 190 | fragments[storeidx].id = id; 191 | fragments[storeidx].size = std::min(maxsize, 0xFFFFFFFFL); 192 | fragments[storeidx].type = type; 193 | if (fragments[idx1].size == 0) 194 | fragments[storeidx].ofs = fragments[idx1].ofs; 195 | else 196 | fragments[storeidx].ofs = fragments[idx1].ofs + (fragments[idx1].size-1)/bio->blocksize + 1; 197 | 198 | return storeidx; 199 | } 200 | 201 | void CFragmentList::SortOffsets() 202 | { 203 | std::sort(ofssort.begin(),ofssort.end(), [&](int a, int b) 204 | { 205 | int ofs1 = fragments[a].ofs; 206 | int ofs2 = fragments[b].ofs; 207 | if (fragments[a].size == 0) ofs1 = INT_MAX; 208 | if (fragments[b].size == 0) ofs2 = INT_MAX; 209 | if (fragments[a].id == CFragmentDesc::FREEID) ofs1 = INT_MAX; 210 | if (fragments[b].id == CFragmentDesc::FREEID) ofs2 = INT_MAX; 211 | return ofs1 < ofs2; 212 | }); 213 | } 214 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /src/FS/SimpleFS/CFragment.h: -------------------------------------------------------------------------------- 1 | #ifndef CFRAGMENT_H 2 | #define CFRAGMENT_H 3 | 4 | #include"CSimpleFSInode.h" 5 | 6 | #include"../IO/CCacheIO.h" 7 | 8 | 9 | // this is the structure on the hard drive 10 | class CFragmentDesc 11 | { 12 | public: 13 | CFragmentDesc(INODETYPE _type, int32_t _id, uint32_t _ofs=0, uint32_t _size=0) : type(_type), id(_id), size(_size), ofs(_ofs){}; 14 | 15 | explicit CFragmentDesc(int8_t *ram) 16 | { 17 | id = *(int32_t*) (ram+0); 18 | size = *(uint32_t*) (ram+4); 19 | ofs = *((uint64_t*) (ram+8)) & 0xFFFFFFFFFFFFFF; // 56 bit 20 | type = (INODETYPE)(*(char*) (ram+15)); 21 | } 22 | 23 | void ToDisk(int8_t *ram) 24 | { 25 | *(int32_t*) (ram+0) = id; 26 | *(uint32_t*) (ram+4) = size; 27 | *((uint64_t*)(ram+8)) = ofs & 0xFFFFFFFFFFFFFF; // 56 bit 28 | *(char*) (ram+15) = (char)type; 29 | } 30 | 31 | uint64_t GetNextFreeBlock(int blocksize) const { return ofs + (size-1)/blocksize + 1; }; 32 | 33 | INODETYPE type; 34 | int32_t id; 35 | uint32_t size; // in bytes 36 | uint64_t ofs; // in blocks 37 | 38 | static const int SIZEONDISK = 16; 39 | 40 | static const int32_t ROOTID = 0; // contains the root directory structure 41 | static const int32_t FREEID = -1; // this block is not used and can be overwritten 42 | static const int32_t TABLEID = -2; // contains the layout tables of the whole filesystem 43 | static const int32_t SUPERID = -3; // id of the super block 44 | static const int32_t INVALIDID = -4; // defines an invalid id like the parent dir of the root directory 45 | }; 46 | 47 | class CFragmentList 48 | { 49 | public: 50 | CFragmentList(const std::shared_ptr &_bio) : bio(_bio) {} 51 | 52 | std::shared_ptr bio; 53 | 54 | std::mutex fragmentsmtx; 55 | std::vector fragments; 56 | std::vector fragmentblocks; 57 | std::vector ofssort; 58 | 59 | void Create(); 60 | void Load(); 61 | void StoreFragment(int idx); 62 | void FreeAllFragments(std::vector &ff); 63 | int ReserveNewFragment(INODETYPE type); 64 | int ReserveNextFreeFragment(int lastidx, int32_t id, INODETYPE type, int64_t maxsize); 65 | void GetFragmentIdxList(int32_t id, std::vector &list, int64_t &size); 66 | INODETYPE GetType(int32_t id); 67 | void SortOffsets(); 68 | }; 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/FS/SimpleFS/CPrintCheckRepair.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include"CPrintCheckRepair.h" 5 | #include"CSimpleFSDirectory.h" 6 | 7 | void CPrintCheckRepair::GetRecursiveDirectories(std::map &direntries, int id, const std::string &path) 8 | { 9 | //printf("recursive: %i %li\n", id, fs.GetNInodes()); 10 | std::string newpath; 11 | try 12 | { 13 | CSimpleFSInodePtr node = fs.OpenNodeInternal(id); 14 | //printf("recursive opened: %i\n", id); 15 | CSimpleFSDirectory dir = CSimpleFSDirectory(node, fs); 16 | 17 | CSimpleFSInternalDirectoryIteratorPtr iterator = dir.GetInternalIterator(); 18 | while(iterator->HasNext()) { 19 | CDirectoryEntryOnDisk de = iterator->Next(); 20 | 21 | //printf("id=%9i: '%s/%s'\n", de.id, path.c_str(), de.name); 22 | if (de.id == CFragmentDesc::INVALIDID) continue; 23 | auto it = direntries.find(de.id); 24 | if (it != direntries.end()) 25 | { 26 | printf("Warning: Found two directory entries with the same id id=%i in directory '%s' and directory '%s'\n", 27 | de.id, path.c_str(), it->second.c_str()); 28 | } 29 | direntries[de.id] = path + "/" + de.name; 30 | if (fs.fragmentlist.GetType(de.id) == INODETYPE::dir) 31 | { 32 | newpath = path + "/" + de.name; 33 | GetRecursiveDirectories(direntries, de.id, newpath); 34 | } 35 | } 36 | } 37 | catch(const int &err) 38 | { 39 | printf("Error: Cannot open dir '%s' with id=%i. Errno: %s\n", path.c_str(), id, strerror(err)); 40 | } 41 | } 42 | 43 | void CPrintCheckRepair::PrintFragments() 44 | { 45 | auto &fragments = fs.fragmentlist.fragments; 46 | 47 | printf("Receive List of all directories\n"); 48 | std::map direntries; 49 | GetRecursiveDirectories(direntries, 0, ""); 50 | 51 | printf("Fragment List:\n"); 52 | for(unsigned int i=0; iblocksize); 80 | if (fs.fragmentlist.fragments[idx2].size == 0) break; 81 | if (fs.fragmentlist.fragments[idx2].id == CFragmentDesc::FREEID) break; 82 | int64_t hole = (fs.fragmentlist.fragments[idx2].ofs - nextofs)*fs.bio->blocksize; 83 | if (hole < 0) 84 | { 85 | fprintf(stderr, "Error in CheckFS: fragment overlap detected"); 86 | exit(1); 87 | } 88 | } 89 | 90 | printf("Check for different types in fragments\n"); 91 | std::map mapping; 92 | for(unsigned int i=0; isecond != fs.fragmentlist.fragments[i].type) 100 | { 101 | printf("Fragment %i Type mismatch for node id=%i: type %i vs %i\n", i, id, (int)it->second, (int)fs.fragmentlist.fragments[i].type); 102 | } 103 | } else 104 | { 105 | mapping[id] = fs.fragmentlist.fragments[i].type; 106 | } 107 | } 108 | 109 | printf("Receive List of all directories\n"); 110 | std::map direntries; 111 | GetRecursiveDirectories(direntries, 0, ""); 112 | } 113 | 114 | void CPrintCheckRepair::PrintInfo() 115 | { 116 | fs.fragmentlist.SortOffsets(); 117 | 118 | std::set s; 119 | std::map types; 120 | int64_t size=0; 121 | uint64_t lastfreeblock = 0; 122 | for (auto &fragment : fs.fragmentlist.fragments) { 123 | int32_t id = fragment.id; 124 | if (id >= 0) 125 | { 126 | size += fragment.size; 127 | if (lastfreeblock < fragment.GetNextFreeBlock(fs.bio->blocksize)) 128 | lastfreeblock = fragment.GetNextFreeBlock(fs.bio->blocksize); 129 | s.insert(id); 130 | types[fragment.type]++; 131 | } 132 | } 133 | printf("number of inodes: %zu\n", s.size()); 134 | printf("stored bytes: %lli\n", (long long int)size); 135 | printf("container usage: %f %%\n", (double)size/(double)fs.bio->GetFilesize()*100.); 136 | printf("last free block: %lli\n", (long long int)lastfreeblock); 137 | printf("empty space at end: %lli Bytes\n", (long long int)(fs.bio->GetFilesize()-lastfreeblock*fs.bio->blocksize)); 138 | 139 | printf("directory fragments: %i\n", types[INODETYPE::dir]); 140 | printf(" file fragments: %i\n", types[INODETYPE::file]); 141 | 142 | printf("Fragmentation:\n"); 143 | 144 | int frags[8] = {0}; 145 | for(auto f : s) 146 | { 147 | int nfragments = 0; 148 | for (auto &fragment : fs.fragmentlist.fragments) { 149 | if (fragment.id == f) nfragments++; 150 | } 151 | int idx = 0; 152 | if (nfragments > 20) idx = 7; else 153 | if (nfragments > 10) idx = 6; else 154 | if (nfragments > 5) idx = 5; else 155 | if (nfragments > 4) idx = 4; else 156 | if (nfragments > 3) idx = 3; else 157 | if (nfragments > 2) idx = 2; else 158 | if (nfragments > 1) idx = 1; else 159 | if (nfragments > 0) idx = 0; 160 | frags[idx]++; 161 | } 162 | 163 | printf(" inodes with 1 fragment : %4i\n", frags[0]); 164 | printf(" inodes with 2 fragments: %4i\n", frags[1]); 165 | printf(" inodes with 3 fragments: %4i\n", frags[2]); 166 | printf(" inodes with 4 fragments: %4i\n", frags[3]); 167 | printf(" inodes with 5 fragments: %4i\n", frags[4]); 168 | printf(" inodes with >5 fragments: %4i\n", frags[5]); 169 | printf(" inodes with >10 fragments: %4i\n", frags[6]); 170 | printf(" inodes with >20 fragments: %4i\n", frags[7]); 171 | } 172 | 173 | -------------------------------------------------------------------------------- /src/FS/SimpleFS/CPrintCheckRepair.h: -------------------------------------------------------------------------------- 1 | #ifndef CPRINTCHECKREPAIR_H 2 | #define CPRINTCHECKREPAIR_H 3 | 4 | #include"CSimpleFS.h" 5 | 6 | class CPrintCheckRepair 7 | { 8 | private: 9 | CSimpleFilesystem &fs; 10 | void GetRecursiveDirectories(std::map &direntries, int id, const std::string &path); 11 | 12 | public: 13 | explicit CPrintCheckRepair(CSimpleFilesystem &_fs) : fs(_fs) {}; 14 | 15 | void PrintFragments(); 16 | void Check(); 17 | void PrintInfo(); 18 | 19 | }; 20 | 21 | #endif 22 | 23 | -------------------------------------------------------------------------------- /src/FS/SimpleFS/CSimpleFS.h: -------------------------------------------------------------------------------- 1 | #ifndef CSIMPLEFS_H 2 | #define CSIMPLEFS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include"../IO/CCacheIO.h" 13 | #include"CFragment.h" 14 | 15 | #include"../CFilesystem.h" 16 | 17 | #include"CSimpleFSDirectory.h" 18 | 19 | // ---------------------------------------------------------- 20 | 21 | class CSimpleFilesystem : public CFilesystem 22 | { 23 | friend class CSimpleFSDirectory; 24 | friend class CSimpleFSInode; 25 | friend class CPrintCheckRepair; 26 | 27 | public: 28 | explicit CSimpleFilesystem(const std::shared_ptr &_bio); 29 | ~CSimpleFilesystem(); 30 | 31 | CInodePtr OpenNode(const CPath &path) override; 32 | CInodePtr OpenNode(int id) override; 33 | 34 | CDirectoryPtr OpenDir(const CPath &path) override; 35 | CDirectoryPtr OpenDir(int id) override; 36 | 37 | CInodePtr OpenFile(const CPath &path) override; 38 | CInodePtr OpenFile(int id) override; 39 | 40 | void Rename(const CPath &path, CDirectoryPtr newdir, const std::string &filename) override; 41 | void Unlink(const CPath &path) override; 42 | void StatFS(CStatFS *buf) override; 43 | 44 | void PrintInfo() override; 45 | void PrintFragments() override; 46 | void Check() override; 47 | 48 | void CreateFS(); 49 | 50 | int64_t GetNInodes(); 51 | 52 | private: 53 | 54 | CSimpleFSInodePtr OpenNodeInternal(int id); 55 | CSimpleFSInodePtr OpenNodeInternal(const CPath &path); 56 | 57 | CSimpleFSDirectoryPtr OpenDirInternal(int id); 58 | 59 | int MakeDirectory(CSimpleFSDirectory& dir, const std::string& name); 60 | int MakeFile(CSimpleFSDirectory& dir, const std::string& name); 61 | 62 | int64_t Read(CSimpleFSInode &node, int8_t *d, int64_t ofs, int64_t size); 63 | void Write(CSimpleFSInode &node, const int8_t *d, int64_t ofs, int64_t size); 64 | void Truncate(CSimpleFSInode &node, int64_t size, bool dozero); 65 | 66 | void GrowNode(CSimpleFSInode &node, int64_t size); 67 | void ShrinkNode(CSimpleFSInode &node, int64_t size); 68 | 69 | int CreateNode(CSimpleFSDirectory &dir, const std::string &name, INODETYPE ); 70 | INODETYPE GetType(int id); 71 | 72 | void MaybeRemove(CSimpleFSInode &node); 73 | 74 | std::shared_ptr bio; 75 | 76 | std::mutex inodescachemtx; 77 | 78 | CFragmentList fragmentlist; 79 | 80 | std::map inodes; 81 | 82 | // Statistics 83 | std::atomic nopendir; 84 | std::atomic nopenfiles; 85 | std::atomic ncreatedir; 86 | std::atomic ncreatefiles; 87 | std::atomic nread; 88 | std::atomic nwritten; 89 | std::atomic nrenamed; 90 | std::atomic nremoved; 91 | std::atomic nunlinked; 92 | std::atomic ntruncated; 93 | }; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/FS/SimpleFS/CSimpleFSDirectory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Logger.h" 4 | #include "CSimpleFS.h" 5 | #include "CSimpleFSDirectory.h" 6 | 7 | CSimpleFSDirectory::CSimpleFSDirectory(CSimpleFSInodePtr node, CSimpleFilesystem &_fs) : dirnode(node), fs(_fs) 8 | { 9 | blocksize = fs.bio->blocksize; 10 | std::lock_guard lock(dirnode->GetMutex()); 11 | if (node->type != INODETYPE::dir) throw ENOTDIR; 12 | } 13 | 14 | CDirectoryIteratorPtr CSimpleFSDirectory::GetIterator() 15 | { 16 | return std::make_unique(GetInternalIterator()); 17 | } 18 | 19 | CSimpleFSInternalDirectoryIteratorPtr CSimpleFSDirectory::GetInternalIterator() { 20 | return std::make_unique(*this); 21 | } 22 | 23 | void CSimpleFSDirectory::CreateEmptyBlock(int8_t* _buf) 24 | { 25 | int ndirperblock = blocksize/sizeof(CDirectoryEntryOnDisk); 26 | CDirectoryEntryOnDisk* buf = (CDirectoryEntryOnDisk*)_buf; 27 | memset(buf, 0, blocksize); 28 | for (int i = 0; iWrite(buf, 0, blocksize); 39 | } 40 | 41 | int CSimpleFSDirectory::MakeDirectory(const std::string& name) 42 | { 43 | CDirectoryEntryOnDisk e(""); 44 | Find(name, e); 45 | if (e.id != CFragmentDesc::INVALIDID) throw EEXIST; 46 | return fs.MakeDirectory(*this, name); 47 | } 48 | 49 | int CSimpleFSDirectory::MakeFile(const std::string& name) 50 | { 51 | CDirectoryEntryOnDisk e(""); 52 | Find(name, e); 53 | if (e.id != CFragmentDesc::INVALIDID) throw EEXIST; 54 | return fs.MakeFile(*this, name); 55 | } 56 | 57 | void CSimpleFSDirectory::AddEntry(const CDirectoryEntryOnDisk &denew) 58 | { 59 | LOG(LogLevel::DEEP) << "AddDirEntry '" << denew.name << "' id=" << denew.id; 60 | 61 | std::lock_guard lock(dirnode->GetMutex()); 62 | 63 | CSimpleFSInternalDirectoryIteratorPtr iterator = GetInternalIterator(); 64 | while(iterator->HasNext()) 65 | { 66 | uint64_t offset = iterator->GetOffset(); 67 | CDirectoryEntryOnDisk de = iterator->Next(); 68 | if (de.id == CFragmentDesc::INVALIDID) 69 | { 70 | //memcpy(&de, &denew, sizeof(CDirectoryEntryOnDisk)); 71 | dirnode->WriteInternal((int8_t*)&denew, offset, sizeof(CDirectoryEntryOnDisk)); 72 | return; 73 | } 74 | } 75 | int8_t buf[blocksize]; 76 | CreateEmptyBlock(buf); 77 | auto *de = (CDirectoryEntryOnDisk*)buf; 78 | memcpy(de, &denew, sizeof(CDirectoryEntryOnDisk)); 79 | dirnode->WriteInternal(buf, dirnode->size, blocksize); 80 | } 81 | 82 | void CSimpleFSDirectory::RemoveEntry(const std::string &name, CDirectoryEntryOnDisk &e) 83 | { 84 | e.id = CFragmentDesc::INVALIDID; 85 | LOG(LogLevel::DEEP) << "RemoveDirEntry '" << name << "' in dir '" << dirnode->name << "'"; 86 | 87 | std::lock_guard lock(dirnode->GetMutex()); 88 | 89 | CSimpleFSInternalDirectoryIteratorPtr iterator = GetInternalIterator(); 90 | while(iterator->HasNext()) { 91 | uint64_t offset = iterator->GetOffset(); 92 | CDirectoryEntryOnDisk de = iterator->Next(); 93 | 94 | if (de.id == CFragmentDesc::INVALIDID) continue; 95 | if (strncmp(de.name, name.c_str(), 64+32) == 0) 96 | { 97 | memcpy(&e, &de, sizeof(CDirectoryEntryOnDisk)); 98 | de.id = CFragmentDesc::INVALIDID; 99 | dirnode->WriteInternal((int8_t*)&de, offset, sizeof(CDirectoryEntryOnDisk)); 100 | return; 101 | } 102 | }; 103 | } 104 | 105 | void CSimpleFSDirectory::Find(const std::string &s, CDirectoryEntryOnDisk &e) 106 | { 107 | std::lock_guard lock(dirnode->GetMutex()); 108 | e.id = CFragmentDesc::INVALIDID; 109 | CSimpleFSInternalDirectoryIteratorPtr iterator = GetInternalIterator(); 110 | while(iterator->HasNext()) 111 | { 112 | CDirectoryEntryOnDisk de = iterator->Next(); 113 | if (de.id != CFragmentDesc::INVALIDID) 114 | { 115 | if (strncmp(de.name, s.c_str(), 64+32) == 0) 116 | { 117 | memcpy(&e, &de, sizeof(CDirectoryEntryOnDisk)); 118 | return; 119 | } 120 | } 121 | 122 | } 123 | } 124 | 125 | bool CSimpleFSDirectory::IsEmpty() 126 | { 127 | CSimpleFSInternalDirectoryIteratorPtr iterator = GetInternalIterator(); 128 | while(iterator->HasNext()) 129 | { 130 | if (iterator->Next().id != CFragmentDesc::INVALIDID) return false; 131 | } 132 | return true; 133 | } 134 | 135 | void CSimpleFSDirectory::List() 136 | { 137 | printf(" Listing of id=%i, name='%s', with size=%lli\n", dirnode->id, dirnode->name.c_str(), (long long int)dirnode->size); 138 | int n = -1; 139 | //const char *typestr[] = {"UNK", "DIR", "FILE"}; 140 | 141 | CSimpleFSInternalDirectoryIteratorPtr iterator = GetInternalIterator(); 142 | while(iterator->HasNext()) { 143 | CDirectoryEntryOnDisk de = iterator->Next(); 144 | n++; 145 | if (de.id == CFragmentDesc::INVALIDID) continue; 146 | printf(" %3i: %7i '%s'\n", n, de.id, de.name); 147 | } 148 | } 149 | 150 | int32_t CSimpleFSDirectory::GetId() 151 | { 152 | return dirnode->GetId(); 153 | } 154 | 155 | // ----------------------------------------------------------------- 156 | 157 | CSimpleFSDirectoryIterator::CSimpleFSDirectoryIterator(CSimpleFSInternalDirectoryIteratorPtr &&_iterator) 158 | : iterator(std::move(_iterator)), lock(iterator->GetDirectory().dirnode->GetMutex()) 159 | {}; 160 | 161 | bool CSimpleFSDirectoryIterator::HasNext() 162 | { 163 | while(iterator->HasNext()) 164 | { 165 | CDirectoryEntryOnDisk deondisk = iterator->Next(); 166 | if (deondisk.id == CFragmentDesc::INVALIDID) continue; 167 | de.name = std::string(deondisk.name); 168 | de.id = deondisk.id; 169 | return true; 170 | 171 | } 172 | return false; 173 | } 174 | 175 | CDirectoryEntry CSimpleFSDirectoryIterator::Next() 176 | { 177 | return de; 178 | } 179 | 180 | // ----------------------------------------------------------------- 181 | 182 | CSimpleFSInternalDirectoryIterator::CSimpleFSInternalDirectoryIterator(CSimpleFSDirectory &_directory) : directory(_directory) 183 | { 184 | buf.assign(_directory.blocksize, 0); 185 | ofs = 0; 186 | nentriesperblock = _directory.blocksize/sizeof(CDirectoryEntryOnDisk); 187 | GetNextBlock(); 188 | }; 189 | 190 | bool CSimpleFSInternalDirectoryIterator::HasNext() 191 | { 192 | return (size != 0); 193 | } 194 | 195 | 196 | 197 | CDirectoryEntryOnDisk CSimpleFSInternalDirectoryIterator::Next() 198 | { 199 | CDirectoryEntryOnDisk de; 200 | memcpy(&de, &buf[idx*sizeof(CDirectoryEntryOnDisk)], sizeof(CDirectoryEntryOnDisk)); 201 | idx++; 202 | if (idx >= nentriesperblock) GetNextBlock(); 203 | return de; 204 | } 205 | 206 | void CSimpleFSInternalDirectoryIterator::GetNextBlock() 207 | { 208 | size = directory.dirnode->ReadInternal(&buf[0], ofs, directory.blocksize); 209 | assert((size==directory.blocksize) || (size == 0)); 210 | ofs += size; 211 | idx = 0; 212 | } 213 | 214 | uint64_t CSimpleFSInternalDirectoryIterator::GetOffset() 215 | { 216 | return ofs - size + idx * sizeof(CDirectoryEntryOnDisk); 217 | } 218 | 219 | CSimpleFSDirectory& CSimpleFSInternalDirectoryIterator::GetDirectory() 220 | { 221 | return directory; 222 | } -------------------------------------------------------------------------------- /src/FS/SimpleFS/CSimpleFSDirectory.h: -------------------------------------------------------------------------------- 1 | #ifndef CDIRECTORY_H 2 | #define CDIRECTORY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include"../CFilesystem.h" 11 | #include"CFragment.h" 12 | 13 | class CPrintCheckRepair; 14 | class CSimpleFSDirectory; 15 | 16 | // TODO This shouldn't be public, but inside the .cpp file 17 | class CDirectoryEntryOnDisk { 18 | public: 19 | explicit CDirectoryEntryOnDisk(const std::string &_name="", int32_t _id=CFragmentDesc::INVALIDID) : id(_id) 20 | { 21 | memset(name, 0, 64+32); 22 | memset(dummy, 0, 16+8); 23 | _name.copy(name, sizeof name); 24 | } 25 | 26 | char name[64+32]{}; 27 | char dummy[16+12]{}; 28 | int32_t id; 29 | }; 30 | 31 | class CSimpleFSInternalDirectoryIterator 32 | { 33 | 34 | public: 35 | explicit CSimpleFSInternalDirectoryIterator(CSimpleFSDirectory &_directory); 36 | 37 | bool HasNext(); 38 | CDirectoryEntryOnDisk Next(); 39 | uint64_t GetOffset(); 40 | CSimpleFSDirectory& GetDirectory(); 41 | 42 | private: 43 | CSimpleFSDirectory &directory; 44 | 45 | void GetNextBlock(); 46 | 47 | std::vector buf; 48 | uint64_t ofs = 0; 49 | int64_t size = 0; 50 | uint64_t idx = 0; 51 | uint64_t nentriesperblock = 0; 52 | }; 53 | using CSimpleFSInternalDirectoryIteratorPtr = std::unique_ptr; 54 | 55 | 56 | class CSimpleFSDirectoryIterator : public CDirectoryIterator 57 | { 58 | public: 59 | 60 | explicit CSimpleFSDirectoryIterator(CSimpleFSInternalDirectoryIteratorPtr &&iterator); 61 | 62 | bool HasNext() override; 63 | CDirectoryEntry Next() override; 64 | 65 | private: 66 | CSimpleFSInternalDirectoryIteratorPtr iterator; 67 | std::lock_guard lock; 68 | CDirectoryEntry de; 69 | }; 70 | 71 | 72 | class CSimpleFSDirectory : public CDirectory 73 | { 74 | friend CSimpleFilesystem; 75 | friend CPrintCheckRepair; 76 | friend CSimpleFSInternalDirectoryIterator; 77 | friend CSimpleFSDirectoryIterator; 78 | 79 | public: 80 | CSimpleFSDirectory(CSimpleFSInodePtr node, CSimpleFilesystem &_fs); 81 | 82 | CDirectoryIteratorPtr GetIterator() override; 83 | CSimpleFSInternalDirectoryIteratorPtr GetInternalIterator(); 84 | 85 | int MakeDirectory(const std::string& name) override; 86 | int MakeFile(const std::string& name) override; 87 | 88 | int32_t GetId() override; 89 | bool IsEmpty() override; 90 | void CreateEmptyBlock(int8_t* buf); 91 | 92 | private: 93 | void Find(const std::string &s, CDirectoryEntryOnDisk &e); 94 | void RemoveEntry(const std::string &name, CDirectoryEntryOnDisk &e); 95 | void AddEntry(const CDirectoryEntryOnDisk &de); 96 | void Create(); 97 | 98 | int GetID() {return dirnode->id;} 99 | void List(); 100 | 101 | CSimpleFSInodePtr dirnode; 102 | CSimpleFilesystem &fs; 103 | int blocksize; 104 | }; 105 | using CSimpleFSDirectoryPtr = std::shared_ptr; 106 | 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /src/FS/SimpleFS/CSimpleFSInode.cpp: -------------------------------------------------------------------------------- 1 | #include "CSimpleFS.h" 2 | #include "CSimpleFSInode.h" 3 | 4 | CSimpleFSInode::~CSimpleFSInode() { 5 | fs.MaybeRemove(*this); 6 | } 7 | 8 | int64_t CSimpleFSInode::Read(int8_t *d, int64_t ofs, int64_t size) 9 | { 10 | std::lock_guard lock(mtx); 11 | return fs.Read(*this, d, ofs, size); 12 | } 13 | 14 | void CSimpleFSInode::Write(const int8_t *d, int64_t ofs, int64_t size) 15 | { 16 | std::lock_guard lock(mtx); 17 | fs.Write(*this, d, ofs, size); 18 | } 19 | 20 | void CSimpleFSInode::Truncate(int64_t size, bool dozero) 21 | { 22 | std::lock_guard lock(mtx); 23 | fs.Truncate(*this, size, dozero); 24 | } 25 | 26 | // non-blocking read and write 27 | void CSimpleFSInode::WriteInternal(const int8_t *d, int64_t ofs, int64_t size) 28 | { 29 | fs.Write(*this, d, ofs, size); 30 | } 31 | 32 | int64_t CSimpleFSInode::ReadInternal(int8_t *d, int64_t ofs, int64_t size) 33 | { 34 | return fs.Read(*this, d, ofs, size); 35 | } 36 | 37 | int64_t CSimpleFSInode::GetSize() 38 | { 39 | std::lock_guard lock(mtx); 40 | return size; 41 | } 42 | 43 | INODETYPE CSimpleFSInode::GetType() 44 | { 45 | std::lock_guard lock(mtx); 46 | return type; 47 | } 48 | 49 | int32_t CSimpleFSInode::GetId() 50 | { 51 | std::lock_guard lock(mtx); 52 | return id; 53 | } 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/FS/SimpleFS/CSimpleFSInode.h: -------------------------------------------------------------------------------- 1 | #ifndef INODE_H 2 | #define INODE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include"../CFilesystem.h" 10 | 11 | class CSimpleFilesystem; 12 | 13 | class CSimpleFSInode : public CInode 14 | { 15 | friend class CSimpleFSDirectory; 16 | friend class CSimpleFSInternalDirectoryIterator; 17 | friend class CSimpleFSDirectoryIterator; 18 | friend class CSimpleFilesystem; 19 | 20 | public: 21 | explicit CSimpleFSInode(CSimpleFilesystem &_fs) : id(-4), parentid(-4), size(0), nlinks(1), type(INODETYPE::undefined), fs(_fs) {} 22 | 23 | virtual ~CSimpleFSInode(); 24 | 25 | int64_t Read(int8_t *d, int64_t ofs, int64_t size) override; 26 | void Write(const int8_t *d, int64_t ofs, int64_t size) override; 27 | void Truncate(int64_t size, bool dozero) override; 28 | 29 | int64_t GetSize() override; 30 | INODETYPE GetType() override; 31 | int32_t GetId() override; 32 | 33 | private: 34 | 35 | std::mutex& GetMutex() { return mtx; } // for lock_guard 36 | 37 | // non-blocking read and write 38 | int64_t ReadInternal(int8_t *d, int64_t ofs, int64_t size); 39 | void WriteInternal(const int8_t *d, int64_t ofs, int64_t size); 40 | 41 | int32_t id; 42 | int32_t parentid; 43 | int64_t size; 44 | std::atomic nlinks; 45 | INODETYPE type; 46 | std::string name; 47 | std::vector fragments; 48 | 49 | std::mutex mtx; 50 | CSimpleFilesystem &fs; 51 | 52 | }; 53 | using CSimpleFSInodePtr = std::shared_ptr; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/IO/CBlockIO.cpp: -------------------------------------------------------------------------------- 1 | #include "CBlockIO.h" 2 | #include 3 | 4 | CAbstractBlockIO::CAbstractBlockIO(int _blocksize) : blocksize(_blocksize) {} 5 | int64_t CAbstractBlockIO::GetWriteCache() { return 0; } 6 | 7 | // ----------------------------------------------------------------- 8 | 9 | CRAMBlockIO::CRAMBlockIO(int _blocksize) : CAbstractBlockIO(_blocksize) 10 | { 11 | data.assign(blocksize*3, 0xFF); 12 | } 13 | 14 | int64_t CRAMBlockIO::GetFilesize() 15 | { 16 | std::lock_guard lock(mutex); 17 | return data.size(); 18 | } 19 | 20 | 21 | void CRAMBlockIO::Read(const int blockidx, const int n, int8_t *d) 22 | { 23 | uint64_t newsize = (blockidx+n)*blocksize; 24 | std::lock_guard lock(mutex); 25 | if (newsize > data.size()) 26 | { 27 | data.resize((newsize*3)/2, 0xFF); 28 | } 29 | memcpy(d, &data[blockidx*blocksize], n*blocksize); 30 | } 31 | 32 | void CRAMBlockIO::Write(const int blockidx, const int n, int8_t* d) 33 | { 34 | uint64_t newsize = (blockidx+n)*blocksize; 35 | std::lock_guard lock(mutex); 36 | if (newsize > data.size()) 37 | { 38 | data.resize((newsize*3)/2, 0xFF); 39 | } 40 | memcpy(&data[blockidx*blocksize], d, n*blocksize); 41 | } 42 | -------------------------------------------------------------------------------- /src/IO/CBlockIO.h: -------------------------------------------------------------------------------- 1 | #ifndef CBLOCKIO_H 2 | #define CBLOCKIO_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | class CAbstractBlockIO; 12 | 13 | class CAbstractBlockIO 14 | { 15 | public: 16 | explicit CAbstractBlockIO(int _blocksize); 17 | virtual void Read(int blockidx, int n, int8_t* d) = 0; 18 | virtual void Write(int blockidx, int n, int8_t* d) = 0; 19 | virtual int64_t GetFilesize() = 0; 20 | virtual int64_t GetWriteCache(); 21 | 22 | public: 23 | unsigned int blocksize; 24 | }; 25 | 26 | 27 | class CRAMBlockIO : public CAbstractBlockIO 28 | { 29 | public: 30 | explicit CRAMBlockIO(int _blocksize); 31 | void Read(int blockidx, int n, int8_t* d) override; 32 | void Write(int blockidx, int n, int8_t* d) override; 33 | int64_t GetFilesize() override; 34 | 35 | private: 36 | std::vector data; 37 | std::mutex mutex; 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/IO/CCacheIO.cpp: -------------------------------------------------------------------------------- 1 | #include"Logger.h" 2 | #include "CCacheIO.h" 3 | #include 4 | 5 | // ----------------------------------------------------------------- 6 | 7 | CBlock::CBlock(CCacheIO &_cio, CEncrypt &_enc, int _blockidx, int size) : nextdirtyidx(-1), blockidx(_blockidx), cio(_cio), enc(_enc), buf(size), count(0) 8 | {} 9 | 10 | int8_t* CBlock::GetBufRead() 11 | { 12 | mutex.lock(); 13 | count++; 14 | if (cio.cryptcache) 15 | enc.Decrypt(blockidx, &buf[0]); 16 | return &buf[0]; 17 | } 18 | 19 | int8_t* CBlock::GetBufReadWrite() 20 | { 21 | int8_t* buf = GetBufRead(); 22 | if (nextdirtyidx == -1) 23 | { 24 | nextdirtyidx = cio.lastdirtyidx.exchange(blockidx, std::memory_order_relaxed); 25 | cio.ndirty++; 26 | } 27 | return buf; 28 | } 29 | 30 | int8_t* CBlock::GetBufUnsafe() 31 | { 32 | return &buf[0]; 33 | } 34 | 35 | 36 | void CBlock::ReleaseBuf() 37 | { 38 | if (cio.cryptcache) 39 | enc.Encrypt(blockidx, &buf[0]); 40 | mutex.unlock(); 41 | } 42 | 43 | // ----------------------------------------------------------------- 44 | 45 | CCacheIO::CCacheIO(const std::shared_ptr &_bio, CEncrypt &_enc, bool _cryptcache) : 46 | bio(_bio), enc(_enc), ndirty(0), lastdirtyidx(-1), terminatesyncthread(false), cryptcache(_cryptcache) 47 | { 48 | blocksize = bio->blocksize; 49 | syncthread = std::thread(&CCacheIO::Async_Sync, this); 50 | } 51 | 52 | CCacheIO::~CCacheIO() 53 | { 54 | LOG(LogLevel::DEBUG) << "Cache: destruct"; 55 | terminatesyncthread.store(true); 56 | Sync(); 57 | syncthread.join(); 58 | assert(ndirty.load() == 0); 59 | LOG(LogLevel::DEBUG) << "All Blocks stored. Erase cache ..."; 60 | 61 | cachemtx.lock(); 62 | for(auto iter = cache.begin(); iter != cache.end();) 63 | { 64 | CBLOCKPTR block = iter->second; 65 | if (block.use_count() != 2) 66 | { 67 | LOG(LogLevel::WARN) << "Block " << block->blockidx << " still in use."; 68 | iter++; 69 | continue; 70 | } 71 | if (!block->mutex.try_lock()) 72 | { 73 | LOG(LogLevel::WARN) << "Locking block " << block->blockidx << " failed."; 74 | iter++; 75 | continue; 76 | } 77 | iter = cache.erase(iter); 78 | block->mutex.unlock(); 79 | } 80 | LOG(LogLevel::DEBUG) << "Cache erased"; 81 | 82 | if (!cache.empty()) 83 | { 84 | LOG(LogLevel::WARN) << "Cache not empty"; 85 | } 86 | cachemtx.unlock(); 87 | } 88 | 89 | CBLOCKPTR CCacheIO::GetBlock(const int blockidx, bool read) 90 | { 91 | cachemtx.lock(); 92 | auto cacheblock = cache.find(blockidx); 93 | if (cacheblock != cache.end()) 94 | { 95 | cachemtx.unlock(); 96 | return cacheblock->second; 97 | } 98 | CBLOCKPTR block(new CBlock(*this, enc, blockidx, blocksize)); 99 | cache[blockidx] = block; 100 | block->mutex.lock(); 101 | cachemtx.unlock(); 102 | if (read) 103 | { 104 | bio->Read(blockidx, 1, block->GetBufUnsafe()); 105 | if (!cryptcache) 106 | enc.Decrypt(blockidx, block->GetBufUnsafe()); 107 | } 108 | block->mutex.unlock(); 109 | 110 | return block; 111 | } 112 | 113 | void CCacheIO::BlockReadForce(const int blockidx, const int n) 114 | { 115 | if (n <= 0) return; 116 | auto *buf = new int8_t[blocksize*n]; 117 | bio->Read(blockidx, n, buf); 118 | cachemtx.lock(); 119 | for(int i=0; isecond; 124 | memcpy(block->GetBufUnsafe(), &buf[i*blocksize], blocksize); 125 | if (!cryptcache) 126 | enc.Decrypt(blockidx+i, block->GetBufUnsafe()); 127 | block->mutex.unlock(); 128 | } 129 | cachemtx.unlock(); 130 | delete[] buf; 131 | } 132 | 133 | void CCacheIO::CacheBlocks(const int blockidx, const int n) 134 | { 135 | if (n <= 0) return; 136 | cachemtx.lock(); 137 | int istart = 0; 138 | for(int i=0; imutex.lock(); 153 | } 154 | } 155 | int npart = n-istart; 156 | cachemtx.unlock(); 157 | BlockReadForce(blockidx+istart, npart); 158 | } 159 | 160 | int64_t CCacheIO::GetFilesize() 161 | { 162 | return bio->GetFilesize(); 163 | } 164 | 165 | int64_t CCacheIO::GetNDirty() 166 | { 167 | return ndirty.load(); 168 | } 169 | 170 | int64_t CCacheIO::GetNCachedBlocks() 171 | { 172 | cachemtx.lock(); 173 | int64_t n = cache.size(); 174 | cachemtx.unlock(); 175 | return n; 176 | } 177 | 178 | 179 | void CCacheIO::Async_Sync() 180 | { 181 | int8_t buf[blocksize]; 182 | for(;;) 183 | { 184 | while (ndirty.load() == 0) 185 | { 186 | if (terminatesyncthread.load()) return; 187 | std::unique_lock lock(async_sync_mutex); 188 | async_sync_cond.wait(lock); 189 | } 190 | 191 | int nextblockidx = lastdirtyidx.exchange(-1, std::memory_order_relaxed); 192 | while(nextblockidx != -1) 193 | { 194 | cachemtx.lock(); 195 | CBLOCKPTR block = cache.find(nextblockidx)->second; 196 | block->mutex.lock(); // TODO trylock and put back on the list 197 | cachemtx.unlock(); 198 | nextblockidx = block->nextdirtyidx; 199 | memcpy(buf, block->GetBufUnsafe(), blocksize); 200 | block->nextdirtyidx = -1; 201 | ndirty--; 202 | block->mutex.unlock(); 203 | 204 | if (!cryptcache) 205 | enc.Encrypt(block->blockidx, buf); 206 | bio->Write(block->blockidx, 1, buf); 207 | } 208 | } 209 | } 210 | 211 | 212 | void CCacheIO::Sync() 213 | { 214 | async_sync_cond.notify_one(); 215 | } 216 | 217 | // ----------------------------------------------------------------- 218 | 219 | void CCacheIO::Read(int64_t ofs, int64_t size, int8_t *d) 220 | { 221 | CBLOCKPTR block; 222 | int8_t *buf = nullptr; 223 | //printf("ReadFragment ofs=%li size=%li\n", ofs, size); 224 | if (size == 0) return; 225 | 226 | int firstblock = ofs/blocksize; 227 | int lastblock = (ofs+size-1)/blocksize; 228 | 229 | CacheBlocks(firstblock, lastblock-firstblock+1); 230 | 231 | int64_t dofs = 0; 232 | for(int64_t j=firstblock; j<=lastblock; j++) 233 | { 234 | //printf("GetBlock %li\n", j); 235 | block = GetBlock(j, true); 236 | //printf("GetBuf %li\n", j); 237 | buf = block->GetBufRead(); 238 | int bsize = blocksize - (ofs%blocksize); 239 | bsize = std::min((int64_t)bsize, size); 240 | memcpy(&d[dofs], &buf[ofs%blocksize], bsize); 241 | ofs += bsize; 242 | dofs += bsize; 243 | size -= bsize; 244 | block->ReleaseBuf(); 245 | } 246 | } 247 | 248 | void CCacheIO::Write(int64_t ofs, int64_t size, const int8_t *d) 249 | { 250 | CBLOCKPTR block; 251 | int8_t *buf = NULL; 252 | //printf("WriteFragment ofs=%li size=%li\n", ofs, size); 253 | if (size == 0) return; 254 | 255 | int firstblock = ofs/blocksize; 256 | int lastblock = (ofs+size-1)/blocksize; 257 | 258 | // check which blocks we have to read 259 | if ((ofs%blocksize) != 0) block = GetBlock(firstblock, true); 260 | if (((ofs+size-1)%blocksize) != 0) block = GetBlock(lastblock, true); 261 | 262 | int64_t dofs = 0; 263 | for(int64_t j=firstblock; j<=lastblock; j++) 264 | { 265 | block = GetBlock(j, false); 266 | buf = block->GetBufReadWrite(); 267 | int bsize = blocksize - (ofs%blocksize); 268 | bsize = std::min((int64_t)bsize, size); 269 | memcpy(&buf[ofs%blocksize], &d[dofs], bsize); 270 | ofs += bsize; 271 | dofs += bsize; 272 | size -= bsize; 273 | block->ReleaseBuf(); 274 | } 275 | Sync(); 276 | } 277 | 278 | void CCacheIO::Zero(int64_t ofs, int64_t size) 279 | { 280 | CBLOCKPTR block; 281 | int8_t *buf = nullptr; 282 | //printf("ZeroFragment ofs=%li size=%li\n", ofs, size); 283 | if (size == 0) return; 284 | 285 | int firstblock = ofs/blocksize; 286 | int lastblock = (ofs+size-1)/blocksize; 287 | 288 | // check which blocks we have to read 289 | if ((ofs%blocksize) != 0) block = GetBlock(firstblock, true); 290 | if (((ofs+size-1)%blocksize) != 0) block = GetBlock(lastblock, true); 291 | 292 | int64_t dofs = 0; 293 | for(int64_t j=firstblock; j<=lastblock; j++) 294 | { 295 | block = GetBlock(j, false); 296 | buf = block->GetBufReadWrite(); 297 | int bsize = blocksize - (ofs%blocksize); 298 | bsize = std::min((int64_t)bsize, size); 299 | memset(&buf[ofs%blocksize], 0, bsize); 300 | ofs += bsize; 301 | dofs += bsize; 302 | size -= bsize; 303 | block->ReleaseBuf(); 304 | } 305 | Sync(); 306 | } 307 | -------------------------------------------------------------------------------- /src/IO/CCacheIO.h: -------------------------------------------------------------------------------- 1 | #ifndef CCACHEIO_H 2 | #define CCACHEIO_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "CBlockIO.h" 12 | #include "CEncrypt.h" 13 | 14 | class CCacheIO; 15 | 16 | class CBlock 17 | { 18 | friend class CCacheIO; 19 | public: 20 | CBlock(CCacheIO &_bio, CEncrypt &_enc, int _blockidx, int size); 21 | int8_t* GetBufRead(); 22 | int8_t* GetBufReadWrite(); 23 | int8_t* GetBufUnsafe(); 24 | void ReleaseBuf(); 25 | 26 | 27 | private: 28 | int nextdirtyidx; 29 | int blockidx; 30 | std::mutex mutex; 31 | CCacheIO &cio; 32 | CEncrypt &enc; 33 | std::vector buf; 34 | uint32_t count; 35 | }; 36 | 37 | using CBLOCKPTR = std::shared_ptr; 38 | 39 | class CCacheIO 40 | { 41 | friend class CBlock; 42 | 43 | public: 44 | CCacheIO(const std::shared_ptr &bio, CEncrypt &_enc, bool _cryptcache); 45 | ~CCacheIO(); 46 | 47 | void Read(int64_t ofs, int64_t size, int8_t *d); 48 | void Write(int64_t ofs, int64_t size, const int8_t *d); 49 | void Zero(int64_t ofs, int64_t size); 50 | 51 | CBLOCKPTR GetBlock(int blockidx, bool read=true); 52 | //CBLOCKPTR GetWriteBlock(int blockidx); 53 | void CacheBlocks(int blockidx, int n); 54 | 55 | int64_t GetFilesize(); 56 | int64_t GetNDirty(); 57 | int64_t GetNCachedBlocks(); 58 | void Sync(); 59 | 60 | int blocksize; 61 | 62 | private: 63 | void Async_Sync(); 64 | void BlockReadForce(int blockidx, int n); 65 | std::shared_ptr bio; 66 | 67 | CEncrypt &enc; 68 | std::map cache; 69 | std::mutex cachemtx; 70 | std::atomic ndirty; 71 | std::atomic lastdirtyidx; 72 | 73 | std::thread syncthread; 74 | std::atomic terminatesyncthread; 75 | std::mutex async_sync_mutex; 76 | std::condition_variable async_sync_cond; 77 | 78 | bool cryptcache; 79 | }; 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /src/IO/CEncrypt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | GCRY_THREAD_OPTION_PTHREAD_IMPL; 6 | 7 | #include "Logger.h" 8 | #include "CEncrypt.h" 9 | 10 | //https://gnupg.org/documentation/manuals/gcrypt/Working-with-cipher-handles.html#Working-with-cipher-handles 11 | //https://gnupg.org/documentation/manuals/gcrypt/Key-Derivation.html#Key-Derivation 12 | 13 | typedef struct 14 | { 15 | int32_t crc; 16 | char magic[8]; 17 | uint16_t majorversion; 18 | uint16_t minorversion; 19 | uint8_t salt[32]; 20 | struct { 21 | char username[128]; 22 | uint8_t key[64]; 23 | uint8_t enccheckbytes[64]; 24 | uint8_t checkbytes[64]; 25 | int32_t hashreps; 26 | } user[4]; 27 | 28 | } TEncHeader; 29 | 30 | void GCryptCheckError(const char *function, gpg_error_t ret) 31 | { 32 | if (ret) 33 | { 34 | LOG(LogLevel::ERR) << function << ": Failure: " << gcry_strsource(ret) << "/" << gcry_strerror (ret); 35 | throw std::exception(); 36 | } 37 | } 38 | 39 | 40 | void CEncrypt::PassToHash(char *pass, uint8_t salt[32], uint8_t passkey[64], unsigned long hashreps) 41 | { 42 | gpg_error_t ret = gcry_kdf_derive( 43 | pass, strlen(pass), 44 | GCRY_KDF_SCRYPT, 45 | GCRY_MD_SHA256, 46 | salt, 32, 47 | hashreps, 48 | 64, passkey); 49 | GCryptCheckError("getpass", ret); 50 | } 51 | 52 | void CEncrypt::CreateEnc(int8_t *block, char *pass) 53 | { 54 | LOG(LogLevel::INFO) << "Create Encryption block"; 55 | uint8_t key[64]; 56 | gcry_randomize (key, 64, GCRY_STRONG_RANDOM); 57 | 58 | auto *h = (TEncHeader*)block; 59 | memset(h, 0, sizeof(blocksize)); 60 | h->majorversion = 1; 61 | h->minorversion = 0; 62 | strcpy(h->magic, "coverfs"); 63 | 64 | gcry_create_nonce (h->salt, 32); 65 | 66 | h->user[0].hashreps = 500; 67 | strcpy(h->user[0].username, "poke"); 68 | gcry_create_nonce (h->user[0].enccheckbytes, 64); 69 | 70 | uint8_t passkey[64]; 71 | PassToHash(pass, h->salt, passkey, static_cast(h->user[0].hashreps)); 72 | gpg_error_t ret; 73 | 74 | gcry_cipher_hd_t hd; 75 | ret = gcry_cipher_open(&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 0); 76 | GCryptCheckError("gcry_cipher_open", ret); 77 | ret = gcry_cipher_setkey(hd, passkey, 32); 78 | GCryptCheckError("gcry_cipher_setkey", ret); 79 | ret = gcry_cipher_encrypt (hd, 80 | h->user[0].checkbytes, 64, 81 | h->user[0].enccheckbytes, 64); 82 | GCryptCheckError("gcry_cipher_encrypt", ret); 83 | ret = gcry_cipher_encrypt (hd, h->user[0].key, 64, key, 64); 84 | GCryptCheckError("gcry_cipher_encrypt", ret); 85 | for (unsigned char &i : key) i = 0x0; 86 | gcry_cipher_close(hd); 87 | 88 | gcry_md_hash_buffer(GCRY_MD_CRC32, &h->crc, (int8_t*)h+4, blocksize-4); 89 | } 90 | 91 | CEncrypt::CEncrypt(CAbstractBlockIO &bio, char *pass) 92 | { 93 | static_assert(sizeof(TEncHeader) == 4+8+4+32+(128+64+64+64+4)*4, ""); 94 | assert(bio.blocksize >= 1024); 95 | blocksize = bio.blocksize; 96 | gpg_error_t ret; 97 | 98 | const char* gcryptversion = gcry_check_version (GCRYPT_VERSION); 99 | LOG(LogLevel::INFO) << "gcrypt version " << gcryptversion; 100 | if (gcryptversion == nullptr) 101 | { 102 | LOG(LogLevel::ERR) << "gcrypt version too old"; 103 | throw std::exception(); 104 | } 105 | ret = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); 106 | GCryptCheckError("gcry_control", ret); 107 | gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); 108 | 109 | assert(gcry_md_get_algo_dlen (GCRY_MD_CRC32) == 4); 110 | 111 | int8_t block[blocksize]; 112 | bio.Read(0, 1, block); 113 | auto *h = (TEncHeader*)block; 114 | if (strncmp(h->magic, "coverfs", 8) != 0) 115 | { 116 | CreateEnc(block, pass); 117 | bio.Write(0, 1, block); 118 | } 119 | 120 | int32_t crc; 121 | gcry_md_hash_buffer(GCRY_MD_CRC32, &crc, (int8_t*)h+4, blocksize-4); 122 | assert(h->crc == crc); 123 | assert(h->majorversion == 1); 124 | assert(h->minorversion == 0); 125 | 126 | uint8_t passkey[64]; 127 | PassToHash(pass, h->salt, passkey, static_cast(h->user[0].hashreps)); 128 | 129 | gcry_cipher_hd_t hd; 130 | ret = gcry_cipher_open(&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 0); 131 | GCryptCheckError("gcry_cipher_open", ret); 132 | ret = gcry_cipher_setkey(hd, passkey, 32); 133 | GCryptCheckError("gcry_cipher_setkey", ret); 134 | uint8_t check[64]; 135 | ret = gcry_cipher_encrypt(hd, check, 64, h->user[0].enccheckbytes, 64); 136 | GCryptCheckError("gcry_cipher_encrypt", ret); 137 | 138 | if (memcmp(check, h->user[0].checkbytes, 64) != 0) 139 | { 140 | LOG(LogLevel::ERR) << "Cannot decrypt filesystem. Did you type the right password?"; 141 | throw std::exception(); 142 | } 143 | uint8_t key[64]; 144 | ret = gcry_cipher_decrypt(hd, key, 64, h->user[0].key, 64); 145 | GCryptCheckError("gcry_cipher_decrypt", ret); 146 | gcry_cipher_close(hd); 147 | 148 | for (auto &i : hdblock) { 149 | ret = gcry_cipher_open(&i, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0); 150 | GCryptCheckError("gcry_cipher_open", ret); 151 | ret = gcry_cipher_setkey(i, key, 32); 152 | GCryptCheckError("gcry_cipher_setkey", ret); 153 | } 154 | 155 | memset(key, 0, 64); 156 | memset(block, 0, blocksize); 157 | } 158 | 159 | void CEncrypt::Decrypt(const int blockidx, int8_t *d) 160 | { 161 | //printf("Decrypt blockidx %i\n", blockidx); 162 | int32_t iv[4]; 163 | iv[0] = blockidx; iv[1] = 0; iv[2] = 0; iv[3] = 0; // I know this is bad 164 | 165 | if (blockidx == 0) return; 166 | 167 | for(int i=0; i<4; i++) 168 | { 169 | if (!mutex[i].try_lock()) continue; 170 | gcry_cipher_setiv (hdblock[i], iv, 16); 171 | gpg_error_t ret = gcry_cipher_decrypt(hdblock[i], d, blocksize, NULL, 0); 172 | GCryptCheckError("gcry_cipher_decrypt", ret); 173 | mutex[i].unlock(); 174 | return; 175 | } 176 | 177 | // all cipher handles are locked. Wait ... 178 | mutex[0].lock(); 179 | gcry_cipher_setiv (hdblock[0], iv, 16); 180 | gpg_error_t ret = gcry_cipher_decrypt(hdblock[0], d, blocksize, NULL, 0); 181 | GCryptCheckError("gcry_cipher_decrypt", ret); 182 | mutex[0].unlock(); 183 | } 184 | 185 | void CEncrypt::Encrypt(const int blockidx, int8_t* d) 186 | { 187 | //printf("Encrypt blockidx %i\n", blockidx); 188 | int32_t iv[4]; 189 | iv[0] = blockidx; iv[1] = 0; iv[2] = 0; iv[3] = 0; // I know, this is bad 190 | if (blockidx == 0) return; 191 | 192 | for(int i=0; i<4; i++) 193 | { 194 | if (!mutex[i].try_lock()) continue; 195 | gcry_cipher_setiv (hdblock[i], iv, 16); 196 | gpg_error_t ret = gcry_cipher_encrypt(hdblock[i], d, blocksize, 0, 0); 197 | GCryptCheckError("gcry_cipher_encrypt", ret); 198 | mutex[i].unlock(); 199 | return; 200 | } 201 | 202 | // all cipher handles are locked. Wait ... 203 | mutex[1].lock(); 204 | gcry_cipher_setiv (hdblock[1], iv, 16); 205 | gpg_error_t ret = gcry_cipher_encrypt(hdblock[1], d, blocksize, 0, 0); 206 | GCryptCheckError("gcry_cipher_encrypt", ret); 207 | mutex[1].unlock(); 208 | } 209 | -------------------------------------------------------------------------------- /src/IO/CEncrypt.h: -------------------------------------------------------------------------------- 1 | #ifndef CENCRYPT_H 2 | #define CENCRYPT_H 3 | 4 | #include 5 | 6 | #include 7 | #include "CBlockIO.h" 8 | 9 | class CEncrypt 10 | { 11 | public: 12 | CEncrypt(CAbstractBlockIO &_bio, char* pass); 13 | void PassToHash(char* pass, uint8_t salt[32], uint8_t passkey[32], unsigned long hashreps); 14 | void Decrypt(int blockidx, int8_t *d); 15 | void Encrypt(int blockidx, int8_t* d); 16 | void CreateEnc(int8_t* block, char *pass); 17 | 18 | private: 19 | int blocksize; 20 | gcry_cipher_hd_t hdblock[4]; // for multi-threading support we need several cipher handles 21 | std::mutex mutex[4]; 22 | }; 23 | 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/IO/CNetBlockIO.cpp: -------------------------------------------------------------------------------- 1 | #include"Logger.h" 2 | #include"CNetBlockIO.h" 3 | #include"CNetReadWriteBuffer.h" 4 | 5 | #include 6 | #include 7 | 8 | using boost::asio::ip::tcp; 9 | 10 | enum class COMMAND : int32_t {READ=0, WRITE=1, SIZE=2, CONTAINERINFO=3, CLOSE=4}; 11 | 12 | typedef struct 13 | { 14 | int32_t cmd; 15 | int32_t dummy; 16 | int64_t offset; 17 | int64_t length; 18 | int64_t data; 19 | } CommandDesc; 20 | 21 | template 22 | constexpr auto to_underlying(E e) noexcept 23 | { 24 | return static_cast>(e); 25 | } 26 | 27 | bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx) 28 | { 29 | // The verify callback can be used to check whether the certificate that is 30 | // being presented is valid for the peer. For example, RFC 2818 describes 31 | // the steps involved in doing this for HTTPS. Consult the OpenSSL 32 | // documentation for more details. Note that the callback is called once 33 | // for each certificate in the certificate chain, starting from the root 34 | // certificate authority. 35 | 36 | // In this example we will simply print the certificate's subject name. 37 | char subject_name[256]; 38 | X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); 39 | X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); 40 | LOG(LogLevel::INFO) << "Verifying certificate: " << subject_name; 41 | 42 | return preverified; 43 | } 44 | 45 | 46 | CNetBlockIO::CNetBlockIO(int _blocksize, const std::string &host, const std::string &port) 47 | : CAbstractBlockIO(_blocksize), 48 | ctx(io_service, ssl::context::sslv23), 49 | sctrl(io_service, ctx), 50 | sdata(io_service, ctx), 51 | cmdid(0) 52 | { 53 | static_assert(sizeof(CommandDesc) == 32, ""); 54 | LOG(LogLevel::INFO) << "Try to connect to " << host << ":" << port; 55 | 56 | ctx.set_verify_mode(boost::asio::ssl::context::verify_peer); 57 | try 58 | { 59 | ctx.load_verify_file("ssl/server.crt"); 60 | } catch(boost::system::system_error &e) 61 | { 62 | LOG(LogLevel::ERR) << "Error during loading or parsing of ssl/server.crt: " << e.what(); 63 | throw std::exception(); 64 | } 65 | 66 | sctrl.set_verify_mode(boost::asio::ssl::verify_peer); 67 | sctrl.set_verify_callback(verify_certificate); 68 | 69 | sdata.set_verify_mode(boost::asio::ssl::verify_peer); 70 | sdata.set_verify_callback(verify_certificate); 71 | 72 | tcp::resolver resolver(io_service); 73 | tcp::resolver::query q(host, port); 74 | boost::system::error_code ec; 75 | tcp::resolver::iterator iter = resolver.resolve(q, ec); 76 | if (ec) 77 | { 78 | LOG(LogLevel::ERR) << "Cannot resolve host"; 79 | throw std::exception(); 80 | } 81 | LOG(LogLevel::INFO) << "Connect to " << host; 82 | 83 | boost::asio::connect(sctrl.lowest_layer(), iter, ec); 84 | if (ec) 85 | { 86 | LOG(LogLevel::ERR) << "Cannot connect to server. (Control Stream)\n"; 87 | throw std::exception(); 88 | } 89 | sctrl.handshake(boost::asio::ssl::stream_base::client); 90 | 91 | boost::asio::connect(sdata.lowest_layer(), iter, ec); 92 | if (ec) 93 | { 94 | LOG(LogLevel::ERR) << "Cannot connect to server. (Data Stream)"; 95 | throw std::exception(); 96 | } 97 | sdata.handshake(boost::asio::ssl::stream_base::client); 98 | 99 | #ifdef __linux__ 100 | int priority = 6; 101 | int ret = setsockopt(sctrl.lowest_layer().native(), SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)); 102 | if (ret != 0) 103 | { 104 | LOG(LogLevel::WARN) << "Cannot set socket priority"; 105 | } 106 | #endif 107 | 108 | rbbufctrl = std::make_unique(sctrl); 109 | rbbufdata = std::make_unique(sdata); 110 | 111 | iothread = std::thread([&](){ 112 | work = std::make_unique(io_service); 113 | io_service.run(); 114 | }); 115 | 116 | GetInfo(); 117 | } 118 | 119 | CNetBlockIO::~CNetBlockIO() 120 | { 121 | 122 | LOG(LogLevel::DEBUG) << "CNetBlockIO: Destruct"; 123 | LOG(LogLevel::DEBUG) << "CNetBlockIO: Send Close command"; 124 | Close(); 125 | LOG(LogLevel::DEBUG) << "CNetBlockIO: Send Close command done"; 126 | 127 | rbbufctrl->Sync(); 128 | rbbufdata->Sync(); 129 | 130 | work.reset(); 131 | io_service.stop(); 132 | iothread.join(); 133 | 134 | LOG(LogLevel::DEBUG) << "CNetBlockIO: Destruct buffer"; 135 | rbbufctrl.reset(); 136 | rbbufdata.reset(); 137 | LOG(LogLevel::DEBUG) << "CNetBlockIO: Destruct buffers done"; 138 | 139 | LOG(LogLevel::DEBUG) << "CNetBlockIO: Destruct done"; 140 | } 141 | 142 | int64_t CNetBlockIO::GetWriteCache() 143 | { 144 | return rbbufctrl->GetBytesInCache() + rbbufdata->GetBytesInCache(); 145 | } 146 | 147 | int64_t CNetBlockIO::GetFilesize() 148 | { 149 | int64_t filesize; 150 | CommandDesc cmd{}; 151 | int8_t data[8]; 152 | int32_t id = cmdid.fetch_add(1); 153 | cmd.cmd = to_underlying(COMMAND::SIZE); 154 | std::future fut = rbbufctrl->Read(id, data, 8); 155 | rbbufctrl->Write(id, (int8_t*)&cmd, 4); 156 | fut.get(); 157 | memcpy(&filesize, data, sizeof(filesize)); // to prevent the aliasing warning 158 | 159 | return filesize; 160 | } 161 | 162 | void CNetBlockIO::GetInfo() 163 | { 164 | CommandDesc cmd{}; 165 | int8_t data[36]; 166 | int32_t id = cmdid.fetch_add(1); 167 | cmd.cmd = to_underlying(COMMAND::CONTAINERINFO); 168 | std::future fut = rbbufctrl->Read(id, data, 36); 169 | rbbufctrl->Write(id, (int8_t*)&cmd, 4); 170 | fut.get(); 171 | LOG(LogLevel::INFO) << "Connected to '" << data << "'"; 172 | } 173 | 174 | 175 | void CNetBlockIO::Close() 176 | { 177 | CommandDesc cmd{}; 178 | int8_t data[8]; 179 | int32_t id = cmdid.fetch_add(1); 180 | cmd.cmd = to_underlying(COMMAND::CLOSE); 181 | std::future futctrl = rbbufctrl->Read(id, data, 0); 182 | std::future futdata = rbbufdata->Read(id, data, 0); 183 | rbbufctrl->Write(id, (int8_t*)&cmd, 4); 184 | rbbufdata->Write(id, (int8_t*)&cmd, 4); 185 | futctrl.get(); 186 | futdata.get(); 187 | } 188 | 189 | 190 | void CNetBlockIO::Read(const int blockidx, const int n, int8_t *d) 191 | { 192 | CommandDesc cmd{}; 193 | int32_t id = cmdid.fetch_add(1); 194 | cmd.cmd = to_underlying(COMMAND::READ); 195 | cmd.dummy = 0; 196 | cmd.offset = blockidx*blocksize; 197 | cmd.length = blocksize*n; 198 | //printf("read block %i\n", blockidx); 199 | std::future fut = rbbufctrl->Read(id, d, blocksize*n); 200 | rbbufctrl->Write(id, (int8_t*)&cmd, 2*4+2*8); 201 | fut.get(); 202 | } 203 | 204 | void CNetBlockIO::Write(const int blockidx, const int n, int8_t* d) 205 | { 206 | int8_t buf[blocksize*n + 2*8 + 2*4]; 207 | auto *cmd = (CommandDesc*)buf; 208 | int32_t id = cmdid.fetch_add(1); 209 | cmd->cmd = to_underlying(COMMAND::WRITE); 210 | cmd->dummy = 0; 211 | cmd->offset = blockidx*blocksize; 212 | cmd->length = blocksize*n; 213 | memcpy(&cmd->data, d, blocksize*n); 214 | rbbufdata->Write(id, buf, blocksize*n + 2*8 + 2*4); 215 | } 216 | -------------------------------------------------------------------------------- /src/IO/CNetBlockIO.h: -------------------------------------------------------------------------------- 1 | #ifndef CNETIO_H 2 | #define CNETIO_H 3 | 4 | #include "CBlockIO.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | using boost::asio::ip::tcp; 11 | namespace ssl = boost::asio::ssl; 12 | typedef ssl::stream ssl_socket; 13 | 14 | #include 15 | #include 16 | 17 | class CNetReadWriteBuffer; 18 | 19 | class CNetBlockIO : public CAbstractBlockIO 20 | { 21 | public: 22 | CNetBlockIO(int _blocksize, const std::string &host, const std::string &port); 23 | ~CNetBlockIO(); 24 | 25 | void Read(int blockidx, int n, int8_t* d); 26 | void Write(int blockidx, int n, int8_t* d); 27 | int64_t GetFilesize() override; 28 | int64_t GetWriteCache() override; 29 | void GetInfo(); 30 | void Close(); 31 | 32 | private: 33 | boost::asio::io_service io_service; 34 | ssl::context ctx; 35 | ssl_socket sctrl; 36 | ssl_socket sdata; 37 | std::atomic_int cmdid; 38 | std::thread iothread; 39 | std::unique_ptr work; 40 | std::unique_ptr rbbufctrl; 41 | std::unique_ptr rbbufdata; 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/IO/CNetReadWriteBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include"Logger.h" 2 | #include "CNetReadWriteBuffer.h" 3 | 4 | 5 | CNetReadWriteBuffer::CNetReadWriteBuffer(ssl_socket &s) : socket(s) 6 | { 7 | // prepare write ring buffer 8 | buf.assign(1024*1024, 0); 9 | pushidx = 0; 10 | popidx = 0; 11 | bufsize = 0; 12 | 13 | // Start the async read loop 14 | AsyncRead(); 15 | } 16 | 17 | CNetReadWriteBuffer::~CNetReadWriteBuffer() 18 | { 19 | LOG(LogLevel::DEBUG) << "CNetReadWriteBuffer: destruct"; 20 | Sync(); 21 | LOG(LogLevel::DEBUG) << "CNetReadWriteBuffer: destruct done"; 22 | } 23 | 24 | // -------------------------------------------------------- 25 | 26 | void CNetReadWriteBuffer::Sync() 27 | { 28 | { 29 | std::lock_guard lock(readidmapmtx); 30 | unsigned long n = readidmap.size(); 31 | if (n != 0) 32 | { 33 | LOG(LogLevel::WARN) << "Read queue not empty"; 34 | } 35 | } 36 | while(true) 37 | { 38 | size_t n = bufsize.load(); 39 | if (n == 0) 40 | { 41 | LOG(LogLevel::DEBUG) << "CNetReadWriteBuffer: sync done"; 42 | return; 43 | } 44 | LOG(LogLevel::INFO) << "write cache: emptying cache. Still "<< n << "bytes to go."; 45 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 46 | } 47 | } 48 | 49 | std::future CNetReadWriteBuffer::Read(int32_t id, int8_t *buf, int32_t size) 50 | { 51 | CReadBufferDesc rbi(buf, size); 52 | std::lock_guard lock(readidmapmtx); 53 | readidmap[id] = std::move(rbi); 54 | return readidmap[id].promise.get_future(); 55 | } 56 | 57 | 58 | void CNetReadWriteBuffer::AsyncRead2(int32_t size, int32_t id) 59 | { 60 | static CReadBufferDesc rbi; 61 | std::lock_guard lock(readidmapmtx); 62 | auto it = readidmap.find(id); 63 | assert(it != readidmap.end()); 64 | rbi = std::move(it->second); 65 | readidmap.erase(it); 66 | 67 | boost::asio::async_read( 68 | socket, 69 | boost::asio::buffer(rbi.buf, rbi.size), 70 | [this](const boost::system::error_code& ec, std::size_t readbytes) 71 | { 72 | assert(readbytes == rbi.size); 73 | rbi.promise.set_value(); 74 | AsyncRead(); 75 | }); 76 | } 77 | 78 | void CNetReadWriteBuffer::AsyncRead() 79 | { 80 | static int32_t data[2]; 81 | boost::asio::async_read( 82 | socket, 83 | boost::asio::buffer(data, 8), 84 | [this](const boost::system::error_code& ec, std::size_t readbytes) 85 | { 86 | AsyncRead2(data[0]-8, data[1]); 87 | }); 88 | } 89 | 90 | // -------------------------------------------------------- 91 | 92 | void CNetReadWriteBuffer::Write(int32_t id, int8_t *d, int n) 93 | { 94 | std::lock_guard lock(writemtx); 95 | int32_t data[2]; 96 | data[0] = n+8; // total length of packet 97 | data[1] = id; // unique id of packet 98 | Push((int8_t*)data, 8); 99 | Push(d, n); 100 | AsyncWrite(); 101 | } 102 | 103 | void CNetReadWriteBuffer::Push(int8_t *d, int n) 104 | { 105 | //printf("Push %i bytes\n", n); 106 | for(int i=0; i buf.size()-2) 110 | { 111 | LOG(LogLevel::DEEP) << "Ringbuffer full: blocking"; 112 | AsyncWrite(); 113 | std::unique_lock lock(condmtx); 114 | while(bufsize.load() > buf.size()-2) 115 | { 116 | cond.wait_for(lock, std::chrono::milliseconds(500)); 117 | } 118 | } 119 | buf[pushidx] = d[i]; 120 | pushidx++; 121 | bufsize.fetch_add(1); 122 | if (pushidx >= buf.size()) pushidx -= buf.size(); 123 | } 124 | } 125 | 126 | void CNetReadWriteBuffer::AsyncWrite() 127 | { 128 | wpmutex.lock(); 129 | bool wip = write_in_progress.test_and_set(); 130 | wpmutex.unlock(); 131 | 132 | if (wip) return; // return if it already runs 133 | //if (bufsize.load() > 0) printf("write size=%i\n", bufsize.load()); 134 | size_t sendsize = std::min(buf.size()-popidx, bufsize.load()); 135 | boost::asio::async_write( 136 | socket, 137 | boost::asio::buffer(&(buf[popidx]), sendsize), 138 | [this](const boost::system::error_code& ec, std::size_t writtenbytes) 139 | { 140 | //std::unique_lock lock(condmtx); 141 | //printf("written bytes %li\n", writtenbytes); 142 | popidx += writtenbytes; 143 | bufsize.fetch_sub(writtenbytes); 144 | if (popidx >= buf.size()) popidx -= buf.size(); 145 | cond.notify_one(); 146 | wpmutex.lock(); 147 | write_in_progress.clear(); 148 | wpmutex.unlock(); 149 | if (bufsize.load() > 0) AsyncWrite(); 150 | }); 151 | } 152 | 153 | int64_t CNetReadWriteBuffer::GetBytesInCache() 154 | { 155 | return bufsize.load(); 156 | } 157 | -------------------------------------------------------------------------------- /src/IO/CNetReadWriteBuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef CWRITERINGBUFFER_H 2 | #define CWRITERINGBUFFER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | using boost::asio::ip::tcp; 14 | namespace ssl = boost::asio::ssl; 15 | typedef ssl::stream ssl_socket; 16 | 17 | class CReadBufferDesc 18 | { 19 | public: 20 | explicit CReadBufferDesc(int8_t *_buf= nullptr, size_t _size=0) : buf(_buf), size(_size) {} 21 | int8_t *buf; // which buffer to fill 22 | size_t size; // size of buffer 23 | std::promise promise; // which task to notify 24 | }; 25 | 26 | class CNetReadWriteBuffer 27 | { 28 | public: 29 | explicit CNetReadWriteBuffer(ssl_socket &s); 30 | ~CNetReadWriteBuffer(); 31 | void Write(int32_t id, int8_t *d, int n); 32 | std::future Read(int32_t id, int8_t *buf, int32_t size); 33 | void Sync(); 34 | int64_t GetBytesInCache(); 35 | 36 | private: 37 | 38 | // for reading 39 | void AsyncRead(); 40 | void AsyncRead2(int32_t size, int32_t id); 41 | std::mutex readidmapmtx; 42 | std::map readidmap; 43 | 44 | // for writing 45 | void Push(int8_t *d, int n); 46 | void AsyncWrite(); 47 | 48 | // write buffer 49 | std::vector buf; 50 | unsigned int pushidx; 51 | unsigned int popidx; 52 | std::atomic_size_t bufsize; 53 | 54 | std::condition_variable cond; 55 | std::mutex condmtx; 56 | 57 | std::atomic_flag write_in_progress = ATOMIC_FLAG_INIT; 58 | std::mutex wpmutex; 59 | 60 | std::mutex writemtx; 61 | 62 | ssl_socket &socket; 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/client/CStatusView.cpp: -------------------------------------------------------------------------------- 1 | #include "CStatusView.h" 2 | #include "Logger.h" 3 | 4 | 5 | CStatusView::CStatusView( 6 | std::weak_ptr _fs, 7 | std::weak_ptr _cbio, 8 | std::weak_ptr _bio 9 | ) : fs(_fs), cbio(_cbio), bio(_bio) 10 | { 11 | wait_for_terminate = terminate_signal.get_future(); 12 | t = std::thread(&CStatusView::Work, this); 13 | } 14 | 15 | CStatusView::~CStatusView() 16 | { 17 | terminate_signal.set_value(); 18 | t.join(); 19 | } 20 | 21 | void CStatusView::Work() 22 | { 23 | std::string ninodes; 24 | std::string ncached; 25 | std::string ndirty; 26 | std::string nwritecache; 27 | 28 | while(wait_for_terminate.wait_for(std::chrono::seconds(1)) == std::future_status::timeout) 29 | { 30 | /* 31 | if (auto fs = this->fs.lock()) 32 | { 33 | ninodes = std::to_string(fs->GetNInodes()); 34 | } else 35 | */ 36 | { 37 | ninodes = "-"; 38 | } 39 | if (auto bio = this->bio.lock()) 40 | { 41 | nwritecache = std::to_string(bio->GetWriteCache()); 42 | } else 43 | { 44 | nwritecache = "-"; 45 | } 46 | if (auto cbio = this->cbio.lock()) 47 | { 48 | ncached = std::to_string(cbio->GetNCachedBlocks()); 49 | ndirty = std::to_string(cbio->GetNDirty()); 50 | } else 51 | { 52 | ncached = "-"; 53 | ndirty = "-"; 54 | } 55 | LOG(LogLevel::INFO) << 56 | "used inodes: " << ninodes << 57 | " cached blocks: "<< ncached << 58 | " dirty blocks: " << ndirty << 59 | " write cache: " << nwritecache; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/client/CStatusView.h: -------------------------------------------------------------------------------- 1 | #ifndef CSTATUSVIEW_H 2 | #define CSTATUSVIEW_H 3 | 4 | #include "../FS/SimpleFS/CSimpleFS.h" 5 | #include "../IO/CCacheIO.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | class CStatusView 12 | { 13 | public: 14 | CStatusView( 15 | std::weak_ptr _fs, 16 | std::weak_ptr _cbio, 17 | std::weak_ptr _bio 18 | ); 19 | ~CStatusView(); 20 | 21 | private: 22 | void Work(); 23 | 24 | std::thread t; 25 | std::promise terminate_signal; 26 | std::future wait_for_terminate; 27 | std::weak_ptr fs; 28 | std::weak_ptr cbio; 29 | std::weak_ptr bio; 30 | }; 31 | 32 | 33 | #endif 34 | 35 | -------------------------------------------------------------------------------- /src/client/ParallelTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include"ParallelTest.h" 9 | #include"../FS/CFilesystem.h" 10 | 11 | 12 | #define MAXSIZE 0xFFFFF 13 | 14 | // ---------------------- 15 | 16 | static CFilesystem *fs; 17 | 18 | // ---------------------- 19 | 20 | typedef struct 21 | { 22 | CInodePtr node; 23 | char filename[256]{}; 24 | int64_t size{}; 25 | std::mutex mtx; 26 | char data[MAXSIZE+2]{}; 27 | unsigned int g_seed{}; 28 | } FSTRUCT; 29 | 30 | static FSTRUCT *files; 31 | 32 | static unsigned int niter = 2000; 33 | static unsigned int nfiles = 10; 34 | static unsigned int nthreads = 10; 35 | 36 | static unsigned int g_seed = 0; 37 | 38 | inline int fastrand(unsigned int &g_seed) 39 | { 40 | g_seed = (214013*g_seed+2531011); 41 | return (g_seed>>16)&0x7FFF; 42 | } 43 | 44 | // ---------------------- 45 | 46 | void Execute(int tid) 47 | { 48 | char *data = new char[MAXSIZE+2]; 49 | CDirectoryPtr dir = fs->OpenDir(CPath("/")); 50 | 51 | //printf("thread %i:\n", tid); 52 | for(unsigned int iter=0; iter files[id].size) 68 | { 69 | memset(&(files[id].data[ files[id].size ]), 0, newsize - files[id].size); 70 | } 71 | files[id].size = newsize; 72 | files[id].node->Truncate(newsize, true); 73 | } 74 | break; 75 | 76 | 77 | case 1: // write 78 | { 79 | if (files[id].size > 0) ofs = rand() % files[id].size; 80 | int newsize = rand() & MAXSIZE; 81 | if (ofs+newsize > MAXSIZE) newsize = MAXSIZE - ofs - 1; 82 | if (newsize < 0) newsize = 0; 83 | 84 | printf("tid %1i %5i: write %i ofs=%i size=%i\n", tid, iter, id, ofs, newsize); 85 | for(int i=0; iWrite((int8_t*)&(files[id].data[ofs]), ofs, newsize); 91 | if (ofs+newsize > files[id].size) files[id].size = ofs+newsize; 92 | } 93 | break; 94 | 95 | case 2: // read 96 | { 97 | if (files[id].size > 0) ofs = rand() % files[id].size; 98 | int newsize = rand() & MAXSIZE; 99 | if (ofs+newsize > MAXSIZE) newsize = MAXSIZE - ofs - 1; 100 | if (newsize < 0) newsize = 0; 101 | 102 | printf("tid %1i %5i: read %i ofs=%i size=%i\n", tid, iter, id, ofs, newsize); 103 | if (ofs+newsize > files[id].size) newsize = files[id].size - ofs - 1; 104 | if (newsize < 0) newsize = 0; 105 | files[id].node->Read((int8_t*)data, ofs, newsize); 106 | 107 | for(int i=0; iGetSize() != (unsigned int)files[id].size) 122 | { 123 | printf("size of file %i does not match %i %lli\n", id, (int)files[id].size, (long long int)files[id].node->GetSize()); 124 | exit(1); 125 | } 126 | } 127 | break; 128 | 129 | case 4: // rename 130 | { 131 | printf("tid %1i %5i: rename %i\n", tid, iter, id); 132 | char newfilename[256]; 133 | sprintf(newfilename, "tests%02i_%03i.dat", id, rand()%999); 134 | fs->Rename(CPath(files[id].filename), dir, newfilename); 135 | strncpy(files[id].filename, newfilename, 256); 136 | } 137 | break; 138 | 139 | 140 | case 5: // create&remove 141 | { 142 | printf("tid %1i %5i: create&remove %i\n", tid, iter, id); 143 | char newfilename[256]; 144 | sprintf(newfilename, "tests%02i_check.dat", id); 145 | dir->MakeFile(newfilename); 146 | fs->Unlink(CPath(newfilename)); 147 | } 148 | break; 149 | 150 | default: break; 151 | } // switch 152 | files[id].mtx.unlock(); 153 | 154 | } 155 | delete[] data; 156 | } 157 | 158 | 159 | void ParallelTest(unsigned int _nfiles, unsigned int _nthreads, unsigned int _niter, CFilesystem &_fs) 160 | { 161 | printf("Number of files %i\n", nfiles); 162 | printf("Number of threads: %i\n", nthreads); 163 | printf("Number of iterations per thread: %i\n", niter); 164 | 165 | srand (time(NULL)); 166 | g_seed = time(NULL); 167 | 168 | nfiles = _nfiles; 169 | nthreads = _nthreads; 170 | niter = _niter; 171 | fs = &_fs; 172 | CDirectoryPtr dir = fs->OpenDir(CPath("/")); 173 | 174 | files = new FSTRUCT[nfiles]; 175 | for(unsigned int i=0; iMakeFile(files[i].filename); 182 | } 183 | catch(...) 184 | { 185 | // file already exists 186 | } 187 | files[i].node = fs->OpenFile(CPath(files[i].filename)); 188 | files[i].node->Truncate(0, true); 189 | 190 | files[i].size = 0; 191 | memset(files[i].data, 0, MAXSIZE+1); 192 | } 193 | 194 | auto *t = new std::thread[nthreads]; 195 | 196 | for(unsigned int i=0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include"Logger.h" 8 | 9 | #include"../interface/CFSHandler.h" 10 | #include"../FS/SimpleFS/CPrintCheckRepair.h" 11 | #include"CStatusView.h" 12 | #include"ParallelTest.h" 13 | 14 | #include"../webapp/webapp.h" 15 | #include 16 | 17 | // ----------------------------------------------------------------- 18 | 19 | static CFSHandler handler; 20 | std::unique_ptr statusview; 21 | 22 | // ----------------------------------------------------------------- 23 | 24 | void PrintUsage(char *argv[]) 25 | { 26 | printf("Usage: %s [options] mountpoint\n", argv[0]); 27 | printf("Options:\n"); 28 | printf(" --help Print this help message\n"); 29 | printf(" --backend [backend] [backend] can be 'ram', 'file', or 'cvfsserer'\n"); 30 | printf(" default: 'cvfsserver'\n"); 31 | printf(" --fstype [fstype] [fstype] can be 'simple', or 'container'\n"); 32 | printf(" --host [hostname] default: 'localhost'\n"); 33 | printf(" --port [port] default: '62000'\n"); 34 | printf(" --cryptcache crypt cache in RAM\n"); 35 | printf(" --info Prints information about filesystem\n"); 36 | printf(" --fragments Prints information about the fragments\n"); 37 | printf(" --rootdir Print root directory\n"); 38 | printf(" --check Check filesystem\n"); 39 | printf(" --test Tests filesystem and multi-threading\n"); 40 | printf(" --debug Debug output\n"); 41 | #ifdef HAVE_POCO 42 | printf(" --web Start Webinterface\n"); 43 | #endif 44 | } 45 | 46 | 47 | // ----------------------------------------------------------------- 48 | 49 | static void catch_function(int signo) 50 | { 51 | LOG(LogLevel::INFO) << "Terminate Signal received"; 52 | handler.Unmount().get(); 53 | } 54 | 55 | // ----------------------------------------------------------------- 56 | 57 | int main(int argc, char *argv[]) 58 | { 59 | char hostname[256]; 60 | char mountpoint[256]; 61 | char port[256]; 62 | char backend[256]; 63 | char fstype[256]; 64 | bool check = false; 65 | bool info = false; 66 | bool showfragments = false; 67 | bool rootdir = false; 68 | //bool cryptcache = false; 69 | bool testfs = false; 70 | #ifdef HAVE_POCO 71 | bool webinterface = false; 72 | #endif 73 | 74 | fstype[0] = 0; 75 | 76 | strncpy(hostname, "localhost", 255); 77 | strncpy(port, "62000", 255); 78 | strncpy(backend, "cvfsserver", 255); 79 | Logger().Set(LogLevel::INFO); 80 | 81 | mountpoint[0] = 0; 82 | 83 | if (argc < 2) 84 | { 85 | PrintUsage(argv); 86 | return 0; 87 | } 88 | 89 | static struct option long_options[] = { 90 | {"help", no_argument, nullptr, 0 }, 91 | {"port", required_argument, nullptr, 0 }, 92 | {"host", required_argument, nullptr, 0 }, 93 | {"info", no_argument, nullptr, 0 }, 94 | {"fragments", no_argument, nullptr, 0 }, 95 | {"rootdir", no_argument, nullptr, 0 }, 96 | {"check", no_argument, nullptr, 0 }, 97 | {"backend", required_argument, nullptr, 0 }, 98 | {"fstype", required_argument, nullptr, 0 }, 99 | {"debug", no_argument, nullptr, 0 }, 100 | {"debugdeep", no_argument, nullptr, 0 }, 101 | {"cryptcache", no_argument, nullptr, 0 }, 102 | {"test", no_argument, nullptr, 0 }, 103 | {"web", no_argument, nullptr, 0 }, 104 | {nullptr, 0, nullptr, 0 } 105 | }; 106 | 107 | while(true) 108 | { 109 | int option_index = 0; 110 | int c = getopt_long(argc, argv, "", long_options, &option_index); 111 | if (c == -1) break; 112 | switch (c) 113 | { 114 | case 0: 115 | switch(option_index) 116 | { 117 | case 1: 118 | strncpy(port, optarg, 255); 119 | break; 120 | 121 | case 2: 122 | strncpy(hostname, optarg, 255); 123 | break; 124 | 125 | case 3: 126 | info = true; 127 | break; 128 | 129 | case 4: 130 | showfragments = true; 131 | break; 132 | 133 | case 5: 134 | rootdir = true; 135 | break; 136 | 137 | case 6: 138 | check = true; 139 | break; 140 | 141 | case 7: 142 | strncpy(backend, optarg, 255); 143 | for (char *p=backend ; *p; ++p) *p = static_cast(tolower(*p)); 144 | break; 145 | 146 | case 8: 147 | strncpy(fstype, optarg, 255); 148 | for (char *p=fstype ; *p; ++p) *p = static_cast(tolower(*p)); 149 | break; 150 | 151 | case 9: 152 | Logger().Set(LogLevel::DEBUG); 153 | break; 154 | 155 | case 10: 156 | Logger().Set(LogLevel::DEEP); 157 | break; 158 | 159 | case 11: 160 | //cryptcache = true; 161 | break; 162 | 163 | case 12: 164 | testfs = true; 165 | break; 166 | 167 | case 13: 168 | #ifdef HAVE_POCO 169 | webinterface = true; 170 | #endif 171 | break; 172 | 173 | case 0: // help 174 | default: 175 | PrintUsage(argv); 176 | return EXIT_FAILURE; 177 | } 178 | break; 179 | 180 | case '?': 181 | default: 182 | PrintUsage(argv); 183 | return EXIT_FAILURE; 184 | } 185 | } 186 | 187 | LOG(LogLevel::INFO) << "Start CoverFS"; 188 | 189 | #ifdef HAVE_POCO 190 | if (webinterface) 191 | { 192 | return StartWebApp(handler); 193 | //return EXIT_SUCCESS; 194 | } 195 | #endif 196 | 197 | if ((!check) && (!info) && (!showfragments) && (!rootdir) && (!testfs)) 198 | { 199 | if (optind < argc) 200 | { 201 | strncpy(mountpoint, argv[optind], 255); 202 | } else 203 | { 204 | PrintUsage(argv); 205 | return EXIT_FAILURE; 206 | } 207 | } 208 | 209 | bool success = true; 210 | if (strcmp(backend, "ram") == 0) 211 | { 212 | success = handler.ConnectRAM().get(); 213 | } else 214 | if (strncmp(backend, "file", 255) == 0) 215 | { 216 | LOG(LogLevel::ERR) << "Backend 'file' not supported"; 217 | return EXIT_FAILURE; 218 | } else 219 | if (strncmp(backend, "cvfsserver", 255) == 0) 220 | { 221 | success = handler.ConnectNET(hostname, port).get(); 222 | } else 223 | { 224 | LOG(LogLevel::ERR) << "Backend '" << backend << "' not supported"; 225 | return EXIT_FAILURE; 226 | } 227 | 228 | if (!success) return EXIT_FAILURE; 229 | 230 | handler.SetFilesystemType(SIMPLE); 231 | if ((fstype[0] == 0) || (strcmp(fstype, "simple") == 0)) 232 | { 233 | handler.SetFilesystemType(SIMPLE); 234 | } else 235 | if (strcmp(fstype, "container") == 0) 236 | { 237 | handler.SetFilesystemType(CONTAINER); 238 | } else 239 | { 240 | LOG(LogLevel::ERR) << "Filesystem '" << fstype << "' not supported"; 241 | return EXIT_FAILURE; 242 | } 243 | 244 | char *pass = getpass("Password: "); 245 | bool ret = handler.Decrypt(pass).get(); 246 | memset(pass, 0, strlen(pass)); 247 | if (!ret) return EXIT_FAILURE; 248 | 249 | 250 | if (info) 251 | { 252 | printf("==============================\n"); 253 | printf("============ INFO ============\n"); 254 | printf("==============================\n"); 255 | handler.fs->PrintInfo(); 256 | } 257 | 258 | if (showfragments) 259 | { 260 | printf("==============================\n"); 261 | printf("========= FRAGMENTS ==========\n"); 262 | printf("==============================\n"); 263 | handler.fs->PrintFragments(); 264 | } 265 | 266 | if (check) 267 | { 268 | printf("==============================\n"); 269 | printf("=========== CHECK ============\n"); 270 | printf("==============================\n"); 271 | handler.fs->Check(); 272 | } 273 | 274 | if (rootdir) 275 | { 276 | CDirectoryPtr dir = handler.fs->OpenDir(CPath("/")); 277 | if (dir.get() == nullptr) 278 | { 279 | LOG(LogLevel::ERR) << "Root Directory not present"; 280 | return EXIT_FAILURE; 281 | } 282 | int n = 0; 283 | printf("======================\n"); 284 | printf("Root directory entries\n"); 285 | printf("======================\n"); 286 | 287 | CDirectoryIteratorPtr iterator = dir->GetIterator(); 288 | while (iterator->HasNext()) { 289 | printf(" %3i: '%s'\n", n, iterator->Next().name.c_str()); 290 | n++; 291 | } 292 | printf("======================\n"); 293 | } 294 | 295 | if (testfs) 296 | { 297 | printf("==============================\n"); 298 | printf("============ TEST ============\n"); 299 | printf("==============================\n"); 300 | ParallelTest(10, 10, 2000, *handler.fs); 301 | statusview = std::make_unique(handler.fs, handler.cbio, handler.bio); 302 | //std::this_thread::sleep_for(std::chrono::seconds(20)); 303 | } 304 | 305 | if ((info) || (showfragments) || (check) || (rootdir) || (testfs)) 306 | { 307 | LOG(LogLevel::INFO) << "Stop CoverFS"; 308 | return EXIT_SUCCESS; 309 | } 310 | 311 | statusview = std::make_unique(handler.fs, handler.cbio, handler.bio); 312 | 313 | if (signal(SIGINT, catch_function) == SIG_ERR) 314 | { 315 | LOG(LogLevel::ERR) << "An error occurred while setting a signal handler."; 316 | return EXIT_FAILURE; 317 | } 318 | handler.Mount(argc, argv, mountpoint).get(); 319 | 320 | LOG(LogLevel::INFO) << "Stop CoverFS"; 321 | } 322 | -------------------------------------------------------------------------------- /src/fuse/dokanoper.h: -------------------------------------------------------------------------------- 1 | #ifndef DOKANOPER_H 2 | #define DOKANOPER_H 3 | 4 | #include"../FS/CFilesystem.h" 5 | 6 | int StartDokan(int argc, char *argv[], const char* mountpoint, CFilesystem &fs); 7 | int StopDokan(); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/fuse/fuseoper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include"Logger.h" 8 | #include"../FS/CFilesystem.h" 9 | 10 | #include"fuseoper.h" 11 | 12 | //http://fuse.sourceforge.net/doxygen/fusexmp__fh_8c.html 13 | //https://www.cs.hmc.edu/~geoff/classes/hmc.cs135.201001/homework/fuse/fuse_doc.html 14 | 15 | #define FUSE_USE_VERSION 26 16 | extern "C" { 17 | #include 18 | } 19 | 20 | static CFilesystem *fs; 21 | std::string mountpoint; 22 | struct fuse *fusectx = NULL; 23 | struct fuse_chan *fuse_chan = NULL; 24 | 25 | static int fuse_getattr(const char *path, struct stat *stbuf) 26 | { 27 | LOG(LogLevel::INFO) << "FUSE: getattr '" << path << "'"; 28 | 29 | memset(stbuf, 0, sizeof(struct stat)); 30 | 31 | if (strcmp(path, "/") == 0) 32 | { 33 | stbuf->st_mode = S_IFDIR | 0755; 34 | stbuf->st_nlink = 2; 35 | return 0; 36 | } 37 | 38 | try 39 | { 40 | CInodePtr node = fs->OpenNode(CPath(path)); 41 | int64_t size = node->GetSize(); 42 | stbuf->st_size = size; 43 | stbuf->st_blocks = size/512; 44 | stbuf->st_nlink = 1; 45 | if (node->GetType() == INODETYPE::dir) 46 | { 47 | stbuf->st_mode = S_IFDIR | 0755; 48 | } else 49 | { 50 | stbuf->st_mode = S_IFREG | 0666; 51 | } 52 | 53 | } catch(const int &err) 54 | { 55 | return -err; 56 | } 57 | 58 | return 0; 59 | } 60 | 61 | static int fuse_utimens(const char *path, const struct timespec tv[2]) 62 | { 63 | LOG(LogLevel::INFO) << "FUSE: utimens '" << path << "'"; 64 | return 0; 65 | } 66 | 67 | static int fuse_chmod(const char *path, mode_t mode) 68 | { 69 | LOG(LogLevel::INFO) << "FUSE: chmod '" << path << "'"; 70 | return 0; 71 | } 72 | 73 | static int fuse_chown(const char *path, uid_t uid, gid_t gid) 74 | { 75 | LOG(LogLevel::INFO) << "FUSE: chown '" << path << "'"; 76 | return 0; 77 | } 78 | 79 | static int fuse_truncate(const char *path, off_t size) 80 | { 81 | LOG(LogLevel::INFO) << "FUSE: truncate '" << path << "' size=" << size; 82 | try 83 | { 84 | CInodePtr node = fs->OpenFile(CPath(path)); 85 | node->Truncate(size, true); 86 | } catch(const int &err) 87 | { 88 | return -err; 89 | } 90 | return 0; 91 | } 92 | 93 | static int fuse_opendir(const char *path, struct fuse_file_info *fi) 94 | { 95 | LOG(LogLevel::INFO) << "FUSE: opendir '" << path << "'"; 96 | try 97 | { 98 | CDirectoryPtr dir = fs->OpenDir(CPath(path)); 99 | fi->fh = dir->GetId(); 100 | } catch(const int &err) 101 | { 102 | return -err; 103 | } 104 | return 0; 105 | } 106 | 107 | static int fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) 108 | { 109 | (void) offset; 110 | LOG(LogLevel::INFO) << "FUSE: readdir '" << path << "'"; 111 | try 112 | { 113 | CDirectoryPtr dir = fs->OpenDir(fi->fh); 114 | filler(buf, ".", NULL, 0); 115 | filler(buf, "..", NULL, 0); 116 | CDirectoryIteratorPtr iterator = dir->GetIterator(); 117 | while(iterator->HasNext()) 118 | { 119 | filler(buf, iterator->Next().name.c_str(), NULL, 0); 120 | } 121 | } catch(const int &err) 122 | { 123 | return -err; 124 | } 125 | 126 | return 0; 127 | } 128 | 129 | static int fuse_open(const char *path, struct fuse_file_info *fi) 130 | { 131 | LOG(LogLevel::INFO) << "FUSE: open '" << path << "'"; 132 | try 133 | { 134 | CInodePtr node = fs->OpenFile(CPath(path)); 135 | fi->fh = node->GetId(); 136 | } catch(const int &err) 137 | { 138 | return -err; 139 | } 140 | /* 141 | if ((fi->flags & 3) != O_RDONLY) 142 | return -EACCES; 143 | */ 144 | return 0; 145 | } 146 | 147 | static int fuse_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) 148 | { 149 | LOG(LogLevel::INFO) << "FUSE: read '" << path << "' ofs=" << offset << " size=" << size; 150 | try 151 | { 152 | CInodePtr node = fs->OpenFile(fi->fh); 153 | size = node->Read((int8_t*)buf, offset, size); 154 | } catch(const int &err) 155 | { 156 | return -err; 157 | } 158 | 159 | return size; 160 | } 161 | 162 | static int fuse_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) 163 | { 164 | LOG(LogLevel::INFO) << "FUSE: write '" << path << "' ofs=" << offset << " size=" << size; 165 | 166 | try 167 | { 168 | CInodePtr node = fs->OpenFile(fi->fh); 169 | node->Write((int8_t*)buf, offset, size); 170 | } catch(const int &err) 171 | { 172 | return -err; 173 | } 174 | return size; 175 | } 176 | 177 | 178 | static int fuse_mkdir(const char *path, mode_t mode) 179 | { 180 | LOG(LogLevel::INFO) << "FUSE: mkdir '" << path << "'"; 181 | // test if dir is empty? Looks like this is tested already 182 | std::vector splitpath = CPath(path).GetPath(); 183 | assert(splitpath.size() >= 1); 184 | std::string dirname = splitpath.back(); 185 | splitpath.pop_back(); 186 | try 187 | { 188 | CDirectoryPtr dir = fs->OpenDir(splitpath); 189 | dir->MakeDirectory(dirname); 190 | } catch(const int &err) 191 | { 192 | return -err; 193 | } 194 | return 0; 195 | } 196 | 197 | static int fuse_rmdir(const char *path) 198 | { 199 | LOG(LogLevel::INFO) << "FUSE: rmdir '" << path << "'"; 200 | 201 | try 202 | { 203 | CDirectoryPtr dir = fs->OpenDir(CPath(path)); 204 | if (!dir->IsEmpty()) return -ENOTEMPTY; 205 | fs->Unlink(CPath(path)); 206 | } catch(const int &err) 207 | { 208 | return -err; 209 | } 210 | 211 | return 0; 212 | } 213 | 214 | static int fuse_unlink(const char *path) 215 | { 216 | LOG(LogLevel::INFO) << "FUSE: unlink '" << path << "'"; 217 | 218 | try 219 | { 220 | fs->Unlink(CPath(path)); 221 | } catch(const int &err) 222 | { 223 | return -err; 224 | } 225 | 226 | return 0; 227 | } 228 | 229 | static int fuse_create(const char *path, mode_t mode, struct fuse_file_info *fi) 230 | { 231 | LOG(LogLevel::INFO) << "FUSE: create '" << path << "'"; 232 | std::vector splitpath = CPath(path).GetPath(); 233 | assert(splitpath.size() >= 1); 234 | std::string filename = splitpath.back(); 235 | splitpath.pop_back(); 236 | try 237 | { 238 | CDirectoryPtr dir = fs->OpenDir(splitpath); 239 | fi->fh = dir->MakeFile(filename); 240 | } catch(const int &err) 241 | { 242 | return -err; 243 | } 244 | 245 | return 0; 246 | } 247 | 248 | static int fuse_access(const char *path, int mask) 249 | { 250 | LOG(LogLevel::INFO) << "FUSE: access '" << path << "'"; 251 | try 252 | { 253 | CInodePtr node = fs->OpenNode(CPath(path)); 254 | } catch(const int &err) 255 | { 256 | return -err; 257 | } 258 | 259 | return 0; 260 | } 261 | 262 | static int fuse_rename(const char *oldpath, const char *newpath) 263 | { 264 | LOG(LogLevel::INFO) << "FUSE: create '" << oldpath << "' to '" << newpath << "'"; 265 | 266 | std::vector splitpath = CPath(newpath).GetPath(); 267 | assert(!splitpath.empty()); 268 | 269 | try 270 | { 271 | std::string filename = splitpath.back(); 272 | splitpath.pop_back(); 273 | CDirectoryPtr dir = fs->OpenDir(splitpath); 274 | fs->Rename(CPath(oldpath), dir, filename); 275 | } catch(const int &err) 276 | { 277 | return -err; 278 | } 279 | return 0; 280 | } 281 | 282 | static int fuse_statfs(const char *path, struct statvfs *buf) 283 | { 284 | LOG(LogLevel::INFO) << "FUSE: statfs '" << path << "'"; 285 | CStatFS stat; 286 | fs->StatFS(&stat); 287 | buf->f_bavail = stat.f_bavail; 288 | buf->f_bfree = stat.f_bfree; 289 | buf->f_blocks = stat.f_blocks; 290 | buf->f_bsize = stat.f_bsize; 291 | buf->f_files = stat.f_files; 292 | buf->f_frsize = stat.f_frsize; 293 | buf->f_namemax = stat.f_namemax; 294 | 295 | return 0; 296 | } 297 | 298 | int StopFuse() 299 | { 300 | if (fs == NULL) return EXIT_SUCCESS; 301 | if (fusectx == NULL) return EXIT_SUCCESS; 302 | LOG(LogLevel::INFO) << "Unmount FUSE mountpoint: " << mountpoint; 303 | fuse_unmount(mountpoint.c_str(), fuse_chan); 304 | return EXIT_SUCCESS; 305 | } 306 | 307 | int StartFuse(int argc, char *argv[], const char* _mountpoint, CFilesystem &_fs) 308 | { 309 | fs = &_fs; 310 | mountpoint = std::string(_mountpoint); 311 | 312 | LOG(LogLevel::INFO) << "FUSE Version: " << fuse_version(); 313 | 314 | struct fuse_args args = FUSE_ARGS_INIT(0, NULL); 315 | 316 | fuse_opt_add_arg(&args, "-odirect_io"); 317 | fuse_opt_add_arg(&args, "-obig_writes"); 318 | fuse_opt_add_arg(&args, "-oasync_read"); 319 | // fuse_opt_add_arg(&args, "-f"); 320 | // fuse_opt_add_arg(&args, _mountpoint); 321 | 322 | struct fuse_operations fuse_oper; 323 | memset(&fuse_oper, 0, sizeof(struct fuse_operations)); 324 | fuse_oper.getattr = fuse_getattr; 325 | fuse_oper.opendir = fuse_opendir; 326 | fuse_oper.readdir = fuse_readdir; 327 | fuse_oper.open = fuse_open; 328 | fuse_oper.read = fuse_read; 329 | fuse_oper.write = fuse_write; 330 | fuse_oper.mkdir = fuse_mkdir; 331 | fuse_oper.create = fuse_create; 332 | fuse_oper.rmdir = fuse_rmdir; 333 | fuse_oper.unlink = fuse_unlink; 334 | fuse_oper.truncate = fuse_truncate; 335 | fuse_oper.access = fuse_access; 336 | fuse_oper.rename = fuse_rename; 337 | fuse_oper.chmod = fuse_chmod; 338 | fuse_oper.chown = fuse_chown; 339 | fuse_oper.statfs = fuse_statfs; 340 | fuse_oper.utimens = fuse_utimens; 341 | //fuse_oper.flag_nullpath_ok = 1; 342 | 343 | fuse_chan = fuse_mount(_mountpoint, &args); 344 | fusectx = fuse_new(fuse_chan, &args, &fuse_oper, sizeof(fuse_oper), NULL); 345 | 346 | int ret = fuse_loop_mt(fusectx); 347 | fuse_destroy(fusectx); 348 | return ret; 349 | 350 | // return fuse_loop(fusectx); 351 | // return fuse_main(args.argc, args.argv, &fuse_oper, NULL); 352 | } 353 | 354 | -------------------------------------------------------------------------------- /src/fuse/fuseoper.h: -------------------------------------------------------------------------------- 1 | #ifndef FUSE_H 2 | #define FUSE_H 3 | 4 | #include"../FS/CFilesystem.h" 5 | 6 | int StartFuse(int argc, char *argv[], const char* mountpoint, CFilesystem &fs); 7 | int StopFuse(); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/interface/CFSHandler.cpp: -------------------------------------------------------------------------------- 1 | #include"CFSHandler.h" 2 | 3 | #if !defined(_WIN32) && !defined(_WIN64) && !defined(__CYGWIN__) 4 | #include"../fuse/fuseoper.h" 5 | #include "../FS/ContainerFS/ContainerFS.h" 6 | #include "../FS/SimpleFS/CSimpleFS.h" 7 | 8 | #else 9 | #include"../fuse/dokanoper.h" 10 | #endif 11 | 12 | std::future CFSHandler::Unmount() 13 | { 14 | std::future result( std::async([this]{ 15 | try 16 | { 17 | #if !defined(_WIN32) && !defined(_WIN64) && !defined(__CYGWIN__) 18 | return StopFuse(); 19 | #else 20 | return StopDokan(); 21 | #endif 22 | } catch(...) 23 | { 24 | return EXIT_FAILURE; 25 | } 26 | })); 27 | return result; 28 | } 29 | 30 | std::future CFSHandler::Mount(int argc, char *argv[], const char *mountpoint) 31 | { 32 | std::future result(std::async([this, argc, argv, mountpoint]{ 33 | try 34 | { 35 | #if !defined(_WIN32) && !defined(_WIN64) && !defined(__CYGWIN__) 36 | status = MOUNTED; 37 | int ret = StartFuse(argc, argv, mountpoint, *fs); 38 | status = UNMOUNTED; 39 | return ret; 40 | #else 41 | status = MOUNTED; 42 | int ret = StartDokan(argc, argv, mountpoint, *fs); 43 | status = UNMOUNTED; 44 | return ret; 45 | #endif 46 | } catch(...) 47 | { 48 | return 1; 49 | } 50 | 51 | })); 52 | return result; 53 | } 54 | 55 | std::future CFSHandler::ConnectNET(const std::string hostname, const std::string port) 56 | { 57 | std::future result( std::async([this, hostname, port]{ 58 | try 59 | { 60 | bio.reset(new CNetBlockIO(4096, hostname, port)); 61 | status = CONNECTED; 62 | return true; 63 | } catch(...) 64 | { 65 | return false; 66 | } 67 | })); 68 | return result; 69 | } 70 | 71 | std::future CFSHandler::ConnectRAM() 72 | { 73 | std::future result( std::async([this]{ 74 | try 75 | { 76 | bio.reset(new CRAMBlockIO(4096)); 77 | status = CONNECTED; 78 | return true; 79 | } catch(...) 80 | { 81 | return false; 82 | } 83 | })); 84 | return result; 85 | } 86 | 87 | std::future CFSHandler::Decrypt(char *pass) 88 | { 89 | std::future result( std::async([this, pass] { 90 | try 91 | { 92 | enc.reset(new CEncrypt(*bio, pass)); 93 | cbio.reset(new CCacheIO(bio, *enc, false)); 94 | 95 | switch(filesystemType) 96 | { 97 | case SIMPLE: 98 | fs.reset(new CSimpleFilesystem(cbio)); 99 | break; 100 | 101 | case CONTAINER: 102 | fs.reset(new ContainerFS(cbio)); 103 | break; 104 | } 105 | 106 | status = UNMOUNTED; 107 | return true; 108 | } catch(...) 109 | { 110 | return false; 111 | } 112 | })); 113 | return result; 114 | } 115 | 116 | void CFSHandler::SetFilesystemType(FilesystemType _filesystemType) { 117 | filesystemType = _filesystemType; 118 | } 119 | -------------------------------------------------------------------------------- /src/interface/CFSHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef CFSHANDLER_H 2 | #define CFSHANDLER_H 3 | 4 | #include 5 | #include"../IO/CBlockIO.h" 6 | #include"../IO/CNetBlockIO.h" 7 | #include"../IO/CEncrypt.h" 8 | #include"../IO/CCacheIO.h" 9 | #include"../FS/CFilesystem.h" 10 | 11 | enum HandlerStatus { DISCONNECTED, CONNECTED, UNMOUNTED, MOUNTED }; 12 | 13 | enum FilesystemType { SIMPLE, CONTAINER }; 14 | 15 | class CFSHandler 16 | { 17 | public: 18 | 19 | std::shared_ptr bio; 20 | std::shared_ptr enc; 21 | std::shared_ptr cbio; 22 | CFilesystemPtr fs; 23 | 24 | std::future ConnectNET(const std::string hostname, const std::string port); 25 | std::future ConnectRAM(); 26 | std::future Decrypt(char *pass); 27 | std::future Mount(int argc, char *argv[], const char *mountpoint); 28 | std::future Unmount(); 29 | 30 | void SetFilesystemType(FilesystemType _filesystemType); 31 | 32 | private: 33 | HandlerStatus status = DISCONNECTED; 34 | FilesystemType filesystemType = SIMPLE; 35 | 36 | }; 37 | 38 | 39 | #endif -------------------------------------------------------------------------------- /src/server/coverfsserver.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "Logger.h" 12 | 13 | using boost::asio::ip::tcp; 14 | 15 | typedef boost::asio::ssl::stream ssl_socket; 16 | 17 | FILE *fp; 18 | int64_t filesize; 19 | 20 | enum class COMMAND {read, write, size, info, close}; 21 | 22 | typedef struct 23 | { 24 | int32_t cmdlen; 25 | int32_t id; 26 | int32_t cmd; 27 | int32_t dummy; 28 | int64_t offset; 29 | int64_t length; 30 | int64_t data; 31 | } COMMANDSTRUCT; 32 | 33 | typedef struct 34 | { 35 | int32_t cmdlen; 36 | int32_t id; 37 | int8_t data; 38 | } REPLYCOMMANDSTRUCT; 39 | 40 | 41 | void ParseCommand(char *commandbuf, ssl_socket &sock) 42 | { 43 | //COMMANDSTRUCT *cmd = reinterpret_cast(commandbuf); 44 | auto *cmd = (COMMANDSTRUCT*)commandbuf; 45 | LOG(LogLevel::INFO) << "received command " << cmd->cmd << " with len=" << cmd->cmdlen; 46 | 47 | assert(cmd->cmdlen >= 8); 48 | switch((COMMAND)cmd->cmd) 49 | { 50 | case COMMAND::read: 51 | { 52 | //printf("READ ofs=%li size=%li (block: %li)\n", cmd->offset, cmd->length, cmd->offset/4096); 53 | fseek(fp, cmd->offset, SEEK_SET); 54 | auto *data = new int8_t[cmd->length+8]; 55 | auto *reply = (REPLYCOMMANDSTRUCT*)data; 56 | reply->cmdlen = cmd->length+8; 57 | reply->id = cmd->id; 58 | size_t nread = fread(&reply->data, cmd->length, 1, fp); 59 | if (nread == 0) 60 | { 61 | filesize = ftell(fp); 62 | if (cmd->offset+cmd->length >= filesize) 63 | { 64 | LOG(LogLevel::WARN) << "Read outside of file boundary"; 65 | } else 66 | { 67 | throw std::runtime_error(std::string("Cannot read ") + std::to_string(cmd->length) + " bytes from container"); 68 | } 69 | } 70 | boost::asio::write(sock, boost::asio::buffer(reply, reply->cmdlen)); 71 | delete[] data; 72 | break; 73 | } 74 | case COMMAND::write: 75 | { 76 | //printf("WRITE ofs=%li size=%li (block: %li)\n", cmd->offset, cmd->length, cmd->offset/4096); 77 | fseek(fp, cmd->offset, SEEK_SET); 78 | size_t nwrite = fwrite(&cmd->data, cmd->length, 1, fp); 79 | if (nwrite == 0) { 80 | throw std::runtime_error( 81 | std::string("Cannot write ") + std::to_string(cmd->length) + " bytes into container"); 82 | } 83 | break; 84 | } 85 | case COMMAND::size: 86 | { 87 | //printf("SIZE\n"); 88 | fseek(fp, 0L, SEEK_END); 89 | filesize = ftell(fp); 90 | fseek(fp, 0L, SEEK_SET); 91 | int32_t data[4]; 92 | auto *reply = (REPLYCOMMANDSTRUCT*)data; 93 | reply->cmdlen = 16; 94 | reply->id = cmd->id; 95 | memcpy(&reply->data, &filesize, 8); 96 | boost::asio::write(sock, boost::asio::buffer(reply, reply->cmdlen)); 97 | break; 98 | } 99 | 100 | case COMMAND::info: 101 | { 102 | //printf("INFO\n"); 103 | char data[44]; 104 | memset(data, 0, 44); 105 | auto *reply = (REPLYCOMMANDSTRUCT*)data; 106 | reply->cmdlen = 44; 107 | reply->id = cmd->id; 108 | strncpy((char*)&reply->data, "CoverFS Server V 1.0", 36); 109 | boost::asio::write(sock, boost::asio::buffer(reply, reply->cmdlen)); 110 | break; 111 | } 112 | 113 | case COMMAND::close: 114 | { 115 | //printf("CLOSE\n"); 116 | REPLYCOMMANDSTRUCT reply{}; 117 | reply.cmdlen = 8; 118 | reply.id = cmd->id; 119 | boost::asio::write(sock, boost::asio::buffer(&reply, reply.cmdlen)); 120 | break; 121 | } 122 | 123 | } 124 | 125 | } 126 | 127 | void ParseStream(const char *data, int length, ssl_socket &sock, char *commandbuf, int32_t &commandbuflen) 128 | { 129 | for(int i=0; iread_some(boost::asio::buffer(data, max_length), error); 159 | /* 160 | if (error == boost::asio::error::eof) break; // Connection closed cleanly by peer. 161 | else if (error) throw boost::system::system_error(error); // Some other error. 162 | */ 163 | if (error) break; 164 | ParseStream(data, length, *sock, commandbuf, commandbuflen); 165 | } 166 | } 167 | catch (std::exception& e) 168 | { 169 | LOG(LogLevel::ERR) << "Exception in thread: " << e.what(); 170 | } 171 | LOG(LogLevel::INFO) << "Connection closed"; 172 | } 173 | 174 | std::string get_password(std::size_t max_length, boost::asio::ssl::context::password_purpose purpose) 175 | { 176 | char *password = getpass("Password for private key: "); 177 | return std::string(password); 178 | } 179 | 180 | void server(boost::asio::io_service& io_service, unsigned short port) 181 | { 182 | // Create a context that uses the default paths for 183 | // finding CA certificates. 184 | boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); 185 | ctx.set_options( 186 | boost::asio::ssl::context::default_workarounds 187 | | boost::asio::ssl::context::no_sslv2 188 | | boost::asio::ssl::context::single_dh_use); 189 | ctx.set_password_callback(get_password); 190 | try 191 | { 192 | ctx.use_certificate_chain_file("ssl/server.crt"); 193 | ctx.use_private_key_file("ssl/server.key", boost::asio::ssl::context::pem); 194 | ctx.use_tmp_dh_file("ssl/dh1024.pem"); 195 | } catch(...) 196 | { 197 | LOG(LogLevel::ERR) << "Cannot open ssl related files"; 198 | throw std::exception(); 199 | } 200 | 201 | LOG(LogLevel::INFO) << "Start listening on port " << port; 202 | tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port)); 203 | 204 | for (;;) 205 | { 206 | try 207 | { 208 | auto *sock = new ssl_socket(io_service, ctx); 209 | a.accept(sock->lowest_layer()); 210 | LOG(LogLevel::INFO) 211 | << "Connection from '" 212 | << sock->lowest_layer().remote_endpoint().address().to_string() 213 | << "'. Establish SSL connection"; 214 | 215 | sock->handshake(boost::asio::ssl::stream_base::server); 216 | 217 | std::thread(session, sock).detach(); 218 | //session(sock); 219 | } 220 | catch (std::exception& e) 221 | { 222 | LOG(LogLevel::ERR) << "Exception: " << e.what(); 223 | } 224 | catch (...) // No matter what happens, continue 225 | { 226 | LOG(LogLevel::ERR) << "Unknown connection problem. Connection closed"; 227 | } 228 | 229 | } 230 | } 231 | 232 | void PrintUsage(char *argv[]) 233 | { 234 | printf("Usage: %s [port]\n", argv[0]); 235 | printf("The default port is 62000\n"); 236 | } 237 | 238 | int main(int argc, char *argv[]) 239 | { 240 | static_assert(sizeof(COMMANDSTRUCT) == 40, ""); 241 | boost::asio::io_service io_service; 242 | int defaultport = 62000; 243 | 244 | if (argc > 2) 245 | { 246 | PrintUsage(argv); 247 | return 0; 248 | } 249 | if (argc == 2) 250 | { 251 | if (strcmp(argv[1], "--help") == 0) 252 | { 253 | PrintUsage(argv); 254 | return 0; 255 | } 256 | defaultport = std::atoi(argv[1]); 257 | } 258 | 259 | const char filename[] = "cfscontainer"; 260 | fp = fopen(filename, "r+b"); 261 | 262 | if (fp == nullptr) 263 | { 264 | LOG(LogLevel::INFO) << "create new file '" << filename << "'"; 265 | fp = fopen(filename, "wb"); 266 | if (fp == nullptr) 267 | { 268 | LOG(LogLevel::ERR) << "Cannot create file"; 269 | return 1; 270 | } 271 | char data[4096*3] = {0}; 272 | fwrite(data, sizeof(data), 1, fp); 273 | fclose(fp); 274 | fp = fopen(filename, "r+b"); 275 | if (fp == nullptr) 276 | { 277 | LOG(LogLevel::ERR) << "Cannot open file"; 278 | return 1; 279 | } 280 | } 281 | 282 | try 283 | { 284 | server(io_service, defaultport); 285 | } 286 | catch(std::exception &e) 287 | { 288 | LOG(LogLevel::ERR) << e.what(); 289 | } 290 | catch(...) 291 | { 292 | LOG(LogLevel::ERR) << "Unknown exception"; 293 | } 294 | return 0; 295 | } 296 | -------------------------------------------------------------------------------- /src/utils/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "Logger.h" 2 | 3 | #include 4 | #include 5 | 6 | LogLevel Logger::level = LogLevel::INFO; 7 | 8 | Logger::Logger() = default; 9 | 10 | Logger::~Logger() 11 | { 12 | os << std::endl; 13 | std::cout << os.str(); 14 | } 15 | 16 | LogLevel& Logger::GetReporingLevel() 17 | { 18 | return level; 19 | } 20 | 21 | std::ostringstream& Logger::Get(LogLevel level) 22 | { 23 | //os << "- " << NowTime(); 24 | os << " - " << ToString(level) << ": "; 25 | return os; 26 | } 27 | 28 | void Logger::Set(LogLevel newlevel) 29 | { 30 | level = newlevel; 31 | } 32 | 33 | std::string Logger::ToString(LogLevel level) 34 | { 35 | static const char* const buffer[] = {" ERR", "WARN", "INFO", " DBG", "DEEP"}; 36 | return buffer[to_underlying(level)]; 37 | } 38 | -------------------------------------------------------------------------------- /src/utils/Logger.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_H 2 | #define DEBUG_H 3 | 4 | #include 5 | 6 | enum class LogLevel : int {ERR, WARN, INFO, DEBUG, DEEP}; 7 | 8 | class Logger 9 | { 10 | public: 11 | Logger(); 12 | ~Logger(); 13 | 14 | std::ostringstream& Get(LogLevel); 15 | 16 | static LogLevel& GetReporingLevel(); 17 | 18 | void Set(LogLevel newlevel); 19 | 20 | template 21 | static constexpr auto to_underlying(E e) noexcept 22 | { 23 | return static_cast>(e); 24 | } 25 | 26 | 27 | private: 28 | std::string ToString(LogLevel level); 29 | static LogLevel level; 30 | std::ostringstream os; 31 | }; 32 | 33 | #define LOG(level)\ 34 | if (Logger::to_underlying(level) > Logger::to_underlying(Logger::GetReporingLevel())) ;\ 35 | else Logger().Get(level) 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/utils/StringUtils.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | bool EndsWith(std::string const &fullString, std::string const &ending) 5 | { 6 | if (fullString.length() >= ending.length()) 7 | { 8 | return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending)); 9 | } else { 10 | return false; 11 | } 12 | } 13 | 14 | bool StartsWith(std::string const &fullString, std::string const &starting) 15 | { 16 | return !fullString.compare(0, starting.size(), starting); 17 | } 18 | 19 | template 20 | void split(const std::string &s, char delim, Out result) { 21 | std::stringstream ss(s); 22 | std::string item; 23 | while (std::getline(ss, item, delim)) { 24 | *(result++) = item; 25 | } 26 | } 27 | 28 | std::vector split(const std::string &s, char delim) { 29 | std::vector elems; 30 | split(s, delim, std::back_inserter(elems)); 31 | return elems; 32 | } 33 | -------------------------------------------------------------------------------- /src/webapp/CConfigFile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include"CConfigFile.h" 14 | 15 | 16 | CConfigFile::CConfigFile(const std::string& _filename) 17 | { 18 | filename = _filename; 19 | Load(); 20 | } 21 | 22 | void CConfigFile::Load() 23 | { 24 | std::ifstream in(filename.c_str()); 25 | if (!in.is_open()) 26 | { 27 | // error and create new file 28 | Save(); 29 | return; 30 | } 31 | 32 | Poco::XML::InputSource src(in); 33 | Poco::XML::DOMParser parser; 34 | Poco::AutoPtr pDoc = parser.parse(&src); 35 | 36 | Poco::XML::NodeIterator it(pDoc, Poco::XML::NodeFilter::SHOW_ALL); 37 | Poco::XML::Node* pNode = it.nextNode(); 38 | while (pNode) 39 | { 40 | //std::cout << pNode->nodeName() << ":" << pNode->getNodeValue() << std::endl; 41 | pNode = it.nextNode(); 42 | } 43 | } 44 | 45 | void CConfigFile::Save() 46 | { 47 | std::ofstream str(filename + ".temp"); 48 | if (!str.is_open()) 49 | { 50 | // error, just return 51 | return; 52 | } 53 | Poco::XML::XMLWriter writer(str, Poco::XML::XMLWriter::WRITE_XML_DECLARATION | Poco::XML::XMLWriter::PRETTY_PRINT); 54 | writer.setNewLine("\n"); 55 | writer.startDocument(); 56 | writer.startElement("", "configuration", ""); 57 | writer.startElement("", "webinterface", ""); 58 | writer.dataElement("", "host", "", hostname); 59 | writer.dataElement("", "port", "", std::to_string(port)); 60 | writer.endElement("", "webinterface", ""); 61 | writer.dataElement("", "mountpoint", "", mountpoint); 62 | writer.endElement("", "configuration", ""); 63 | writer.endDocument(); 64 | str.close(); 65 | 66 | int fd = open((filename + ".temp").c_str(), O_APPEND); 67 | fsync(fd); 68 | close(fd); 69 | 70 | rename((filename + ".temp").c_str(), filename.c_str()); 71 | } 72 | /* 73 | int main() 74 | { 75 | CConfigFile config("CoverFS.config"); 76 | config.Save(); 77 | 78 | return 0; 79 | } 80 | */ 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/webapp/CConfigFile.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class CConfigFile 4 | { 5 | public: 6 | explicit CConfigFile(const std::string& _filename); 7 | void Load(); 8 | void Save(); 9 | 10 | std::string hostname = "localhost"; 11 | int port = 1234; 12 | std::string mountpoint = "w:"; 13 | 14 | private: 15 | std::string filename; 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /src/webapp/CoverFS.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | localhost 5 | 1234 6 | 7 | w: 8 | 9 | -------------------------------------------------------------------------------- /src/webapp/webapp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include"CConfigFile.h" 14 | #include"../utils/StringUtils.h" 15 | #include"../interface/CFSHandler.h" 16 | 17 | static CFSHandler *handler; 18 | 19 | // compile with g++ main.cpp CConfigFile.cpp -lPocoNet -lPocoUtil -lPocoFoundation -lPocoXML 20 | 21 | class CStatusbar { 22 | public: 23 | std::string status, message; 24 | CStatusbar(std::string _status, std::string _message) : status(std::move(_status)), message(std::move(_message)) {} 25 | }; 26 | 27 | CConfigFile configfile("CoverFS.config"); 28 | std::vector statusbar; 29 | 30 | class RequestHandler : public Poco::Net::HTTPRequestHandler 31 | { 32 | public: 33 | 34 | void handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override; 35 | 36 | private: 37 | 38 | void SendFile(const std::string& filename, std::ostream& out) 39 | { 40 | std::ifstream ifs(filename.c_str()); 41 | if (!ifs.is_open()) return; 42 | out << ifs.rdbuf(); 43 | } 44 | 45 | }; 46 | 47 | void RequestHandler::handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) { 48 | 49 | std::cout << " URI=" << req.getURI() << std::endl; 50 | std::vector paths = split(req.getURI(), '/'); 51 | std::vector parameters; 52 | std::vector lastpathsplit = split(paths.back(), '?'); 53 | 54 | if (lastpathsplit.size() == 2) 55 | { 56 | paths.back() = lastpathsplit.front(); 57 | parameters = split(lastpathsplit.back(), '&'); 58 | std::cout << parameters.size() << std::endl; 59 | } 60 | 61 | if ((paths.size() == 3) && (paths[1] == "css")) 62 | { 63 | resp.setStatus(Poco::Net::HTTPResponse::HTTP_OK); 64 | resp.setContentType("text/css"); 65 | std::ostream& out = resp.send(); 66 | SendFile(std::string("templates/css/") + paths[2], out); 67 | out.flush(); 68 | } else 69 | if ((paths.size() == 3) && (paths[1] == "js")) 70 | { 71 | resp.setStatus(Poco::Net::HTTPResponse::HTTP_OK); 72 | resp.setContentType("text/javascript"); 73 | std::ostream& out = resp.send(); 74 | SendFile(std::string("templates/js/") + paths[2], out); 75 | out.flush(); 76 | } else 77 | if ((paths.size() == 3) && (paths[1] == "ajax")) 78 | { 79 | resp.setStatus(Poco::Net::HTTPResponse::HTTP_OK); 80 | resp.setContentType("application/json"); 81 | std::ostream& out = resp.send(); 82 | if (paths[2] == "status") 83 | { 84 | out << "{"; 85 | out << R"("downloadrate" : ")" << (rand()%50) << " MB/s\","; 86 | out << R"("uploadrate" : ")" << (rand()%50) << " MB/s\""; 87 | /* 88 | cachedblocks 89 | writecache 90 | ncommits 91 | ninodes 92 | fragments 93 | fragmentation 94 | containersize 95 | emptyspace 96 | */ 97 | out << "}"; 98 | } 99 | if (paths[2] == "log") 100 | { 101 | out << "{}"; 102 | } 103 | if (paths[2] == "mount") 104 | { 105 | statusbar.emplace_back("success", "Container mounted on W:"); 106 | out << "{}"; 107 | } 108 | if (paths[2] == "scan") 109 | { 110 | statusbar.emplace_back("success", "Scan started. Please consult the log for more details"); 111 | out << "{}"; 112 | } 113 | if (paths[2] == "optimize") 114 | { 115 | statusbar.emplace_back("danger", "Optimize destroyed your container"); 116 | out << "{}"; 117 | } 118 | if (paths[2] == "shrink") 119 | { 120 | statusbar.emplace_back("info", "Sorry, Shrink is not yet supported"); 121 | out << "{}"; 122 | } 123 | if (paths[2] == "statusbar") 124 | { 125 | out << "{"; 126 | if (!statusbar.empty()) 127 | { 128 | out << R"("status" : ")" << statusbar[0].status << "\","; 129 | out << R"("message" : ")" << statusbar[0].message << "\""; 130 | statusbar.erase(statusbar.begin()); 131 | } 132 | out << "}"; 133 | } 134 | if ((paths[2] == "config") && (parameters.size() == 4)) 135 | { 136 | std::cout << parameters[0] << std::endl; 137 | std::cout << configfile.hostname << std::endl; 138 | out << "{"; 139 | out << R"("host" : ")" << configfile.hostname << "\","; 140 | out << R"("port" : ")" << configfile.port << "\","; 141 | out << R"("mountpoint" : ")" << configfile.mountpoint << "\""; 142 | out << "}"; 143 | } 144 | out.flush(); 145 | } else 146 | if ((paths.size() == 2) && (EndsWith(paths[1], ".html"))) 147 | { 148 | resp.setStatus(Poco::Net::HTTPResponse::HTTP_OK); 149 | resp.setContentType("text/html"); 150 | std::ostream& out = resp.send(); 151 | SendFile("templates/header.html", out); 152 | 153 | std::string filename = split(paths[1], '.')[0]; 154 | std::transform(filename.begin(), filename.end(), filename.begin(), ::tolower); 155 | out << ")"; 157 | 158 | SendFile(std::string("templates/") + paths[1], out); 159 | SendFile("templates/footer.html", out); 160 | out.flush(); 161 | } else 162 | if (paths.size() == 1) 163 | { 164 | resp.redirect("configuration.html"); 165 | resp.send(); 166 | } else 167 | { 168 | resp.setStatus(Poco::Net::HTTPResponse::HTTP_NOT_FOUND); 169 | resp.setContentType("text/html"); 170 | std::ostream& out = resp.send(); 171 | out << "

404 not found

"; 172 | out.flush(); 173 | } 174 | } 175 | 176 | class HandlerFactory : public Poco::Net::HTTPRequestHandlerFactory 177 | { 178 | public: 179 | HandlerFactory () = default; 180 | 181 | Poco::Net::HTTPRequestHandler* createRequestHandler (const Poco::Net::HTTPServerRequest &request) override { 182 | return new RequestHandler(); 183 | } 184 | }; 185 | 186 | 187 | class SimpleHTTPServerApplication : public Poco::Util::ServerApplication 188 | { 189 | protected: 190 | int main(const std::vector &args) override { 191 | Poco::UInt16 port = 9999; 192 | Poco::Net::ServerSocket socket(port); 193 | auto *pParams = new Poco::Net::HTTPServerParams(); 194 | 195 | Poco::Net::HTTPServer server(new HandlerFactory(), socket, pParams); 196 | 197 | server.start(); 198 | waitForTerminationRequest(); 199 | server.stop(); 200 | return EXIT_OK; 201 | } 202 | }; 203 | 204 | int StartWebApp(CFSHandler &_handler) 205 | { 206 | handler = &_handler; 207 | int argc = 1; 208 | const char* argv_const[] = {"CoverFS", nullptr}; 209 | char **argv = const_cast(argv_const); 210 | 211 | try 212 | { 213 | SimpleHTTPServerApplication app; 214 | return app.run(argc, argv); 215 | } 216 | catch (Poco::Exception& exc) 217 | { 218 | std::cerr << exc.displayText() << std::endl; 219 | return Poco::Util::Application::EXIT_SOFTWARE; 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/webapp/webapp.h: -------------------------------------------------------------------------------- 1 | #ifndef WEBAPP_H 2 | #define WEBAPP_H 3 | 4 | #include"../interface/CFSHandler.h" 5 | 6 | int StartWebApp(CFSHandler &_handler); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /ssl/dh1024.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIGHAoGBAKzDXnL88NFHpHH6eIMgWt576z1QPU9e05VhGg0VLoLxMCvkoZfZHqmK 3 | cfpazjsk5BQch03aKApf5NqxFmQxHiBQCZl5M5zKl344X+gmstTW/3ZR/zVIKGRs 4 | IoWdFEANWJUCqUagShbBcHy5CqXtLLHHT94UMLSzp8qcdMTk2jjLAgEC 5 | -----END DH PARAMETERS----- 6 | -------------------------------------------------------------------------------- /ssl/gen.sh: -------------------------------------------------------------------------------- 1 | rm server* 2 | rm dh1024.pem 3 | rm openssl.cnf 4 | 5 | set -e 6 | 7 | #Generate a private key without password 8 | #openssl genrsa -aes128 -passout pass:abcd -out server.key 2048 9 | openssl genrsa -out server.key 2048 10 | 11 | #Generate Certificate signing request 12 | 13 | echo " 14 | [ req ] 15 | distinguished_name = req_distinguished_name 16 | prompt = no 17 | 18 | [ req_distinguished_name ] 19 | commonName = CoverFS 20 | " > openssl.cnf 21 | 22 | openssl req -new -config openssl.cnf -key server.key -out server.csr 23 | 24 | 25 | #Sign certificate with private key 26 | openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt 27 | 28 | 29 | #Remove password requirement (needed for example) 30 | #cp server.key server.key.secure 31 | #openssl rsa -in server.key.secure -out server.key 32 | 33 | #Generate dhparam file 34 | openssl dhparam -out dh1024.pem 1024 35 | -------------------------------------------------------------------------------- /ssl/openssl.cnf: -------------------------------------------------------------------------------- 1 | 2 | [ req ] 3 | distinguished_name = req_distinguished_name 4 | prompt = no 5 | 6 | [ req_distinguished_name ] 7 | commonName = CoverFS 8 | 9 | -------------------------------------------------------------------------------- /ssl/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICoDCCAYgCCQDAaEjxyam8XDANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdD 3 | b3ZlckZTMB4XDTE2MDExNTIyMjY1NVoXDTI2MDExMjIyMjY1NVowEjEQMA4GA1UE 4 | AwwHQ292ZXJGUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANLyhiiG 5 | Wbr9Ls7lfKuEdtzNhhf5dS/NV2eEQGPZf4RbwXxwVhg/wplIuSoHCE6i4rpZHF0s 6 | 5rjge2cp3vwl7NyhExWa/2aqvBgafylUqHpzxb+DnNyoPlUhCrW5RBcjWnDL83cJ 7 | hVUMq1GtvqWg0b++eDBVMCBjHxBwxn+/5k65cKriBl3cV/RdcPfvNTarseNQBQoR 8 | +DIbizQrSzerS2XXzxlo8Wln6wLgK1dfKPnkwqArKfovaRgVhPhp2aqPoy+IT/zp 9 | TU8mjvJMvs0pWh9jhopzLhBPb6nhWdBMgrvB3jFssc+NsLmVLXuD7q2jLFhreN3r 10 | g7ISrRpIUnIqftMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAhG9TtbybFp0He00a 11 | vYfKjBNCy/z7/iVLvOnfcIuVF0LQaYzmINpoN4rBhorNMOeEgSmC1lqdSFZdlQyJ 12 | KuJr1xlbmW2bmJHIRxOoyp8PEaUsGn+hMnsgOI1GFzSgXHjS0cyav8Gy6BKtfimj 13 | PZDsMAlCiCsbNw9sJuHfm8Ehxvo7dKqz41uW3zjvZv3gYLJ2pMm5qHZgYWkhi5Ht 14 | nQxtDXaq1fA4K162c4wi2TKe0btx4a2tzDyRPbsYFQngNFiecYjUK9zugPjmu6IM 15 | 6BApfep4/wE+3YNhVP2+PRx3VfDTT35X3tSMOWnR2WU+FJcK40OIulJcMMzV8VM2 16 | zcDtkw== 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /ssl/server.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICVzCCAT8CAQAwEjEQMA4GA1UEAwwHQ292ZXJGUzCCASIwDQYJKoZIhvcNAQEB 3 | BQADggEPADCCAQoCggEBANLyhiiGWbr9Ls7lfKuEdtzNhhf5dS/NV2eEQGPZf4Rb 4 | wXxwVhg/wplIuSoHCE6i4rpZHF0s5rjge2cp3vwl7NyhExWa/2aqvBgafylUqHpz 5 | xb+DnNyoPlUhCrW5RBcjWnDL83cJhVUMq1GtvqWg0b++eDBVMCBjHxBwxn+/5k65 6 | cKriBl3cV/RdcPfvNTarseNQBQoR+DIbizQrSzerS2XXzxlo8Wln6wLgK1dfKPnk 7 | wqArKfovaRgVhPhp2aqPoy+IT/zpTU8mjvJMvs0pWh9jhopzLhBPb6nhWdBMgrvB 8 | 3jFssc+NsLmVLXuD7q2jLFhreN3rg7ISrRpIUnIqftMCAwEAAaAAMA0GCSqGSIb3 9 | DQEBCwUAA4IBAQAvD6vVA/eahr68NhcN4useRO+iUjUDDu0wfqMt6OvhJZWpBjEl 10 | d8sUPyXjCUVaQY1cpF0n/XUOqzBSJhDkZswnMYxchNhg6ZhKDNm09M73Sl96Yq3I 11 | obB8V2nnQV20qj5dNWRXr/VeBJqx78IegQjiCncQROD4kpZ4/8sQ2Pvk2/7tyBJV 12 | 2VjIF7sn4S5RhtMJ3rQs3/arCYDnttoW7fFW5092Z9VY8OrhEjy+AucynqoVpFUE 13 | 4CqMcQBCL6vrmbu30vlvqzhs39Mk1Epf6w77ih0FkS7fCjYMqUWANXeflUF3nB5Q 14 | TtXrfM2V5lqdpz9SfeLVVQAc11180aqyv56G 15 | -----END CERTIFICATE REQUEST----- 16 | -------------------------------------------------------------------------------- /ssl/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA0vKGKIZZuv0uzuV8q4R23M2GF/l1L81XZ4RAY9l/hFvBfHBW 3 | GD/CmUi5KgcITqLiulkcXSzmuOB7Zyne/CXs3KETFZr/Zqq8GBp/KVSoenPFv4Oc 4 | 3Kg+VSEKtblEFyNacMvzdwmFVQyrUa2+paDRv754MFUwIGMfEHDGf7/mTrlwquIG 5 | XdxX9F1w9+81Nqux41AFChH4MhuLNCtLN6tLZdfPGWjxaWfrAuArV18o+eTCoCsp 6 | +i9pGBWE+GnZqo+jL4hP/OlNTyaO8ky+zSlaH2OGinMuEE9vqeFZ0EyCu8HeMWyx 7 | z42wuZUte4PuraMsWGt43euDshKtGkhScip+0wIDAQABAoIBADBfFIxuYl0SeY1P 8 | 6kqaUXdIWZtdxJV1jLlcBjffQ/Jh5/hU+ikNVd44Yt1UR39gsoTwsiRbi3yRXTrG 9 | yy8eszXUab/mjvJH7GHKkaY0l32c1peX4nxmyARVU1NgbFCx9qcu3WFKeZyLDy3n 10 | nXP1cKN7VawfnK2QjSsD8UCSDIm4aZ2ZHXyCHp4HJ2VL4avnM3jDlS1DI2WpbZpU 11 | Gt3zOhyR9wSWdeL2St5KwBg2OETk0sZxezwIjU6yaw3ZpVpOWlowGsXPetKxCKP/ 12 | XMY9eP7bMIgpnp50io0SzapM7L1eAUg9hg6ojbsYFGSGQDpxRGcfkEutSYcx9kb7 13 | PXrXE6ECgYEA6dnEZyj+F3C43V1vHXnql2qOtmk8I8l+ck3BSGSXoP9Fp6ViSPF1 14 | Ef3L+GMYq6OAG0wqUSbya7U6QdmLdCXixZPhkucZexZ+n+QEIZ/jZSq6lcRHcYOs 15 | th2P/41DGAq5oSiYVnsMNi+RpkQWldVDFPlywB0+RuOvDcs6m1JMVF0CgYEA5u1q 16 | S14H9+AChEOz9uXT2jd+XHI49h/CLXt5Y+NlBepZ8jFcRGpixQuGSsCngxOHnWRr 17 | qTztG4Q/39Y4Wq9V6JG6r+bTSRZz0YipfsJkbaAHDTMFZQ6XiGRdb0xT6NjHZIRj 18 | AG3PJqpZZIXyaR5lsspcJacHgHXieREFU4mK7O8CgYA9pfAV9gOOMGQ7z07kqWhD 19 | xI6c3f9Bu/O+tGrY59PlWIaHXJ0dd7ISLSMhdxZg4Th7ecfKHwdXh640/+G4m+g9 20 | h++2p3/bKCH3isfgCWOMHwiTROxEq57TX9W/XAEtDF7Fcos+eS/N9Rpjh52goFkP 21 | 5Xbv2IW7cHiMnV/05GxE7QKBgQDlL83l3P4FiaKVyGfM645VrevQLmDQDPb3kusI 22 | Mv/pXgxE7a5IDFnYfDac7BWUZoaas7aSMXCVday7J22ouwmFF1T0DR+3EvyBgaPO 23 | tXlcv40gEXoSMOg9qnZ85oEEwFksLqPfIhyMoFa2CKZso4mFZ4cKq3oriVPqmfTy 24 | Uri5qwKBgAe+LNiwux4pMi3i25TREZoD98mq+3Pzf5BdMVn44tcRDqOl2/Kd0rwh 25 | rycakLqBrIRzX6Sym2p5PUPi9jxA2ZX4RiTQnkPLeqshJDqtw6wU9wQKfG+Zgjpo 26 | LxO9dZFggcbQnnkfgnPhQ/lQOXhvorWk/XwrMs9cspUYsb2oPbiz 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /templates/configuration.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |

Configuration

6 |
7 |
8 | 9 |
10 |
11 |
12 |

Mount

13 |
14 |
15 |
16 |
17 | 18 | 19 | e.g. "localhost" 20 |
21 |
22 | 23 | 24 | Default port: 1234 25 |
26 |
27 | 28 | 29 | e.g. Drive Letter "H:" 30 |
31 |
32 | 33 | 34 | 8 characters or more 35 |
36 |
37 | 38 | 39 |
40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /templates/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | } 4 | 5 | svg { 6 | width: 20px; 7 | height: 20px; 8 | } 9 | 10 | /* footer */ 11 | /* 12 | #footer { 13 | background: #fd680e; 14 | padding: 20px 0 5px; 15 | position: absolute; 16 | left: 0; 17 | right: 0; 18 | width: 100%; 19 | height: 50px; 20 | } 21 | */ 22 | 23 | #footer { 24 | position: fixed; 25 | left: 0; 26 | bottom: 0; 27 | width: 100%; 28 | height: 20px; 29 | background-color: #fd680e; 30 | } 31 | 32 | .alert-fixed { 33 | margin-bottom: 0px; 34 | /* 35 | width: 100%; 36 | position: fixed; 37 | */ 38 | } 39 | -------------------------------------------------------------------------------- /templates/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s-macke/CoverFS/1720c5892a2dbb7c3bc8b4f3b3c95e7274318a11/templates/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /templates/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s-macke/CoverFS/1720c5892a2dbb7c3bc8b4f3b3c95e7274318a11/templates/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /templates/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s-macke/CoverFS/1720c5892a2dbb7c3bc8b4f3b3c95e7274318a11/templates/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /templates/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s-macke/CoverFS/1720c5892a2dbb7c3bc8b4f3b3c95e7274318a11/templates/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /templates/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | CoverFS Web Interface 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 47 | 48 |
49 |
50 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /templates/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /templates/log.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |

Log

6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
LevelTimeMessage
Info01.01.2017 20:00:00This is a very long text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
Debug01.01.2017 20:00:00This is text
Warn01.01.2017 20:00:00This is text
Error01.01.2017 20:00:00This is text
42 |
43 |
44 |
45 | 46 |
47 |
48 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /templates/status.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Status

5 |
6 |
7 |
8 |
9 |

10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |

STATUS

StatusMounted

NETWORK

Download rate10 MB/s
Upload rate1 MB/s
Host:Portdomain.dev:1234

CACHE

Blocks (4096 Bytes)123
Write Cache10 MB
Decrypted Blocks1
Commits in queue5

FILESYSTEM

Open inodes8
Number of inodes48678
Fragments48678
Fragmentation0.1%

CONTAINER

Size42 GB
Empty space at end1.3 GB
MountpointX:
87 |

88 |
89 |
90 | 91 | 92 | 93 | 94 | 95 | 124 | 125 | 126 |
127 | -------------------------------------------------------------------------------- /tests/checkfragment.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define MAXSIZE 0xFFFFF 12 | 13 | // ---------------------- 14 | 15 | typedef struct 16 | { 17 | int fd{}; 18 | char filename[256]{}; 19 | int size{}; 20 | std::mutex mtx; 21 | char data[MAXSIZE+2]{}; 22 | } FSTRUCT; 23 | 24 | FSTRUCT *files; 25 | unsigned int niter = 2000; 26 | unsigned int nfiles = 10; 27 | unsigned int nthreads = 10; 28 | 29 | unsigned int g_seed = 0x0; 30 | 31 | inline int fastrand() 32 | { 33 | g_seed = (214013*g_seed+2531011); 34 | return (g_seed>>16)&0x7FFF; 35 | } 36 | 37 | // ---------------------- 38 | 39 | size_t fsize(int fd) 40 | { 41 | struct stat st{}; 42 | if(fstat(fd, &st) != 0) { 43 | return 0; 44 | } 45 | return st.st_size; 46 | } 47 | 48 | void Execute(int tid) 49 | { 50 | auto *data = new char[MAXSIZE+2]; 51 | ssize_t retsize; 52 | 53 | //printf("thread %i:\n", tid); 54 | for(unsigned int iter=0; iter 0) ofs = rand() % files[id].size; 61 | int newsize = rand() & MAXSIZE; 62 | if (ofs+newsize > MAXSIZE) newsize = MAXSIZE - ofs - 1; 63 | if (newsize < 0) newsize = 0; 64 | 65 | //printf("cmd=%i id=%i\n", cmd, id); 66 | switch(cmd) 67 | { 68 | case 0: // Truncate 69 | newsize = rand() & MAXSIZE; 70 | printf("tid %1i %5i: Truncate %i size=%i\n", tid, iter, id, newsize); 71 | if (newsize > files[id].size) 72 | if (newsize > files[id].size) 73 | { 74 | memset(&(files[id].data[ files[id].size ]), 0, newsize-files[id].size); 75 | } 76 | files[id].size = newsize; 77 | if (ftruncate(files[id].fd, files[id].size) != 0) 78 | { 79 | perror("Error during truncate"); 80 | exit(1); 81 | } 82 | break; 83 | 84 | case 1: // write 85 | printf("tid %1i %5i: write %i ofs=%i size=%i\n", tid, iter, id, ofs, newsize); 86 | for(int i=0; i files[id].size) files[id].size = ofs+newsize; 110 | break; 111 | 112 | case 2: // read 113 | printf("tid %1i %5i: read %i ofs=%i size=%i\n", tid, iter, id, ofs, newsize); 114 | if (ofs+newsize > files[id].size) newsize = files[id].size - ofs - 1; 115 | if (newsize < 0) newsize = 0; 116 | retsize = 0; 117 | do 118 | { 119 | ssize_t ret = lseek(files[id].fd, ofs, SEEK_SET); 120 | if (ret < 0) 121 | { 122 | perror("Error during seek"); 123 | exit(1); 124 | } 125 | 126 | ret = read(files[id].fd, &data[retsize], newsize-retsize); 127 | if (ret < 0) 128 | { 129 | perror("Error during read"); 130 | exit(1); 131 | } 132 | retsize += ret; 133 | } while(retsize < newsize); 134 | assert(retsize == newsize); 135 | for(int i=0; i