├── .github └── workflows │ └── build.yml ├── .gitmodules ├── CMakeLists.txt ├── CMakeSettings.json ├── LICENCE ├── README.md ├── btrfs-dump.pl ├── mingw-amd64.cmake ├── mingw-x86.cmake ├── msvc-aarch64.cmake ├── msvc-amd64.cmake ├── msvc-armv7.cmake ├── msvc-x86.cmake ├── send-dump.pl └── src ├── balance.c ├── blake2-impl.h ├── blake2b-ref.c ├── boot.c ├── btrfs-vol.inf ├── btrfs.c ├── btrfs.cdf ├── btrfs.h ├── btrfs.inf ├── btrfs.rc.in ├── btrfs_drv.h ├── btrfsioctl.h ├── cache.c ├── calcthread.c ├── compress.c ├── crc32c-aarch64.asm ├── crc32c-gas.S ├── crc32c-masm.asm ├── crc32c.c ├── crc32c.h ├── create.c ├── devctrl.c ├── dirctrl.c ├── extent-tree.c ├── fastio.c ├── fileinfo.c ├── flushthread.c ├── free-space.c ├── fsctl.c ├── fsrtl.c ├── galois.c ├── mkbtrfs ├── mkbtrfs.c ├── mkbtrfs.rc.in └── resource.h ├── pnp.c ├── read.c ├── registry.c ├── reparse.c ├── resource.h ├── scrub.c ├── search.c ├── security.c ├── send.c ├── sha256.c ├── shellext ├── balance.cpp ├── balance.h ├── contextmenu.cpp ├── contextmenu.h ├── devices.cpp ├── devices.h ├── factory.cpp ├── factory.h ├── iconoverlay.cpp ├── iconoverlay.h ├── main.cpp ├── mappings.cpp ├── mountmgr.cpp ├── mountmgr.h ├── propsheet.cpp ├── propsheet.h ├── recv.cpp ├── recv.h ├── resource.h ├── scrub.cpp ├── scrub.h ├── send.cpp ├── send.h ├── shellbtrfs.def ├── shellbtrfs.manifest ├── shellbtrfs.rc.in ├── shellext.h ├── subvol.ico ├── subvol.svg ├── volpropsheet.cpp └── volpropsheet.h ├── tests ├── create.cpp ├── cs.cpp ├── delete.cpp ├── ea.cpp ├── fileinfo.cpp ├── io.cpp ├── links.cpp ├── manifest.xml ├── mmap.cpp ├── oplock.cpp ├── overwrite.cpp ├── rename.cpp ├── reparse.cpp ├── security.cpp ├── streams.cpp ├── supersede.cpp ├── test.cpp ├── test.h └── test.rc.in ├── treefuncs.c ├── ubtrfs ├── resource.h ├── ubtrfs.c ├── ubtrfs.def └── ubtrfs.rc.in ├── volume.c ├── worker-thread.c ├── write.c ├── xor-gas.S ├── xor-masm.asm └── zstd-shim.h /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [push] 3 | env: 4 | PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/etc/eselect/wine/bin 5 | jobs: 6 | cmake: 7 | runs-on: msvc-wine 8 | container: 9 | volumes: 10 | - /var/run/pcscd/pcscd.comm:/var/run/pcscd/pcscd.comm 11 | steps: 12 | - run: echo "SHORT_SHA=`echo ${{ github.sha }} | cut -c1-8`" >> $GITHUB_ENV 13 | - run: git clone --recurse-submodules -j`nproc` ${{ github.server_url }}/${{ github.repository }} ${SHORT_SHA} 14 | - run: cd ${SHORT_SHA} && git checkout ${{ github.sha }} 15 | - run: mkdir -p build/debug/{amd64,x86,aarch64,arm} 16 | - run: mkdir -p build/release/{amd64,x86,aarch64,arm} 17 | - run: mkdir -p build/pdb/{debug,release}/{amd64,x86,aarch64,arm} 18 | - run: cmake -DCMAKE_TOOLCHAIN_FILE=msvc-amd64.cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_TEST=OFF -S ${SHORT_SHA} -B build/debug/amd64 && cmake --build build/debug/amd64 --parallel `nproc` 19 | - run: cmake -DCMAKE_TOOLCHAIN_FILE=msvc-x86.cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_TEST=OFF -S ${SHORT_SHA} -B build/debug/x86 && cmake --build build/debug/x86 --parallel `nproc` 20 | - run: cmake -DCMAKE_TOOLCHAIN_FILE=msvc-aarch64.cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_TEST=OFF -S ${SHORT_SHA} -B build/debug/aarch64 && cmake --build build/debug/aarch64 --parallel `nproc` 21 | - run: cmake -DCMAKE_TOOLCHAIN_FILE=msvc-armv7.cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_TEST=OFF -S ${SHORT_SHA} -B build/debug/arm && cmake --build build/debug/arm --parallel `nproc` 22 | - run: cmake -DCMAKE_TOOLCHAIN_FILE=msvc-amd64.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_TEST=OFF -S ${SHORT_SHA} -B build/release/amd64 && cmake --build build/release/amd64 --parallel `nproc` 23 | - run: cmake -DCMAKE_TOOLCHAIN_FILE=msvc-x86.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_TEST=OFF -S ${SHORT_SHA} -B build/release/x86 && cmake --build build/release/x86 --parallel `nproc` 24 | - run: cmake -DCMAKE_TOOLCHAIN_FILE=msvc-aarch64.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_TEST=OFF -S ${SHORT_SHA} -B build/release/aarch64 && cmake --build build/release/aarch64 --parallel `nproc` 25 | - run: cmake -DCMAKE_TOOLCHAIN_FILE=msvc-armv7.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_TEST=OFF -S ${SHORT_SHA} -B build/release/arm && cmake --build build/release/arm --parallel `nproc` 26 | - run: mv build/debug/amd64/*.pdb build/pdb/debug/amd64/ 27 | - run: mv build/debug/x86/*.pdb build/pdb/debug/x86/ 28 | - run: mv build/debug/aarch64/*.pdb build/pdb/debug/aarch64/ 29 | - run: mv build/debug/arm/*.pdb build/pdb/debug/arm/ 30 | - run: mv build/release/amd64/*.pdb build/pdb/release/amd64/ 31 | - run: mv build/release/x86/*.pdb build/pdb/release/x86/ 32 | - run: mv build/release/aarch64/*.pdb build/pdb/release/aarch64/ 33 | - run: mv build/release/arm/*.pdb build/pdb/release/arm/ 34 | - run: cp ${SHORT_SHA}/src/{btrfs,btrfs-vol}.inf build/debug/ 35 | - run: cp ${SHORT_SHA}/src/{btrfs,btrfs-vol}.inf build/release/ 36 | - run: stampinf -f build/debug/btrfs.inf -d \* -v \* 37 | - run: stampinf -f build/debug/btrfs-vol.inf -d \* -v \* 38 | - run: stampinf -f build/release/btrfs.inf -d \* -v \* 39 | - run: stampinf -f build/release/btrfs-vol.inf -d \* -v \* 40 | - run: cd build/debug && makecat ../../${SHORT_SHA}/src/btrfs.cdf 41 | - run: cd build/release && makecat ../../${SHORT_SHA}/src/btrfs.cdf 42 | - env: 43 | CERTIFICATE: ${{ secrets.CERTIFICATE }} 44 | run: echo "${CERTIFICATE}" > codesigning.crt 45 | - env: 46 | PKCS11CERT: ${{ secrets.PKCS11CERT }} 47 | PKCS11KEY: ${{ secrets.PKCS11KEY }} 48 | run: for i in build/{debug,release}/btrfs.cat; do osslsigncode sign -pkcs11module /usr/lib64/libcrypto3PKCS.so -pkcs11cert "${PKCS11CERT}" -key "${PKCS11KEY}" -certs codesigning.crt -t http://timestamp.digicert.com -in $i -out tmp && mv tmp $i; done 49 | - env: 50 | PKCS11CERT: ${{ secrets.PKCS11CERT }} 51 | PKCS11KEY: ${{ secrets.PKCS11KEY }} 52 | run: for i in build/{debug,release}/{amd64,x86,aarch64,arm}/{btrfs.sys,mkbtrfs.exe,shellbtrfs.dll,ubtrfs.dll}; do osslsigncode sign -pkcs11module /usr/lib64/libcrypto3PKCS.so -pkcs11cert "${PKCS11CERT}" -key "${PKCS11KEY}" -certs codesigning.crt -t http://timestamp.digicert.com -ph -in $i -out tmp && mv tmp $i; done 53 | - uses: actions/upload-artifact@v3 54 | with: 55 | name: ${{ github.sha }} 56 | overwrite: true 57 | path: | 58 | build/**/btrfs.sys 59 | build/**/mkbtrfs.exe 60 | build/**/shellbtrfs.dll 61 | build/**/ubtrfs.dll 62 | build/**/*.inf 63 | build/**/*.cat 64 | build/pdb 65 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/zstd"] 2 | path = src/zstd 3 | url = https://github.com/facebook/zstd 4 | [submodule "src/zlib"] 5 | path = src/zlib 6 | url = https://github.com/madler/zlib 7 | -------------------------------------------------------------------------------- /CMakeSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "x64-Debug", 5 | "generator": "Ninja", 6 | "configurationType": "Debug", 7 | "buildRoot": "${projectDir}\\out\\build\\${name}", 8 | "installRoot": "${projectDir}\\out\\install\\${name}", 9 | "cmakeCommandArgs": "", 10 | "buildCommandArgs": "-v", 11 | "ctestCommandArgs": "", 12 | "inheritEnvironments": [ "msvc_x64_x64" ], 13 | "variables": [] 14 | }, 15 | { 16 | "name": "x86-Debug", 17 | "generator": "Ninja", 18 | "configurationType": "Debug", 19 | "buildRoot": "${projectDir}\\out\\build\\${name}", 20 | "installRoot": "${projectDir}\\out\\install\\${name}", 21 | "cmakeCommandArgs": "", 22 | "buildCommandArgs": "-v", 23 | "ctestCommandArgs": "", 24 | "inheritEnvironments": [ "msvc_x86_x64" ], 25 | "variables": [] 26 | }, 27 | { 28 | "name": "arm-Debug", 29 | "generator": "Ninja", 30 | "configurationType": "Debug", 31 | "buildRoot": "${projectDir}\\out\\build\\${name}", 32 | "installRoot": "${projectDir}\\out\\install\\${name}", 33 | "cmakeCommandArgs": "", 34 | "buildCommandArgs": "-v", 35 | "ctestCommandArgs": "", 36 | "inheritEnvironments": [ "msvc_arm_x64" ], 37 | "variables": [] 38 | }, 39 | { 40 | "name": "arm64-Debug", 41 | "generator": "Ninja", 42 | "configurationType": "Debug", 43 | "buildRoot": "${projectDir}\\out\\build\\${name}", 44 | "installRoot": "${projectDir}\\out\\install\\${name}", 45 | "cmakeCommandArgs": "", 46 | "buildCommandArgs": "-v", 47 | "ctestCommandArgs": "", 48 | "inheritEnvironments": [ "msvc_arm64_x64" ], 49 | "variables": [] 50 | }, 51 | { 52 | "name": "x64-Release", 53 | "generator": "Ninja", 54 | "configurationType": "RelWithDebInfo", 55 | "buildRoot": "${projectDir}\\out\\build\\${name}", 56 | "installRoot": "${projectDir}\\out\\install\\${name}", 57 | "cmakeCommandArgs": "", 58 | "buildCommandArgs": "-v", 59 | "ctestCommandArgs": "", 60 | "inheritEnvironments": [ "msvc_x64_x64" ], 61 | "variables": [] 62 | }, 63 | { 64 | "name": "x86-Release", 65 | "generator": "Ninja", 66 | "configurationType": "RelWithDebInfo", 67 | "buildRoot": "${projectDir}\\out\\build\\${name}", 68 | "installRoot": "${projectDir}\\out\\install\\${name}", 69 | "cmakeCommandArgs": "", 70 | "buildCommandArgs": "-v", 71 | "ctestCommandArgs": "", 72 | "inheritEnvironments": [ "msvc_x86_x64" ], 73 | "variables": [] 74 | }, 75 | { 76 | "name": "arm-Release", 77 | "generator": "Ninja", 78 | "configurationType": "RelWithDebInfo", 79 | "buildRoot": "${projectDir}\\out\\build\\${name}", 80 | "installRoot": "${projectDir}\\out\\install\\${name}", 81 | "cmakeCommandArgs": "", 82 | "buildCommandArgs": "-v", 83 | "ctestCommandArgs": "", 84 | "inheritEnvironments": [ "msvc_arm_x64" ], 85 | "variables": [] 86 | }, 87 | { 88 | "name": "arm64-Release", 89 | "generator": "Ninja", 90 | "configurationType": "RelWithDebInfo", 91 | "buildRoot": "${projectDir}\\out\\build\\${name}", 92 | "installRoot": "${projectDir}\\out\\install\\${name}", 93 | "cmakeCommandArgs": "", 94 | "buildCommandArgs": "-v", 95 | "ctestCommandArgs": "", 96 | "inheritEnvironments": [ "msvc_arm64_x64" ], 97 | "variables": [] 98 | } 99 | ] 100 | } 101 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /mingw-amd64.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # To Cross-compile, use: 3 | # cmake -DCMAKE_TOOLCHAIN_FILE=../mingw.cmake .. 4 | # 5 | # the name of the target operating system 6 | SET(CMAKE_SYSTEM_NAME Windows) 7 | 8 | # which compilers to use for C and C++ 9 | SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) 10 | SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) 11 | SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) 12 | 13 | # here is the target environment located 14 | SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) 15 | 16 | # adjust the default behaviour of the FIND_XXX() commands: 17 | # search headers and libraries in the target environment, search 18 | # programs in the host environment 19 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 20 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 21 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 22 | 23 | set(CMAKE_PREFIX_PATH /usr/x86_64-w64-mingw32/usr/lib/cmake) 24 | 25 | set(CMAKE_SYSTEM_PROCESSOR x86_64) 26 | -------------------------------------------------------------------------------- /mingw-x86.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # To Cross-compile, use: 3 | # cmake -DCMAKE_TOOLCHAIN_FILE=../mingw.cmake .. 4 | # 5 | # the name of the target operating system 6 | SET(CMAKE_SYSTEM_NAME Windows) 7 | 8 | # which compilers to use for C and C++ 9 | SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc) 10 | SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) 11 | SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres) 12 | 13 | SET(CMAKE_C_FLAGS "-m32") 14 | SET(CMAKE_CXX_FLAGS "-m32") 15 | SET(CMAKE_RC_FLAGS "-F pe-i386") 16 | SET(CMAKE_ASM_FLAGS "-m32") 17 | 18 | # here is the target environment located 19 | SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32) 20 | 21 | # adjust the default behaviour of the FIND_XXX() commands: 22 | # search headers and libraries in the target environment, search 23 | # programs in the host environment 24 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 25 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 26 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 27 | 28 | set(CMAKE_PREFIX_PATH /usr/i686-w64-mingw32/usr/lib/cmake) 29 | 30 | set(CMAKE_SYSTEM_PROCESSOR x86) 31 | -------------------------------------------------------------------------------- /msvc-aarch64.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Windows) 2 | 3 | SET(CMAKE_C_COMPILER /opt/msvc/bin/arm64/cl) 4 | SET(CMAKE_CXX_COMPILER /opt/msvc/bin/arm64/cl) 5 | SET(CMAKE_RC_COMPILER /opt/msvc/bin/arm64/rc) 6 | 7 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO") 8 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /MANIFEST:NO") 9 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO") 10 | -------------------------------------------------------------------------------- /msvc-amd64.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Windows) 2 | 3 | SET(CMAKE_C_COMPILER /opt/msvc/bin/x64/cl) 4 | SET(CMAKE_CXX_COMPILER /opt/msvc/bin/x64/cl) 5 | SET(CMAKE_RC_COMPILER /opt/msvc/bin/x64/rc) 6 | 7 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO") 8 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /MANIFEST:NO") 9 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO") 10 | -------------------------------------------------------------------------------- /msvc-armv7.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Windows) 2 | 3 | SET(CMAKE_C_COMPILER /opt/msvc/bin/arm/cl) 4 | SET(CMAKE_CXX_COMPILER /opt/msvc/bin/arm/cl) 5 | SET(CMAKE_RC_COMPILER /opt/msvc/bin/arm/rc) 6 | 7 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO") 8 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /MANIFEST:NO") 9 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO") 10 | -------------------------------------------------------------------------------- /msvc-x86.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Windows) 2 | 3 | SET(CMAKE_C_COMPILER /opt/msvc/bin/x86/cl) 4 | SET(CMAKE_CXX_COMPILER /opt/msvc/bin/x86/cl) 5 | SET(CMAKE_RC_COMPILER /opt/msvc/bin/x86/rc) 6 | 7 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO") 8 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /MANIFEST:NO") 9 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO") 10 | 11 | set(CMAKE_PREFIX_PATH "/home/hellas/wine/vcpkg/installed/x64-windows") 12 | -------------------------------------------------------------------------------- /send-dump.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Dumper for btrfs send streams. 4 | # Released under the same terms, or lack thereof, as btrfs-dump.pl. 5 | 6 | open($f,$ARGV[0]) or die "Error opening ".$ARGV[0].": ".$!; 7 | binmode($f); 8 | 9 | while (!eof($f)) { 10 | do_stream($f); 11 | 12 | if (!eof($f)) { 13 | print "---\n"; 14 | } 15 | } 16 | 17 | close($f); 18 | 19 | sub do_stream { 20 | my ($f)=@_; 21 | 22 | read($f,$a,0x11); 23 | ($magic,$ver)=unpack("a13V",$a); 24 | 25 | if ($magic ne "btrfs-stream\0") { 26 | printf STDERR "Not a send file.\n"; 27 | close($f); 28 | exit; 29 | } 30 | 31 | if ($ver != 1 && $ver != 2) { 32 | printf STDERR "Version $ver not supported.\n"; 33 | close($f); 34 | exit; 35 | } 36 | 37 | $type = 0; 38 | while (!eof($f) && $type != 21) { 39 | read($f,$a,0xa); 40 | ($len,$type,$crc)=unpack("VvV",$a); 41 | 42 | if ($type == 1) { 43 | printf("subvol, %x, %08x\n", $len, $crc); 44 | } elsif ($type == 2) { 45 | printf("snapshot, %x, %08x\n", $len, $crc); 46 | } elsif ($type == 3) { 47 | printf("mkfile, %x, %08x\n", $len, $crc); 48 | } elsif ($type == 4) { 49 | printf("mkdir, %x, %08x\n", $len, $crc); 50 | } elsif ($type == 5) { 51 | printf("mknod, %x, %08x\n", $len, $crc); 52 | } elsif ($type == 6) { 53 | printf("mkfifo, %x, %08x\n", $len, $crc); 54 | } elsif ($type == 7) { 55 | printf("mksock, %x, %08x\n", $len, $crc); 56 | } elsif ($type == 8) { 57 | printf("symlink, %x, %08x\n", $len, $crc); 58 | } elsif ($type == 9) { 59 | printf("rename, %x, %08x\n", $len, $crc); 60 | } elsif ($type == 10) { 61 | printf("link, %x, %08x\n", $len, $crc); 62 | } elsif ($type == 11) { 63 | printf("unlink, %x, %08x\n", $len, $crc); 64 | } elsif ($type == 12) { 65 | printf("rmdir, %x, %08x\n", $len, $crc); 66 | } elsif ($type == 13) { 67 | printf("set_xattr, %x, %08x\n", $len, $crc); 68 | } elsif ($type == 14) { 69 | printf("remove_xattr, %x, %08x\n", $len, $crc); 70 | } elsif ($type == 15) { 71 | printf("write, %x, %08x\n", $len, $crc); 72 | } elsif ($type == 16) { 73 | printf("clone, %x, %08x\n", $len, $crc); 74 | } elsif ($type == 17) { 75 | printf("truncate, %x, %08x\n", $len, $crc); 76 | } elsif ($type == 18) { 77 | printf("chmod, %x, %08x\n", $len, $crc); 78 | } elsif ($type == 19) { 79 | printf("chown, %x, %08x\n", $len, $crc); 80 | } elsif ($type == 20) { 81 | printf("utimes, %x, %08x\n", $len, $crc); 82 | } elsif ($type == 21) { 83 | printf("end, %x, %08x\n", $len, $crc); 84 | } elsif ($type == 22) { 85 | printf("update-extent, %x, %08x\n", $len, $crc); 86 | } elsif ($type == 23) { 87 | printf("fallocate, %x, %08x\n", $len, $crc); 88 | } elsif ($type == 24) { 89 | printf("fileattr, %x, %08x\n", $len, $crc); 90 | } elsif ($type == 25) { 91 | printf("encoded-write, %x, %08x\n", $len, $crc); 92 | } else { 93 | printf("unknown(%x), %x, %08x\n", $type, $len, $crc); 94 | } 95 | 96 | read($f,$b,$len); 97 | print_tlvs($b); 98 | } 99 | } 100 | 101 | sub btrfstime { 102 | my ($t)=@_; 103 | 104 | my $ut = unpack("Q",$t); 105 | my @lt = localtime($ut); 106 | 107 | return sprintf("%04u-%02u-%02u %02u:%02u:%02u",$lt[5]+1900,$lt[4]+1,$lt[3],$lt[2],$lt[1],$lt[0]); 108 | } 109 | 110 | sub print_tlvs { 111 | my ($b)=@_; 112 | 113 | while (length($b)>0) { 114 | my ($t,$l)=unpack("vv",$b); 115 | 116 | if ($t == 1) { 117 | printf(" uuid: %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n", unpack("NnnnCCCCCC",substr($b,4,$l))); 118 | $b=substr($b,$l+4); 119 | } elsif ($t == 2) { 120 | printf(" transid: %x\n", unpack("Q",substr($b,4,$l))); 121 | $b=substr($b,$l+4); 122 | } elsif ($t == 3) { 123 | printf(" inode: %x\n", unpack("Q",substr($b,4,$l))); 124 | $b=substr($b,$l+4); 125 | } elsif ($t == 4) { 126 | printf(" size: %x\n", unpack("Q",substr($b,4,$l))); 127 | $b=substr($b,$l+4); 128 | } elsif ($t == 5) { 129 | printf(" mode: %o\n", unpack("Q",substr($b,4,$l))); 130 | $b=substr($b,$l+4); 131 | } elsif ($t == 6) { 132 | printf(" uid: %u\n", unpack("Q",substr($b,4,$l))); 133 | $b=substr($b,$l+4); 134 | } elsif ($t == 7) { 135 | printf(" gid: %u\n", unpack("Q",substr($b,4,$l))); 136 | $b=substr($b,$l+4); 137 | } elsif ($t == 8) { 138 | printf(" rdev: %x\n", unpack("Q",substr($b,4,$l))); 139 | $b=substr($b,$l+4); 140 | } elsif ($t == 9) { 141 | printf(" ctime: %s\n", btrfstime(substr($b,4,$l))); 142 | $b=substr($b,$l+4); 143 | } elsif ($t == 10) { 144 | printf(" mtime: %s\n", btrfstime(substr($b,4,$l))); 145 | $b=substr($b,$l+4); 146 | } elsif ($t == 11) { 147 | printf(" atime: %s\n", btrfstime(substr($b,4,$l))); 148 | $b=substr($b,$l+4); 149 | } elsif ($t == 12) { 150 | printf(" otime: %s\n", btrfstime(substr($b,4,$l))); 151 | $b=substr($b,$l+4); 152 | } elsif ($t == 13) { 153 | printf(" xattr_name: \"%s\"\n", substr($b,4,$l)); 154 | $b=substr($b,$l+4); 155 | } elsif ($t == 14) { 156 | printf(" xattr_data: \"%s\"\n", substr($b,4,$l)); 157 | $b=substr($b,$l+4); 158 | } elsif ($t == 15) { 159 | printf(" path: \"%s\"\n", substr($b,4,$l)); 160 | $b=substr($b,$l+4); 161 | } elsif ($t == 16) { 162 | printf(" path_to: \"%s\"\n", substr($b,4,$l)); 163 | $b=substr($b,$l+4); 164 | } elsif ($t == 17) { 165 | printf(" path_link: \"%s\"\n", substr($b,4,$l)); 166 | $b=substr($b,$l+4); 167 | } elsif ($t == 18) { 168 | printf(" offset: %x\n", unpack("Q",substr($b,4,$l))); 169 | $b=substr($b,$l+4); 170 | } elsif ($t == 19) { 171 | if ($ver == 2) { 172 | printf(" data: (%x bytes)\n", length($b) - 2); # FIXME 173 | $b=""; 174 | } else { 175 | printf(" data: (%x bytes)\n", $l); 176 | $b=substr($b,$l+4); 177 | } 178 | } elsif ($t == 20) { 179 | printf(" clone_uuid: %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n", unpack("NnnnCCCCCC",substr($b,4,$l))); 180 | $b=substr($b,$l+4); 181 | } elsif ($t == 21) { 182 | printf(" clone_transid: %x\n", unpack("Q",substr($b,4,$l))); 183 | $b=substr($b,$l+4); 184 | } elsif ($t == 22) { 185 | printf(" clone_path: \"%s\"\n", substr($b,4,$l)); 186 | $b=substr($b,$l+4); 187 | } elsif ($t == 23) { 188 | printf(" clone_offset: %x\n", unpack("Q",substr($b,4,$l))); 189 | $b=substr($b,$l+4); 190 | } elsif ($t == 24) { 191 | printf(" clone_len: %x\n", unpack("Q",substr($b,4,$l))); 192 | $b=substr($b,$l+4); 193 | } elsif ($t == 25) { 194 | printf(" fallocate_mode: %x\n", unpack("V",substr($b,4,$l))); 195 | $b=substr($b,$l+4); 196 | } elsif ($t == 26) { 197 | printf(" fileattr: %x\n", unpack("Q",substr($b,4,$l))); 198 | $b=substr($b,$l+4); 199 | } elsif ($t == 27) { 200 | printf(" unencoded_file_len: %x\n", unpack("Q",substr($b,4,$l))); 201 | $b=substr($b,$l+4); 202 | } elsif ($t == 28) { 203 | printf(" unencoded_len: %x\n", unpack("Q",substr($b,4,$l))); 204 | $b=substr($b,$l+4); 205 | } elsif ($t == 29) { 206 | printf(" unencoded_offset: %x\n", unpack("Q",substr($b,4,$l))); 207 | $b=substr($b,$l+4); 208 | } elsif ($t == 30) { 209 | printf(" compression: %x\n", unpack("V",substr($b,4,$l))); 210 | $b=substr($b,$l+4); 211 | } elsif ($t == 31) { 212 | printf(" encryption: %x\n", unpack("V",substr($b,4,$l))); 213 | $b=substr($b,$l+4); 214 | } else { 215 | printf(" unknown(%u),%x\n",$t,$l); 216 | $b=substr($b,$l+4); 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/blake2-impl.h: -------------------------------------------------------------------------------- 1 | /* 2 | BLAKE2 reference source code package - reference C implementations 3 | 4 | Copyright 2012, Samuel Neves . You may use this under the 5 | terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at 6 | your option. The terms of these licenses can be found at: 7 | 8 | - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 9 | - OpenSSL license : https://www.openssl.org/source/license.html 10 | - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | More information about the BLAKE2 hash function can be found at 13 | https://blake2.net. 14 | */ 15 | #pragma once 16 | 17 | #include 18 | #include 19 | 20 | #if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) 21 | #if defined(_MSC_VER) 22 | #define BLAKE2_INLINE __inline 23 | #elif defined(__GNUC__) 24 | #define BLAKE2_INLINE __inline__ 25 | #else 26 | #define BLAKE2_INLINE 27 | #endif 28 | #else 29 | #define BLAKE2_INLINE inline 30 | #endif 31 | 32 | #define NATIVE_LITTLE_ENDIAN 33 | 34 | static BLAKE2_INLINE uint32_t load32( const void *src ) 35 | { 36 | #if defined(NATIVE_LITTLE_ENDIAN) 37 | uint32_t w; 38 | memcpy(&w, src, sizeof w); 39 | return w; 40 | #else 41 | const uint8_t *p = ( const uint8_t * )src; 42 | return (( uint32_t )( p[0] ) << 0) | 43 | (( uint32_t )( p[1] ) << 8) | 44 | (( uint32_t )( p[2] ) << 16) | 45 | (( uint32_t )( p[3] ) << 24) ; 46 | #endif 47 | } 48 | 49 | static BLAKE2_INLINE uint64_t load64( const void *src ) 50 | { 51 | #if defined(NATIVE_LITTLE_ENDIAN) 52 | uint64_t w; 53 | memcpy(&w, src, sizeof w); 54 | return w; 55 | #else 56 | const uint8_t *p = ( const uint8_t * )src; 57 | return (( uint64_t )( p[0] ) << 0) | 58 | (( uint64_t )( p[1] ) << 8) | 59 | (( uint64_t )( p[2] ) << 16) | 60 | (( uint64_t )( p[3] ) << 24) | 61 | (( uint64_t )( p[4] ) << 32) | 62 | (( uint64_t )( p[5] ) << 40) | 63 | (( uint64_t )( p[6] ) << 48) | 64 | (( uint64_t )( p[7] ) << 56) ; 65 | #endif 66 | } 67 | 68 | static BLAKE2_INLINE uint16_t load16( const void *src ) 69 | { 70 | #if defined(NATIVE_LITTLE_ENDIAN) 71 | uint16_t w; 72 | memcpy(&w, src, sizeof w); 73 | return w; 74 | #else 75 | const uint8_t *p = ( const uint8_t * )src; 76 | return ( uint16_t )((( uint32_t )( p[0] ) << 0) | 77 | (( uint32_t )( p[1] ) << 8)); 78 | #endif 79 | } 80 | 81 | static BLAKE2_INLINE void store16( void *dst, uint16_t w ) 82 | { 83 | #if defined(NATIVE_LITTLE_ENDIAN) 84 | memcpy(dst, &w, sizeof w); 85 | #else 86 | uint8_t *p = ( uint8_t * )dst; 87 | *p++ = ( uint8_t )w; w >>= 8; 88 | *p++ = ( uint8_t )w; 89 | #endif 90 | } 91 | 92 | static BLAKE2_INLINE void store32( void *dst, uint32_t w ) 93 | { 94 | #if defined(NATIVE_LITTLE_ENDIAN) 95 | memcpy(dst, &w, sizeof w); 96 | #else 97 | uint8_t *p = ( uint8_t * )dst; 98 | p[0] = (uint8_t)(w >> 0); 99 | p[1] = (uint8_t)(w >> 8); 100 | p[2] = (uint8_t)(w >> 16); 101 | p[3] = (uint8_t)(w >> 24); 102 | #endif 103 | } 104 | 105 | static BLAKE2_INLINE void store64( void *dst, uint64_t w ) 106 | { 107 | #if defined(NATIVE_LITTLE_ENDIAN) 108 | memcpy(dst, &w, sizeof w); 109 | #else 110 | uint8_t *p = ( uint8_t * )dst; 111 | p[0] = (uint8_t)(w >> 0); 112 | p[1] = (uint8_t)(w >> 8); 113 | p[2] = (uint8_t)(w >> 16); 114 | p[3] = (uint8_t)(w >> 24); 115 | p[4] = (uint8_t)(w >> 32); 116 | p[5] = (uint8_t)(w >> 40); 117 | p[6] = (uint8_t)(w >> 48); 118 | p[7] = (uint8_t)(w >> 56); 119 | #endif 120 | } 121 | 122 | static BLAKE2_INLINE uint64_t load48( const void *src ) 123 | { 124 | const uint8_t *p = ( const uint8_t * )src; 125 | return (( uint64_t )( p[0] ) << 0) | 126 | (( uint64_t )( p[1] ) << 8) | 127 | (( uint64_t )( p[2] ) << 16) | 128 | (( uint64_t )( p[3] ) << 24) | 129 | (( uint64_t )( p[4] ) << 32) | 130 | (( uint64_t )( p[5] ) << 40) ; 131 | } 132 | 133 | static BLAKE2_INLINE void store48( void *dst, uint64_t w ) 134 | { 135 | uint8_t *p = ( uint8_t * )dst; 136 | p[0] = (uint8_t)(w >> 0); 137 | p[1] = (uint8_t)(w >> 8); 138 | p[2] = (uint8_t)(w >> 16); 139 | p[3] = (uint8_t)(w >> 24); 140 | p[4] = (uint8_t)(w >> 32); 141 | p[5] = (uint8_t)(w >> 40); 142 | } 143 | 144 | static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c ) 145 | { 146 | return ( w >> c ) | ( w << ( 32 - c ) ); 147 | } 148 | 149 | static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c ) 150 | { 151 | return ( w >> c ) | ( w << ( 64 - c ) ); 152 | } 153 | 154 | #if defined(_MSC_VER) 155 | #define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) 156 | #else 157 | #define BLAKE2_PACKED(x) x __attribute__((packed)) 158 | #endif 159 | 160 | enum blake2b_constant 161 | { 162 | BLAKE2B_BLOCKBYTES = 128, 163 | BLAKE2B_OUTBYTES = 64, 164 | BLAKE2B_KEYBYTES = 64, 165 | BLAKE2B_SALTBYTES = 16, 166 | BLAKE2B_PERSONALBYTES = 16 167 | }; 168 | 169 | typedef struct blake2b_state__ 170 | { 171 | uint64_t h[8]; 172 | uint64_t t[2]; 173 | uint64_t f[2]; 174 | uint8_t buf[BLAKE2B_BLOCKBYTES]; 175 | size_t buflen; 176 | size_t outlen; 177 | uint8_t last_node; 178 | } blake2b_state; 179 | 180 | BLAKE2_PACKED(struct blake2b_param__ 181 | { 182 | uint8_t digest_length; /* 1 */ 183 | uint8_t key_length; /* 2 */ 184 | uint8_t fanout; /* 3 */ 185 | uint8_t depth; /* 4 */ 186 | uint32_t leaf_length; /* 8 */ 187 | uint32_t node_offset; /* 12 */ 188 | uint32_t xof_length; /* 16 */ 189 | uint8_t node_depth; /* 17 */ 190 | uint8_t inner_length; /* 18 */ 191 | uint8_t reserved[14]; /* 32 */ 192 | uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ 193 | uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ 194 | }); 195 | 196 | typedef struct blake2b_param__ blake2b_param; 197 | -------------------------------------------------------------------------------- /src/blake2b-ref.c: -------------------------------------------------------------------------------- 1 | /* 2 | BLAKE2 reference source code package - reference C implementations 3 | 4 | Copyright 2012, Samuel Neves . You may use this under the 5 | terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at 6 | your option. The terms of these licenses can be found at: 7 | 8 | - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 9 | - OpenSSL license : https://www.openssl.org/source/license.html 10 | - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | More information about the BLAKE2 hash function can be found at 13 | https://blake2.net. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "blake2-impl.h" 21 | 22 | static const uint64_t blake2b_IV[8] = 23 | { 24 | 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 25 | 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 26 | 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 27 | 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL 28 | }; 29 | 30 | static const uint8_t blake2b_sigma[12][16] = 31 | { 32 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , 33 | { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , 34 | { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , 35 | { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , 36 | { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , 37 | { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , 38 | { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , 39 | { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , 40 | { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , 41 | { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , 42 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , 43 | { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } 44 | }; 45 | 46 | static int blake2b_update(blake2b_state* S, const void* in, size_t inlen); 47 | 48 | static void blake2b_set_lastnode( blake2b_state *S ) 49 | { 50 | S->f[1] = (uint64_t)-1; 51 | } 52 | 53 | /* Some helper functions, not necessarily useful */ 54 | static int blake2b_is_lastblock( const blake2b_state *S ) 55 | { 56 | return S->f[0] != 0; 57 | } 58 | 59 | static void blake2b_set_lastblock( blake2b_state *S ) 60 | { 61 | if( S->last_node ) blake2b_set_lastnode( S ); 62 | 63 | S->f[0] = (uint64_t)-1; 64 | } 65 | 66 | static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) 67 | { 68 | S->t[0] += inc; 69 | S->t[1] += ( S->t[0] < inc ); 70 | } 71 | 72 | static void blake2b_init0( blake2b_state *S ) 73 | { 74 | size_t i; 75 | memset( S, 0, sizeof( blake2b_state ) ); 76 | 77 | for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; 78 | } 79 | 80 | /* init xors IV with input parameter block */ 81 | static void blake2b_init_param( blake2b_state *S, const blake2b_param *P ) 82 | { 83 | const uint8_t *p = ( const uint8_t * )( P ); 84 | size_t i; 85 | 86 | blake2b_init0( S ); 87 | 88 | /* IV XOR ParamBlock */ 89 | for( i = 0; i < 8; ++i ) 90 | S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); 91 | 92 | S->outlen = P->digest_length; 93 | } 94 | 95 | 96 | 97 | static void blake2b_init( blake2b_state *S, size_t outlen ) 98 | { 99 | blake2b_param P[1]; 100 | 101 | P->digest_length = (uint8_t)outlen; 102 | P->key_length = 0; 103 | P->fanout = 1; 104 | P->depth = 1; 105 | store32( &P->leaf_length, 0 ); 106 | store32( &P->node_offset, 0 ); 107 | store32( &P->xof_length, 0 ); 108 | P->node_depth = 0; 109 | P->inner_length = 0; 110 | memset( P->reserved, 0, sizeof( P->reserved ) ); 111 | memset( P->salt, 0, sizeof( P->salt ) ); 112 | memset( P->personal, 0, sizeof( P->personal ) ); 113 | 114 | blake2b_init_param( S, P ); 115 | } 116 | 117 | #define G(r,i,a,b,c,d) \ 118 | do { \ 119 | a = a + b + m[blake2b_sigma[r][2*i+0]]; \ 120 | d = rotr64(d ^ a, 32); \ 121 | c = c + d; \ 122 | b = rotr64(b ^ c, 24); \ 123 | a = a + b + m[blake2b_sigma[r][2*i+1]]; \ 124 | d = rotr64(d ^ a, 16); \ 125 | c = c + d; \ 126 | b = rotr64(b ^ c, 63); \ 127 | } while(0) 128 | 129 | #define ROUND(r) \ 130 | do { \ 131 | G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ 132 | G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ 133 | G(r,2,v[ 2],v[ 6],v[10],v[14]); \ 134 | G(r,3,v[ 3],v[ 7],v[11],v[15]); \ 135 | G(r,4,v[ 0],v[ 5],v[10],v[15]); \ 136 | G(r,5,v[ 1],v[ 6],v[11],v[12]); \ 137 | G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ 138 | G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ 139 | } while(0) 140 | 141 | static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) 142 | { 143 | uint64_t m[16]; 144 | uint64_t v[16]; 145 | size_t i; 146 | 147 | for( i = 0; i < 16; ++i ) { 148 | m[i] = load64( block + i * sizeof( m[i] ) ); 149 | } 150 | 151 | for( i = 0; i < 8; ++i ) { 152 | v[i] = S->h[i]; 153 | } 154 | 155 | v[ 8] = blake2b_IV[0]; 156 | v[ 9] = blake2b_IV[1]; 157 | v[10] = blake2b_IV[2]; 158 | v[11] = blake2b_IV[3]; 159 | v[12] = blake2b_IV[4] ^ S->t[0]; 160 | v[13] = blake2b_IV[5] ^ S->t[1]; 161 | v[14] = blake2b_IV[6] ^ S->f[0]; 162 | v[15] = blake2b_IV[7] ^ S->f[1]; 163 | 164 | ROUND( 0 ); 165 | ROUND( 1 ); 166 | ROUND( 2 ); 167 | ROUND( 3 ); 168 | ROUND( 4 ); 169 | ROUND( 5 ); 170 | ROUND( 6 ); 171 | ROUND( 7 ); 172 | ROUND( 8 ); 173 | ROUND( 9 ); 174 | ROUND( 10 ); 175 | ROUND( 11 ); 176 | 177 | for( i = 0; i < 8; ++i ) { 178 | S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; 179 | } 180 | } 181 | 182 | #undef G 183 | #undef ROUND 184 | 185 | static int blake2b_update( blake2b_state *S, const void *pin, size_t inlen ) 186 | { 187 | const unsigned char * in = (const unsigned char *)pin; 188 | if( inlen > 0 ) 189 | { 190 | size_t left = S->buflen; 191 | size_t fill = BLAKE2B_BLOCKBYTES - left; 192 | if( inlen > fill ) 193 | { 194 | S->buflen = 0; 195 | memcpy( S->buf + left, in, fill ); /* Fill buffer */ 196 | blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); 197 | blake2b_compress( S, S->buf ); /* Compress */ 198 | in += fill; inlen -= fill; 199 | while(inlen > BLAKE2B_BLOCKBYTES) { 200 | blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); 201 | blake2b_compress( S, in ); 202 | in += BLAKE2B_BLOCKBYTES; 203 | inlen -= BLAKE2B_BLOCKBYTES; 204 | } 205 | } 206 | memcpy( S->buf + S->buflen, in, inlen ); 207 | S->buflen += inlen; 208 | } 209 | return 0; 210 | } 211 | 212 | static int blake2b_final( blake2b_state *S, void *out, size_t outlen ) 213 | { 214 | uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; 215 | size_t i; 216 | 217 | if( out == NULL || outlen < S->outlen ) 218 | return -1; 219 | 220 | if( blake2b_is_lastblock( S ) ) 221 | return -1; 222 | 223 | blake2b_increment_counter( S, S->buflen ); 224 | blake2b_set_lastblock( S ); 225 | memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ 226 | blake2b_compress( S, S->buf ); 227 | 228 | for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ 229 | store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); 230 | 231 | memcpy( out, buffer, S->outlen ); 232 | 233 | return 0; 234 | } 235 | 236 | /* inlen, at least, should be uint64_t. Others can be size_t. */ 237 | void blake2b( void *out, size_t outlen, const void *in, size_t inlen ) 238 | { 239 | blake2b_state S[1]; 240 | 241 | blake2b_init( S, outlen ); 242 | 243 | blake2b_update( S, ( const uint8_t * )in, inlen ); 244 | blake2b_final( S, out, outlen ); 245 | } 246 | -------------------------------------------------------------------------------- /src/btrfs-vol.inf: -------------------------------------------------------------------------------- 1 | ;;; 2 | ;;; WinBtrfs 3 | ;;; 4 | ;;; 5 | ;;; Copyright (c) 2016-24 Mark Harmstone 6 | ;;; 7 | 8 | [Version] 9 | Signature = "$Windows NT$" 10 | Class = Volume 11 | ClassGuid = {71a27cdd-812a-11d0-bec7-08002be2092f} 12 | Provider = %Me% 13 | DriverVer = 03/15/2024,1.9.0.0 14 | CatalogFile = btrfs.cat 15 | PnpLockdown = 1 16 | 17 | [DestinationDirs] 18 | Btrfs.DriverFiles = 12 ;%windir%\system32\drivers 19 | 20 | [Manufacturer] 21 | %Me%=Standard,NTamd64,NTx86,NTarm,NTarm64 22 | 23 | [Standard.NTamd64] 24 | %VolumeName% = Btrfs_Install, BtrfsVolume 25 | %ControllerName% = Btrfs_Install, ROOT\btrfs 26 | 27 | [Standard.NTx86] 28 | %VolumeName% = Btrfs_Install, BtrfsVolume 29 | %ControllerName% = Btrfs_Install, ROOT\btrfs 30 | 31 | [Standard.NTarm] 32 | %VolumeName% = Btrfs_Install, BtrfsVolume 33 | %ControllerName% = Btrfs_Install, ROOT\btrfs 34 | 35 | [Standard.NTarm64] 36 | %VolumeName% = Btrfs_Install, BtrfsVolume 37 | %ControllerName% = Btrfs_Install, ROOT\btrfs 38 | 39 | [Btrfs_Install] 40 | OptionDesc = %ServiceDescription% 41 | CopyFiles = Btrfs.DriverFiles 42 | 43 | [Btrfs_Install.Services] 44 | AddService = %ServiceName%,2,Btrfs.Service 45 | 46 | ; 47 | ; Services Section 48 | ; 49 | 50 | [Btrfs.Service] 51 | DisplayName = %ServiceName% 52 | Description = %ServiceDescription% 53 | ServiceBinary = %12%\%DriverName%.sys ;%windir%\system32\drivers\ 54 | ServiceType = 1 55 | StartType = 1 ;SERVICE_SYSTEM_START 56 | ErrorControl = 1 57 | LoadOrderGroup = "File System" 58 | 59 | ; 60 | ; Copy Files 61 | ; 62 | 63 | [Btrfs.DriverFiles] 64 | %DriverName%.sys 65 | 66 | [SourceDisksFiles] 67 | btrfs.sys = 1,, 68 | 69 | [SourceDisksNames.x86] 70 | 1 = %DiskId1%,,,\x86 71 | 72 | [SourceDisksNames.amd64] 73 | 1 = %DiskId1%,,,\amd64 74 | 75 | [SourceDisksNames.arm] 76 | 1 = %DiskId1%,,,\arm 77 | 78 | [SourceDisksNames.arm64] 79 | 1 = %DiskId1%,,,\aarch64 80 | 81 | ;; 82 | ;; String Section 83 | ;; 84 | 85 | [Strings] 86 | Me = "Mark Harmstone" 87 | ServiceDescription = "Btrfs driver" 88 | ServiceName = "btrfs" 89 | DriverName = "btrfs" 90 | DiskId1 = "Btrfs Device Installation Disk" 91 | VolumeName = "Btrfs volume" 92 | ControllerName = "Btrfs controller" 93 | REG_EXPAND_SZ = 0x00020000 94 | -------------------------------------------------------------------------------- /src/btrfs.cdf: -------------------------------------------------------------------------------- 1 | [CatalogHeader] 2 | Name=btrfs.cat 3 | CatalogVersion=1 4 | HashAlgorithms=SHA1 5 | PageHashes=true 6 | EncodingType=0x00010001 7 | CATATTR1=0x10010001:HWID1:btrfsvolume 8 | CATATTR2=0x10010001:HWID2:root\btrfs 9 | CATATTR3=0x10010001:OS:XPX86,XPX64,VistaX86,VistaX64,7X86,7X64,8X86,8X64,8ARM,_v63,_v63_X64,_v63_ARM,_v100,_v100_X64,_v100_X64_22H2,_v100_ARM64_22H2 10 | 11 | [CatalogFiles] 12 | btrfs.inf=btrfs.inf 13 | btrfs.infATTR1=0x10010001:File:btrfs.inf 14 | btrfs.infATTR2=0x10010001:OSAttr:2:5.1,2:5.2,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 15 | btrfs-vol.inf=btrfs-vol.inf 16 | btrfs-vol.infATTR1=0x10010001:File:btrfs-vol.inf 17 | btrfs-vol.infATTR2=0x10010001:OSAttr:2:5.1,2:5.2,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 18 | aarch64_btrfs.sys=aarch64\btrfs.sys 19 | aarch64_btrfs.sysATTR1=0x10010001:File:btrfs.sys 20 | aarch64_btrfs.sysATTR2=0x10010001:OSAttr:2:5.1,2:5.2,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 21 | aarch64_mkbtrfs.exe=aarch64\mkbtrfs.exe 22 | aarch64_mkbtrfs.exeATTR1=0x10010001:File:mkbtrfs.exe 23 | aarch64_mkbtrfs.exeATTR2=0x10010001:OSAttr:2:10.0 24 | aarch64_shellbtrfs.dll=aarch64\shellbtrfs.dll 25 | aarch64_shellbtrfs.dllATTR1=0x10010001:File:shellbtrfs.dll 26 | aarch64_shellbtrfs.dllATTR2=0x10010001:OSAttr:2:10.0 27 | aarch64_ubtrfs.dll=aarch64\ubtrfs.dll 28 | aarch64_ubtrfs.dllATTR1=0x10010001:File:ubtrfs.dll 29 | aarch64_ubtrfs.dllATTR2=0x10010001:OSAttr:2:10.0 30 | amd64_btrfs.sys=amd64\btrfs.sys 31 | amd64_btrfs.sysATTR1=0x10010001:File:btrfs.sys 32 | amd64_btrfs.sysATTR2=0x10010001:OSAttr:2:5.1,2:5.2,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 33 | amd64_mkbtrfs.exe=amd64\mkbtrfs.exe 34 | amd64_mkbtrfs.exeATTR1=0x10010001:File:mkbtrfs.exe 35 | amd64_mkbtrfs.exeATTR2=0x10010001:OSAttr:2:5.1,2:5.2,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 36 | amd64_shellbtrfs.dll=amd64\shellbtrfs.dll 37 | amd64_shellbtrfs.dllATTR1=0x10010001:File:shellbtrfs.dll 38 | amd64_shellbtrfs.dllATTR2=0x10010001:OSAttr:2:5.1,2:5.2,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 39 | amd64_ubtrfs.dll=amd64\ubtrfs.dll 40 | amd64_ubtrfs.dllATTR1=0x10010001:File:ubtrfs.dll 41 | amd64_ubtrfs.dllATTR2=0x10010001:OSAttr:2:5.1,2:5.2,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 42 | arm_btrfs.sys=arm\btrfs.sys 43 | arm_btrfs.sysATTR1=0x10010001:File:btrfs.sys 44 | arm_btrfs.sysATTR2=0x10010001:OSAttr:2:5.1,2:5.2,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 45 | arm_mkbtrfs.exe=arm\mkbtrfs.exe 46 | arm_mkbtrfs.exeATTR1=0x10010001:File:mkbtrfs.exe 47 | arm_mkbtrfs.exeATTR2=0x10010001:OSAttr:2:6.2,2:6.3 48 | arm_shellbtrfs.dll=arm\shellbtrfs.dll 49 | arm_shellbtrfs.dllATTR1=0x10010001:File:shellbtrfs.dll 50 | arm_shellbtrfs.dllATTR2=0x10010001:OSAttr:2:6.2,2:6.3 51 | arm_ubtrfs.dll=arm\ubtrfs.dll 52 | arm_ubtrfs.dllATTR1=0x10010001:File:ubtrfs.dll 53 | arm_ubtrfs.dllATTR2=0x10010001:OSAttr:2:6.2,2:6.3 54 | x86_btrfs.sys=x86\btrfs.sys 55 | x86_btrfs.sysATTR1=0x10010001:File:btrfs.sys 56 | x86_btrfs.sysATTR2=0x10010001:OSAttr:2:5.1,2:5.2,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 57 | x86_mkbtrfs.exe=x86\mkbtrfs.exe 58 | x86_mkbtrfs.exeATTR1=0x10010001:File:mkbtrfs.exe 59 | x86_mkbtrfs.exeATTR2=0x10010001:OSAttr:2:5.1,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 60 | x86_shellbtrfs.dll=x86\shellbtrfs.dll 61 | x86_shellbtrfs.dllATTR1=0x10010001:File:shellbtrfs.dll 62 | x86_shellbtrfs.dllATTR2=0x10010001:OSAttr:2:5.1,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 63 | x86_ubtrfs.dll=x86\ubtrfs.dll 64 | x86_ubtrfs.dllATTR1=0x10010001:File:ubtrfs.dll 65 | x86_ubtrfs.dllATTR2=0x10010001:OSAttr:2:5.1,2:6.0,2:6.1,2:6.2,2:6.3,2:10.0 66 | -------------------------------------------------------------------------------- /src/btrfs.inf: -------------------------------------------------------------------------------- 1 | ;;; 2 | ;;; WinBtrfs 3 | ;;; 4 | ;;; 5 | ;;; Copyright (c) 2016-24 Mark Harmstone 6 | ;;; 7 | 8 | [Version] 9 | Signature = "$Windows NT$" 10 | Class = Volume 11 | ClassGuid = {71a27cdd-812a-11d0-bec7-08002be2092f} 12 | Provider = %Me% 13 | DriverVer = 03/15/2024,1.9.0.0 14 | CatalogFile = btrfs.cat 15 | 16 | [DestinationDirs] 17 | Btrfs.DriverFiles = 12 ;%windir%\system32\drivers 18 | Btrfs.DllFiles = 11 ;%windir%\system32 19 | 20 | ;; 21 | ;; Default install sections 22 | ;; 23 | 24 | [DefaultInstall.NTamd64] 25 | OptionDesc = %ServiceDescription% 26 | CopyFiles = Btrfs.DriverFiles,Btrfs.DllFiles 27 | AddReg = shellbtrfs_AddReg 28 | CopyINF = btrfs-vol.inf 29 | 30 | [DefaultInstall.NTx86] 31 | OptionDesc = %ServiceDescription% 32 | CopyFiles = Btrfs.DriverFiles,Btrfs.DllFiles 33 | AddReg = shellbtrfs_AddReg 34 | CopyINF = btrfs-vol.inf 35 | 36 | [DefaultInstall.NTarm] 37 | OptionDesc = %ServiceDescription% 38 | CopyFiles = Btrfs.DriverFiles,Btrfs.DllFiles 39 | AddReg = shellbtrfs_AddReg 40 | CopyINF = btrfs-vol.inf 41 | 42 | [DefaultInstall.NTarm64] 43 | OptionDesc = %ServiceDescription% 44 | CopyFiles = Btrfs.DriverFiles,Btrfs.DllFiles 45 | AddReg = shellbtrfs_AddReg 46 | CopyINF = btrfs-vol.inf 47 | 48 | [DefaultInstall.NTamd64.Services] 49 | AddService = %ServiceName%,0x802,Btrfs.Service 50 | 51 | [DefaultInstall.NTx86.Services] 52 | AddService = %ServiceName%,0x802,Btrfs.Service 53 | 54 | [DefaultInstall.NTarm.Services] 55 | AddService = %ServiceName%,0x802,Btrfs.Service 56 | 57 | [DefaultInstall.NTarm64.Services] 58 | AddService = %ServiceName%,0x802,Btrfs.Service 59 | 60 | ; 61 | ; Services Section 62 | ; 63 | 64 | [Btrfs.Service] 65 | DisplayName = %ServiceName% 66 | Description = %ServiceDescription% 67 | ServiceBinary = %12%\%DriverName%.sys ;%windir%\system32\drivers\ 68 | ServiceType = 1 69 | StartType = 1 ;SERVICE_SYSTEM_START 70 | ErrorControl = 1 71 | LoadOrderGroup = "File System" 72 | 73 | ; 74 | ; Copy Files 75 | ; 76 | 77 | [Btrfs.DriverFiles] 78 | %DriverName%.sys 79 | 80 | [Btrfs.DllFiles] 81 | shellbtrfs.dll 82 | ubtrfs.dll 83 | mkbtrfs.exe 84 | 85 | [SourceDisksFiles] 86 | btrfs.sys = 1,, 87 | shellbtrfs.dll = 1,, 88 | ubtrfs.dll = 1,, 89 | mkbtrfs.exe = 1,, 90 | 91 | [SourceDisksNames.x86] 92 | 1 = %DiskId1%,,,\x86 93 | 94 | [SourceDisksNames.amd64] 95 | 1 = %DiskId1%,,,\amd64 96 | 97 | [SourceDisksNames.arm] 98 | 1 = %DiskId1%,,,\arm 99 | 100 | [SourceDisksNames.arm64] 101 | 1 = %DiskId1%,,,\aarch64 102 | 103 | [shellbtrfs_AddReg] 104 | HKCR,*\ShellEx\PropertySheetHandlers\WinBtrfs,,,"{2690B74F-F353-422D-BB12-401581EEF8F2}" 105 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F0},,,"WinBtrfs shell extension (icon handler)" 106 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F0}\InprocServer32,,%REG_EXPAND_SZ%,"%%SystemRoot%%\System32\shellbtrfs.dll" 107 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F0}\InprocServer32,ThreadingModel,,"Apartment" 108 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F1},,,"WinBtrfs shell extension (context menu)" 109 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F1}\InprocServer32,,%REG_EXPAND_SZ%,"%%SystemRoot%%\System32\shellbtrfs.dll" 110 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F1}\InprocServer32,ThreadingModel,,"Apartment" 111 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F2},,,"WinBtrfs shell extension (property sheet)" 112 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F2}\InprocServer32,,%REG_EXPAND_SZ%,"%%SystemRoot%%\System32\shellbtrfs.dll" 113 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F2}\InprocServer32,ThreadingModel,,"Apartment" 114 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F3},,,"WinBtrfs shell extension (volume property sheet)" 115 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F3}\InprocServer32,,%REG_EXPAND_SZ%,"%%SystemRoot%%\System32\shellbtrfs.dll" 116 | HKCR,CLSID\{2690B74F-F353-422D-BB12-401581EEF8F3}\InprocServer32,ThreadingModel,,"Apartment" 117 | HKCR,Directory\Background\ShellEx\ContextMenuHandlers\WinBtrfs,,,"{2690B74F-F353-422D-BB12-401581EEF8F1}" 118 | HKCR,Drive\ShellEx\PropertySheetHandlers\WinBtrfs,,,"{2690B74F-F353-422D-BB12-401581EEF8F3}" 119 | HKCR,Folder\ShellEx\ContextMenuHandlers\WinBtrfs,,,"{2690B74F-F353-422D-BB12-401581EEF8F1}" 120 | HKCR,Folder\ShellEx\PropertySheetHandlers\WinBtrfs,,,"{2690B74F-F353-422D-BB12-401581EEF8F2}" 121 | ;HKLM,Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\WinBtrfs,,,"{2690B74F-F353-422D-BB12-401581EEF8F0}" 122 | 123 | ;; 124 | ;; String Section 125 | ;; 126 | 127 | [Strings] 128 | Me = "Mark Harmstone" 129 | ServiceDescription = "Btrfs driver" 130 | ServiceName = "btrfs" 131 | DriverName = "btrfs" 132 | DiskId1 = "Btrfs Device Installation Disk" 133 | VolumeName = "Btrfs volume" 134 | ControllerName = "Btrfs controller" 135 | REG_EXPAND_SZ = 0x00020000 136 | -------------------------------------------------------------------------------- /src/btrfs.rc.in: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "@CMAKE_CURRENT_SOURCE_DIR@/src/resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (United Kingdom) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) 19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK 20 | #pragma code_page(1252) 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Version 51 | // 52 | 53 | VS_VERSION_INFO VERSIONINFO 54 | FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 55 | PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 56 | FILEFLAGSMASK 0x17L 57 | #ifdef _DEBUG 58 | FILEFLAGS 0x1L 59 | #else 60 | FILEFLAGS 0x0L 61 | #endif 62 | FILEOS 0x4L 63 | FILETYPE 0x1L 64 | FILESUBTYPE 0x0L 65 | BEGIN 66 | BLOCK "StringFileInfo" 67 | BEGIN 68 | BLOCK "080904b0" 69 | BEGIN 70 | VALUE "FileDescription", "WinBtrfs" 71 | VALUE "FileVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" 72 | VALUE "InternalName", "btrfs" 73 | VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-24" 74 | VALUE "OriginalFilename", "btrfs.sys" 75 | VALUE "ProductName", "WinBtrfs" 76 | VALUE "ProductVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" 77 | END 78 | END 79 | BLOCK "VarFileInfo" 80 | BEGIN 81 | VALUE "Translation", 0x809, 1200 82 | END 83 | END 84 | 85 | #endif // English (United Kingdom) resources 86 | ///////////////////////////////////////////////////////////////////////////// 87 | 88 | 89 | 90 | #ifndef APSTUDIO_INVOKED 91 | ///////////////////////////////////////////////////////////////////////////// 92 | // 93 | // Generated from the TEXTINCLUDE 3 resource. 94 | // 95 | 96 | 97 | ///////////////////////////////////////////////////////////////////////////// 98 | #endif // not APSTUDIO_INVOKED 99 | 100 | -------------------------------------------------------------------------------- /src/btrfsioctl.h: -------------------------------------------------------------------------------- 1 | // No copyright claimed in this file - do what you want with it. 2 | 3 | #pragma once 4 | 5 | #include "btrfs.h" 6 | 7 | #define FSCTL_BTRFS_GET_FILE_IDS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x829, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 8 | #define FSCTL_BTRFS_CREATE_SUBVOL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82a, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 9 | #define FSCTL_BTRFS_CREATE_SNAPSHOT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82b, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 10 | #define FSCTL_BTRFS_GET_INODE_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82c, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 11 | #define FSCTL_BTRFS_SET_INODE_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82d, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 12 | #define FSCTL_BTRFS_GET_DEVICES CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82e, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 13 | #define FSCTL_BTRFS_GET_USAGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82f, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 14 | #define FSCTL_BTRFS_START_BALANCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x830, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 15 | #define FSCTL_BTRFS_QUERY_BALANCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x831, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 16 | #define FSCTL_BTRFS_PAUSE_BALANCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x832, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 17 | #define FSCTL_BTRFS_RESUME_BALANCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x833, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 18 | #define FSCTL_BTRFS_STOP_BALANCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x834, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 19 | #define FSCTL_BTRFS_ADD_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x835, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 20 | #define FSCTL_BTRFS_REMOVE_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x836, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 21 | #define IOCTL_BTRFS_QUERY_FILESYSTEMS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x837, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 22 | #define FSCTL_BTRFS_GET_UUID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x838, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 23 | #define FSCTL_BTRFS_START_SCRUB CTL_CODE(FILE_DEVICE_UNKNOWN, 0x839, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 24 | #define FSCTL_BTRFS_QUERY_SCRUB CTL_CODE(FILE_DEVICE_UNKNOWN, 0x83a, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 25 | #define FSCTL_BTRFS_PAUSE_SCRUB CTL_CODE(FILE_DEVICE_UNKNOWN, 0x83b, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 26 | #define FSCTL_BTRFS_RESUME_SCRUB CTL_CODE(FILE_DEVICE_UNKNOWN, 0x83c, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 27 | #define FSCTL_BTRFS_STOP_SCRUB CTL_CODE(FILE_DEVICE_UNKNOWN, 0x83d, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 28 | #define IOCTL_BTRFS_PROBE_VOLUME CTL_CODE(FILE_DEVICE_UNKNOWN, 0x83e, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 29 | #define FSCTL_BTRFS_RESET_STATS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x83f, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 30 | #define FSCTL_BTRFS_MKNOD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x840, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 31 | #define FSCTL_BTRFS_RECEIVED_SUBVOL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x841, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 32 | #define FSCTL_BTRFS_GET_XATTRS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x842, METHOD_BUFFERED, FILE_ANY_ACCESS) 33 | #define FSCTL_BTRFS_SET_XATTR CTL_CODE(FILE_DEVICE_UNKNOWN, 0x843, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 34 | #define FSCTL_BTRFS_RESERVE_SUBVOL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x844, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 35 | #define FSCTL_BTRFS_FIND_SUBVOL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x845, METHOD_BUFFERED, FILE_ANY_ACCESS) 36 | #define FSCTL_BTRFS_SEND_SUBVOL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x846, METHOD_BUFFERED, FILE_ANY_ACCESS) 37 | #define FSCTL_BTRFS_READ_SEND_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x847, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 38 | #define FSCTL_BTRFS_RESIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x848, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 39 | #define IOCTL_BTRFS_UNLOAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x849, METHOD_NEITHER, FILE_ANY_ACCESS) 40 | #define FSCTL_BTRFS_GET_CSUM_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x84a, METHOD_BUFFERED, FILE_READ_ACCESS) 41 | 42 | typedef struct { 43 | uint64_t subvol; 44 | uint64_t inode; 45 | BOOL top; 46 | } btrfs_get_file_ids; 47 | 48 | typedef struct { 49 | HANDLE subvol; 50 | BOOL readonly; 51 | BOOL posix; 52 | uint16_t namelen; 53 | WCHAR name[1]; 54 | } btrfs_create_snapshot; 55 | 56 | typedef struct { 57 | void* POINTER_32 subvol; 58 | BOOL readonly; 59 | BOOL posix; 60 | uint16_t namelen; 61 | WCHAR name[1]; 62 | } btrfs_create_snapshot32; 63 | 64 | #define BTRFS_COMPRESSION_ANY 0 65 | #define BTRFS_COMPRESSION_ZLIB 1 66 | #define BTRFS_COMPRESSION_LZO 2 67 | #define BTRFS_COMPRESSION_ZSTD 3 68 | 69 | typedef struct { 70 | uint64_t subvol; 71 | uint64_t inode; 72 | BOOL top; 73 | uint8_t type; 74 | uint32_t st_uid; 75 | uint32_t st_gid; 76 | uint32_t st_mode; 77 | uint64_t st_rdev; 78 | uint64_t flags; 79 | uint32_t inline_length; 80 | uint64_t disk_size_uncompressed; 81 | uint64_t disk_size_zlib; 82 | uint64_t disk_size_lzo; 83 | uint8_t compression_type; 84 | uint64_t disk_size_zstd; 85 | uint64_t sparse_size; 86 | uint32_t num_extents; 87 | } btrfs_inode_info; 88 | 89 | typedef struct { 90 | uint64_t flags; 91 | BOOL flags_changed; 92 | uint32_t st_uid; 93 | BOOL uid_changed; 94 | uint32_t st_gid; 95 | BOOL gid_changed; 96 | uint32_t st_mode; 97 | BOOL mode_changed; 98 | uint8_t compression_type; 99 | BOOL compression_type_changed; 100 | } btrfs_set_inode_info; 101 | 102 | typedef struct { 103 | uint32_t next_entry; 104 | uint64_t dev_id; 105 | uint64_t size; 106 | uint64_t max_size; 107 | BOOL readonly; 108 | BOOL missing; 109 | ULONG device_number; 110 | ULONG partition_number; 111 | uint64_t stats[5]; 112 | USHORT namelen; 113 | WCHAR name[1]; 114 | } btrfs_device; 115 | 116 | typedef struct { 117 | uint64_t dev_id; 118 | uint64_t alloc; 119 | } btrfs_usage_device; 120 | 121 | typedef struct { 122 | uint32_t next_entry; 123 | uint64_t type; 124 | uint64_t size; 125 | uint64_t used; 126 | uint64_t num_devices; 127 | btrfs_usage_device devices[1]; 128 | } btrfs_usage; 129 | 130 | #define BTRFS_BALANCE_OPTS_ENABLED 0x001 131 | #define BTRFS_BALANCE_OPTS_PROFILES 0x002 132 | #define BTRFS_BALANCE_OPTS_DEVID 0x004 133 | #define BTRFS_BALANCE_OPTS_DRANGE 0x008 134 | #define BTRFS_BALANCE_OPTS_VRANGE 0x010 135 | #define BTRFS_BALANCE_OPTS_LIMIT 0x020 136 | #define BTRFS_BALANCE_OPTS_STRIPES 0x040 137 | #define BTRFS_BALANCE_OPTS_USAGE 0x080 138 | #define BTRFS_BALANCE_OPTS_CONVERT 0x100 139 | #define BTRFS_BALANCE_OPTS_SOFT 0x200 140 | 141 | #define BLOCK_FLAG_SINGLE 0x1000000000000 // only used in balance 142 | 143 | typedef struct { 144 | uint64_t flags; 145 | uint64_t profiles; 146 | uint64_t devid; 147 | uint64_t drange_start; 148 | uint64_t drange_end; 149 | uint64_t vrange_start; 150 | uint64_t vrange_end; 151 | uint64_t limit_start; 152 | uint64_t limit_end; 153 | uint16_t stripes_start; 154 | uint16_t stripes_end; 155 | uint8_t usage_start; 156 | uint8_t usage_end; 157 | uint64_t convert; 158 | } btrfs_balance_opts; 159 | 160 | #define BTRFS_BALANCE_STOPPED 0 161 | #define BTRFS_BALANCE_RUNNING 1 162 | #define BTRFS_BALANCE_PAUSED 2 163 | #define BTRFS_BALANCE_REMOVAL 4 164 | #define BTRFS_BALANCE_ERROR 8 165 | #define BTRFS_BALANCE_SHRINKING 16 166 | 167 | typedef struct { 168 | uint32_t status; 169 | uint64_t chunks_left; 170 | uint64_t total_chunks; 171 | NTSTATUS error; 172 | btrfs_balance_opts data_opts; 173 | btrfs_balance_opts metadata_opts; 174 | btrfs_balance_opts system_opts; 175 | } btrfs_query_balance; 176 | 177 | typedef struct { 178 | btrfs_balance_opts opts[3]; 179 | } btrfs_start_balance; 180 | 181 | typedef struct { 182 | uint8_t uuid[16]; 183 | BOOL missing; 184 | USHORT name_length; 185 | WCHAR name[1]; 186 | } btrfs_filesystem_device; 187 | 188 | typedef struct { 189 | uint32_t next_entry; 190 | uint8_t uuid[16]; 191 | uint32_t num_devices; 192 | btrfs_filesystem_device device; 193 | } btrfs_filesystem; 194 | 195 | #define BTRFS_SCRUB_STOPPED 0 196 | #define BTRFS_SCRUB_RUNNING 1 197 | #define BTRFS_SCRUB_PAUSED 2 198 | 199 | typedef struct { 200 | uint32_t next_entry; 201 | uint64_t address; 202 | uint64_t device; 203 | BOOL recovered; 204 | BOOL is_metadata; 205 | BOOL parity; 206 | 207 | union { 208 | struct { 209 | uint64_t subvol; 210 | uint64_t offset; 211 | uint16_t filename_length; 212 | WCHAR filename[1]; 213 | } data; 214 | 215 | struct { 216 | uint64_t root; 217 | uint8_t level; 218 | KEY firstitem; 219 | } metadata; 220 | }; 221 | } btrfs_scrub_error; 222 | 223 | typedef struct { 224 | uint32_t status; 225 | LARGE_INTEGER start_time; 226 | LARGE_INTEGER finish_time; 227 | uint64_t chunks_left; 228 | uint64_t total_chunks; 229 | uint64_t data_scrubbed; 230 | uint64_t duration; 231 | NTSTATUS error; 232 | uint32_t num_errors; 233 | btrfs_scrub_error errors; 234 | } btrfs_query_scrub; 235 | 236 | typedef struct { 237 | uint64_t inode; 238 | uint8_t type; 239 | uint64_t st_rdev; 240 | uint16_t namelen; 241 | WCHAR name[1]; 242 | } btrfs_mknod; 243 | 244 | typedef struct { 245 | uint64_t generation; 246 | BTRFS_UUID uuid; 247 | } btrfs_received_subvol; 248 | 249 | typedef struct { 250 | USHORT namelen; 251 | USHORT valuelen; 252 | char data[1]; 253 | } btrfs_set_xattr; 254 | 255 | typedef struct { 256 | BOOL readonly; 257 | BOOL posix; 258 | USHORT namelen; 259 | WCHAR name[1]; 260 | } btrfs_create_subvol; 261 | 262 | typedef struct { 263 | BTRFS_UUID uuid; 264 | uint64_t ctransid; 265 | } btrfs_find_subvol; 266 | 267 | typedef struct { 268 | HANDLE parent; 269 | ULONG num_clones; 270 | HANDLE clones[1]; 271 | } btrfs_send_subvol; 272 | 273 | typedef struct { 274 | void* POINTER_32 parent; 275 | ULONG num_clones; 276 | void* POINTER_32 clones[1]; 277 | } btrfs_send_subvol32; 278 | 279 | typedef struct { 280 | uint64_t device; 281 | uint64_t size; 282 | } btrfs_resize; 283 | 284 | typedef struct { 285 | uint8_t csum_type; 286 | uint8_t csum_length; 287 | uint64_t num_sectors; 288 | uint8_t data[1]; 289 | } btrfs_csum_info; 290 | -------------------------------------------------------------------------------- /src/cache.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #include "btrfs_drv.h" 19 | 20 | CACHE_MANAGER_CALLBACKS cache_callbacks; 21 | 22 | static BOOLEAN __stdcall acquire_for_lazy_write(PVOID Context, BOOLEAN Wait) { 23 | PFILE_OBJECT FileObject = Context; 24 | fcb* fcb = FileObject->FsContext; 25 | 26 | TRACE("(%p, %u)\n", Context, Wait); 27 | 28 | if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, Wait)) 29 | return false; 30 | 31 | if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, Wait)) { 32 | ExReleaseResourceLite(&fcb->Vcb->tree_lock); 33 | return false; 34 | } 35 | 36 | fcb->lazy_writer_thread = KeGetCurrentThread(); 37 | 38 | IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); 39 | 40 | return true; 41 | } 42 | 43 | static void __stdcall release_from_lazy_write(PVOID Context) { 44 | PFILE_OBJECT FileObject = Context; 45 | fcb* fcb = FileObject->FsContext; 46 | 47 | TRACE("(%p)\n", Context); 48 | 49 | fcb->lazy_writer_thread = NULL; 50 | 51 | ExReleaseResourceLite(fcb->Header.Resource); 52 | 53 | ExReleaseResourceLite(&fcb->Vcb->tree_lock); 54 | 55 | if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) 56 | IoSetTopLevelIrp(NULL); 57 | } 58 | 59 | static BOOLEAN __stdcall acquire_for_read_ahead(PVOID Context, BOOLEAN Wait) { 60 | PFILE_OBJECT FileObject = Context; 61 | fcb* fcb = FileObject->FsContext; 62 | 63 | TRACE("(%p, %u)\n", Context, Wait); 64 | 65 | if (!ExAcquireResourceSharedLite(fcb->Header.Resource, Wait)) 66 | return false; 67 | 68 | IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); 69 | 70 | return true; 71 | } 72 | 73 | static void __stdcall release_from_read_ahead(PVOID Context) { 74 | PFILE_OBJECT FileObject = Context; 75 | fcb* fcb = FileObject->FsContext; 76 | 77 | TRACE("(%p)\n", Context); 78 | 79 | ExReleaseResourceLite(fcb->Header.Resource); 80 | 81 | if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) 82 | IoSetTopLevelIrp(NULL); 83 | } 84 | 85 | void init_cache() { 86 | cache_callbacks.AcquireForLazyWrite = acquire_for_lazy_write; 87 | cache_callbacks.ReleaseFromLazyWrite = release_from_lazy_write; 88 | cache_callbacks.AcquireForReadAhead = acquire_for_read_ahead; 89 | cache_callbacks.ReleaseFromReadAhead = release_from_read_ahead; 90 | } 91 | -------------------------------------------------------------------------------- /src/calcthread.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #include "btrfs_drv.h" 19 | #include "zstd/lib/common/xxhash.h" 20 | #include "crc32c.h" 21 | 22 | void calc_thread_main(device_extension* Vcb, calc_job* cj) { 23 | while (true) { 24 | KIRQL irql; 25 | calc_job* cj2; 26 | uint8_t* src; 27 | void* dest; 28 | bool last_one = false; 29 | 30 | KeAcquireSpinLock(&Vcb->calcthreads.spinlock, &irql); 31 | 32 | if (cj && cj->not_started == 0) { 33 | KeReleaseSpinLock(&Vcb->calcthreads.spinlock, irql); 34 | break; 35 | } 36 | 37 | if (cj) 38 | cj2 = cj; 39 | else { 40 | if (IsListEmpty(&Vcb->calcthreads.job_list)) { 41 | KeReleaseSpinLock(&Vcb->calcthreads.spinlock, irql); 42 | break; 43 | } 44 | 45 | cj2 = CONTAINING_RECORD(Vcb->calcthreads.job_list.Flink, calc_job, list_entry); 46 | } 47 | 48 | src = cj2->in; 49 | dest = cj2->out; 50 | 51 | switch (cj2->type) { 52 | case calc_thread_crc32c: 53 | case calc_thread_xxhash: 54 | case calc_thread_sha256: 55 | case calc_thread_blake2: 56 | cj2->in = (uint8_t*)cj2->in + Vcb->superblock.sector_size; 57 | cj2->out = (uint8_t*)cj2->out + Vcb->csum_size; 58 | break; 59 | 60 | default: 61 | break; 62 | } 63 | 64 | cj2->not_started--; 65 | 66 | if (cj2->not_started == 0) { 67 | RemoveEntryList(&cj2->list_entry); 68 | last_one = true; 69 | } 70 | 71 | KeReleaseSpinLock(&Vcb->calcthreads.spinlock, irql); 72 | 73 | switch (cj2->type) { 74 | case calc_thread_crc32c: 75 | *(uint32_t*)dest = ~calc_crc32c(0xffffffff, src, Vcb->superblock.sector_size); 76 | break; 77 | 78 | case calc_thread_xxhash: 79 | *(uint64_t*)dest = XXH64(src, Vcb->superblock.sector_size, 0); 80 | break; 81 | 82 | case calc_thread_sha256: 83 | calc_sha256(dest, src, Vcb->superblock.sector_size); 84 | break; 85 | 86 | case calc_thread_blake2: 87 | blake2b(dest, BLAKE2_HASH_SIZE, src, Vcb->superblock.sector_size); 88 | break; 89 | 90 | case calc_thread_decomp_zlib: 91 | cj2->Status = zlib_decompress(src, cj2->inlen, dest, cj2->outlen); 92 | 93 | if (!NT_SUCCESS(cj2->Status)) 94 | ERR("zlib_decompress returned %08lx\n", cj2->Status); 95 | break; 96 | 97 | case calc_thread_decomp_lzo: 98 | cj2->Status = lzo_decompress(src, cj2->inlen, dest, cj2->outlen, cj2->off); 99 | 100 | if (!NT_SUCCESS(cj2->Status)) 101 | ERR("lzo_decompress returned %08lx\n", cj2->Status); 102 | break; 103 | 104 | case calc_thread_decomp_zstd: 105 | cj2->Status = zstd_decompress(src, cj2->inlen, dest, cj2->outlen); 106 | 107 | if (!NT_SUCCESS(cj2->Status)) 108 | ERR("zstd_decompress returned %08lx\n", cj2->Status); 109 | break; 110 | 111 | case calc_thread_comp_zlib: 112 | cj2->Status = zlib_compress(src, cj2->inlen, dest, cj2->outlen, Vcb->options.zlib_level, &cj2->space_left); 113 | 114 | if (!NT_SUCCESS(cj2->Status)) 115 | ERR("zlib_compress returned %08lx\n", cj2->Status); 116 | break; 117 | 118 | case calc_thread_comp_lzo: 119 | cj2->Status = lzo_compress(src, cj2->inlen, dest, cj2->outlen, &cj2->space_left); 120 | 121 | if (!NT_SUCCESS(cj2->Status)) 122 | ERR("lzo_compress returned %08lx\n", cj2->Status); 123 | break; 124 | 125 | case calc_thread_comp_zstd: 126 | cj2->Status = zstd_compress(src, cj2->inlen, dest, cj2->outlen, Vcb->options.zstd_level, &cj2->space_left); 127 | 128 | if (!NT_SUCCESS(cj2->Status)) 129 | ERR("zstd_compress returned %08lx\n", cj2->Status); 130 | break; 131 | } 132 | 133 | if (InterlockedDecrement(&cj2->left) == 0) 134 | KeSetEvent(&cj2->event, 0, false); 135 | 136 | if (last_one) 137 | break; 138 | } 139 | } 140 | 141 | void do_calc_job(device_extension* Vcb, uint8_t* data, uint32_t sectors, void* csum) { 142 | KIRQL irql; 143 | calc_job cj; 144 | 145 | cj.in = data; 146 | cj.out = csum; 147 | cj.left = cj.not_started = sectors; 148 | 149 | switch (Vcb->superblock.csum_type) { 150 | case CSUM_TYPE_CRC32C: 151 | cj.type = calc_thread_crc32c; 152 | break; 153 | 154 | case CSUM_TYPE_XXHASH: 155 | cj.type = calc_thread_xxhash; 156 | break; 157 | 158 | case CSUM_TYPE_SHA256: 159 | cj.type = calc_thread_sha256; 160 | break; 161 | 162 | case CSUM_TYPE_BLAKE2: 163 | cj.type = calc_thread_blake2; 164 | break; 165 | } 166 | 167 | KeInitializeEvent(&cj.event, NotificationEvent, false); 168 | 169 | KeAcquireSpinLock(&Vcb->calcthreads.spinlock, &irql); 170 | 171 | InsertTailList(&Vcb->calcthreads.job_list, &cj.list_entry); 172 | 173 | KeSetEvent(&Vcb->calcthreads.event, 0, false); 174 | KeClearEvent(&Vcb->calcthreads.event); 175 | 176 | KeReleaseSpinLock(&Vcb->calcthreads.spinlock, irql); 177 | 178 | calc_thread_main(Vcb, &cj); 179 | 180 | KeWaitForSingleObject(&cj.event, Executive, KernelMode, false, NULL); 181 | } 182 | 183 | NTSTATUS add_calc_job_decomp(device_extension* Vcb, uint8_t compression, void* in, unsigned int inlen, 184 | void* out, unsigned int outlen, unsigned int off, calc_job** pcj) { 185 | calc_job* cj; 186 | KIRQL irql; 187 | 188 | cj = ExAllocatePoolWithTag(NonPagedPool, sizeof(calc_job), ALLOC_TAG); 189 | if (!cj) { 190 | ERR("out of memory\n"); 191 | return STATUS_INSUFFICIENT_RESOURCES; 192 | } 193 | 194 | cj->in = in; 195 | cj->inlen = inlen; 196 | cj->out = out; 197 | cj->outlen = outlen; 198 | cj->off = off; 199 | cj->left = cj->not_started = 1; 200 | cj->Status = STATUS_SUCCESS; 201 | 202 | switch (compression) { 203 | case BTRFS_COMPRESSION_ZLIB: 204 | cj->type = calc_thread_decomp_zlib; 205 | break; 206 | 207 | case BTRFS_COMPRESSION_LZO: 208 | cj->type = calc_thread_decomp_lzo; 209 | break; 210 | 211 | case BTRFS_COMPRESSION_ZSTD: 212 | cj->type = calc_thread_decomp_zstd; 213 | break; 214 | 215 | default: 216 | ERR("unexpected compression type %x\n", compression); 217 | ExFreePool(cj); 218 | return STATUS_NOT_SUPPORTED; 219 | } 220 | 221 | KeInitializeEvent(&cj->event, NotificationEvent, false); 222 | 223 | KeAcquireSpinLock(&Vcb->calcthreads.spinlock, &irql); 224 | 225 | InsertTailList(&Vcb->calcthreads.job_list, &cj->list_entry); 226 | 227 | KeSetEvent(&Vcb->calcthreads.event, 0, false); 228 | KeClearEvent(&Vcb->calcthreads.event); 229 | 230 | KeReleaseSpinLock(&Vcb->calcthreads.spinlock, irql); 231 | 232 | *pcj = cj; 233 | 234 | return STATUS_SUCCESS; 235 | } 236 | 237 | NTSTATUS add_calc_job_comp(device_extension* Vcb, uint8_t compression, void* in, unsigned int inlen, 238 | void* out, unsigned int outlen, calc_job** pcj) { 239 | calc_job* cj; 240 | KIRQL irql; 241 | 242 | cj = ExAllocatePoolWithTag(NonPagedPool, sizeof(calc_job), ALLOC_TAG); 243 | if (!cj) { 244 | ERR("out of memory\n"); 245 | return STATUS_INSUFFICIENT_RESOURCES; 246 | } 247 | 248 | cj->in = in; 249 | cj->inlen = inlen; 250 | cj->out = out; 251 | cj->outlen = outlen; 252 | cj->left = cj->not_started = 1; 253 | cj->Status = STATUS_SUCCESS; 254 | 255 | switch (compression) { 256 | case BTRFS_COMPRESSION_ZLIB: 257 | cj->type = calc_thread_comp_zlib; 258 | break; 259 | 260 | case BTRFS_COMPRESSION_LZO: 261 | cj->type = calc_thread_comp_lzo; 262 | break; 263 | 264 | case BTRFS_COMPRESSION_ZSTD: 265 | cj->type = calc_thread_comp_zstd; 266 | break; 267 | 268 | default: 269 | ERR("unexpected compression type %x\n", compression); 270 | ExFreePool(cj); 271 | return STATUS_NOT_SUPPORTED; 272 | } 273 | 274 | KeInitializeEvent(&cj->event, NotificationEvent, false); 275 | 276 | KeAcquireSpinLock(&Vcb->calcthreads.spinlock, &irql); 277 | 278 | InsertTailList(&Vcb->calcthreads.job_list, &cj->list_entry); 279 | 280 | KeSetEvent(&Vcb->calcthreads.event, 0, false); 281 | KeClearEvent(&Vcb->calcthreads.event); 282 | 283 | KeReleaseSpinLock(&Vcb->calcthreads.spinlock, irql); 284 | 285 | *pcj = cj; 286 | 287 | return STATUS_SUCCESS; 288 | } 289 | 290 | _Function_class_(KSTART_ROUTINE) 291 | void __stdcall calc_thread(void* context) { 292 | drv_calc_thread* thread = context; 293 | device_extension* Vcb = thread->DeviceObject->DeviceExtension; 294 | 295 | ObReferenceObject(thread->DeviceObject); 296 | 297 | KeSetSystemAffinityThread((KAFFINITY)1 << thread->number); 298 | 299 | while (true) { 300 | KeWaitForSingleObject(&Vcb->calcthreads.event, Executive, KernelMode, false, NULL); 301 | 302 | calc_thread_main(Vcb, NULL); 303 | 304 | if (thread->quit) 305 | break; 306 | } 307 | 308 | ObDereferenceObject(thread->DeviceObject); 309 | 310 | KeSetEvent(&thread->finished, 0, false); 311 | 312 | PsTerminateSystemThread(STATUS_SUCCESS); 313 | } 314 | -------------------------------------------------------------------------------- /src/crc32c-aarch64.asm: -------------------------------------------------------------------------------- 1 | AREA .text, CODE, READONLY 2 | 3 | GLOBAL calc_crc32c_hw 4 | 5 | ; uint32_t calc_crc32c_hw(uint32_t seed, const uint8_t* buf, uint32_t len); 6 | calc_crc32c_hw 7 | ; w0 = crc / seed 8 | ; x1 = buf 9 | ; w2 = len 10 | ; x3 = scratch 11 | 12 | cmp w2, #8 13 | b.lt crchw_stragglers 14 | 15 | ldr x3, [x1] 16 | crc32cx w0, w0, x3 17 | 18 | add x1, x1, #8 19 | sub w2, w2, #8 20 | b calc_crc32c_hw 21 | 22 | crchw_stragglers 23 | cmp w2, #4 24 | b.lt crchw_stragglers2 25 | 26 | ldr w3, [x1] 27 | crc32cw w0, w0, w3 28 | 29 | add x1, x1, #4 30 | sub w2, w2, #4 31 | 32 | crchw_stragglers2 33 | cmp w2, #2 34 | b.lt crchw_stragglers3 35 | 36 | ldrh w3, [x1] 37 | crc32ch w0, w0, w3 38 | 39 | add x1, x1, #2 40 | sub w2, w2, #2 41 | 42 | crchw_stragglers3 43 | cmp w2, #0 44 | b.eq crchw_end 45 | 46 | ldrb w3, [x1] 47 | crc32cb w0, w0, w3 48 | 49 | crchw_end 50 | ret 51 | 52 | END 53 | -------------------------------------------------------------------------------- /src/crc32c-gas.S: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2020 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | .intel_syntax noprefix 19 | 20 | #ifdef __x86_64__ 21 | 22 | .extern crctable 23 | .global calc_crc32c_sw 24 | 25 | /* uint32_t __stdcall calc_crc32c_sw(uint32_t seed, uint8_t* msg, uint32_t msglen); */ 26 | 27 | calc_crc32c_sw: 28 | 29 | /* rax = crc / seed 30 | * rdx = buf 31 | * r8 = len 32 | * rcx = tmp 33 | * r10 = tmp2 */ 34 | 35 | mov rax, rcx 36 | 37 | crcloop: 38 | test r8, r8 39 | jz crcend 40 | 41 | mov rcx, rax 42 | shr rcx, 8 43 | mov r10b, byte ptr [rdx] 44 | xor al, r10b 45 | and rax, 255 46 | shl rax, 2 47 | movabs r10, offset crctable 48 | mov eax, dword ptr [r10 + rax] 49 | xor rax, rcx 50 | 51 | inc rdx 52 | dec r8 53 | 54 | jmp crcloop 55 | 56 | crcend: 57 | ret 58 | 59 | /****************************************************/ 60 | 61 | /* uint32_t __stdcall calc_crc32c_hw(uint32_t seed, uint8_t* msg, uint32_t msglen); */ 62 | 63 | .global calc_crc32c_hw 64 | 65 | calc_crc32c_hw: 66 | 67 | /* rax = crc / seed 68 | * rdx = buf 69 | * r8 = len */ 70 | 71 | mov rax, rcx 72 | 73 | crchw_loop: 74 | cmp r8, 8 75 | jl crchw_stragglers 76 | 77 | crc32 rax, qword ptr [rdx] 78 | 79 | add rdx, 8 80 | sub r8, 8 81 | jmp crchw_loop 82 | 83 | crchw_stragglers: 84 | cmp r8, 4 85 | jl crchw_stragglers2 86 | 87 | crc32 eax, dword ptr [rdx] 88 | 89 | add rdx, 4 90 | sub r8, 4 91 | 92 | crchw_stragglers2: 93 | cmp r8, 2 94 | jl crchw_stragglers3 95 | 96 | crc32 eax, word ptr [rdx] 97 | 98 | add rdx, 2 99 | sub r8, 2 100 | 101 | crchw_stragglers3: 102 | test r8, r8 103 | jz crchw_end 104 | 105 | crc32 eax, byte ptr [rdx] 106 | inc rdx 107 | dec r8 108 | jmp crchw_stragglers3 109 | 110 | crchw_end: 111 | ret 112 | 113 | #elif defined(_X86_) 114 | 115 | .extern _crctable 116 | .global _calc_crc32c_sw@12 117 | .global _calc_crc32c_hw@12 118 | 119 | /* uint32_t __stdcall calc_crc32c_sw(uint32_t seed, uint8_t* msg, uint32_t msglen); */ 120 | 121 | _calc_crc32c_sw@12: 122 | 123 | push ebp 124 | mov ebp, esp 125 | 126 | push esi 127 | push ebx 128 | 129 | mov eax, [ebp+8] 130 | mov edx, [ebp+12] 131 | mov ebx, [ebp+16] 132 | 133 | /* eax = crc / seed 134 | * ebx = len 135 | * esi = tmp 136 | * edx = buf 137 | * ecx = tmp2 */ 138 | 139 | crcloop: 140 | test ebx, ebx 141 | jz crcend 142 | 143 | mov esi, eax 144 | shr esi, 8 145 | mov cl, byte ptr [edx] 146 | xor al, cl 147 | and eax, 255 148 | shl eax, 2 149 | mov eax, [_crctable + eax] 150 | xor eax, esi 151 | 152 | inc edx 153 | dec ebx 154 | 155 | jmp crcloop 156 | 157 | crcend: 158 | pop ebx 159 | pop esi 160 | 161 | pop ebp 162 | 163 | ret 12 164 | 165 | /****************************************************/ 166 | 167 | /* uint32_t __stdcall calc_crc32c_hw(uint32_t seed, uint8_t* msg, uint32_t msglen); */ 168 | 169 | _calc_crc32c_hw@12: 170 | 171 | push ebp 172 | mov ebp, esp 173 | 174 | mov eax, [ebp+8] 175 | mov edx, [ebp+12] 176 | mov ecx, [ebp+16] 177 | 178 | /* eax = crc / seed 179 | * ecx = len 180 | * edx = buf */ 181 | 182 | crchw_loop: 183 | cmp ecx, 4 184 | jl crchw_stragglers 185 | 186 | crc32 eax, dword ptr [edx] 187 | 188 | add edx, 4 189 | sub ecx, 4 190 | jmp crchw_loop 191 | 192 | crchw_stragglers: 193 | cmp ecx, 2 194 | jl crchw_stragglers2 195 | 196 | crc32 eax, word ptr [edx] 197 | 198 | add edx, 2 199 | sub ecx, 2 200 | 201 | crchw_stragglers2: 202 | test ecx, ecx 203 | jz crchw_end 204 | 205 | crc32 eax, byte ptr [edx] 206 | inc edx 207 | dec ecx 208 | jmp crchw_stragglers2 209 | 210 | crchw_end: 211 | pop ebp 212 | 213 | ret 12 214 | 215 | #endif 216 | -------------------------------------------------------------------------------- /src/crc32c-masm.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Mark Harmstone 2020 2 | ; 3 | ; This file is part of WinBtrfs. 4 | ; 5 | ; WinBtrfs is free software: you can redistribute it and/or modify 6 | ; it under the terms of the GNU Lesser General Public Licence as published by 7 | ; the Free Software Foundation, either version 3 of the Licence, or 8 | ; (at your option) any later version. 9 | ; 10 | ; WinBtrfs is distributed in the hope that it will be useful, 11 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ; GNU Lesser General Public Licence for more details. 14 | ; 15 | ; You should have received a copy of the GNU Lesser General Public Licence 16 | ; along with WinBtrfs. If not, see . 17 | 18 | IFDEF RAX 19 | ELSE 20 | .686P 21 | ENDIF 22 | 23 | _TEXT SEGMENT 24 | 25 | IFDEF RAX 26 | 27 | EXTERN crctable:qword 28 | 29 | PUBLIC calc_crc32c_sw 30 | 31 | ; uint32_t __stdcall calc_crc32c_sw(uint32_t seed, uint8_t* msg, uint32_t msglen); 32 | 33 | calc_crc32c_sw: 34 | 35 | ; rax = crc / seed 36 | ; rdx = buf 37 | ; r8 = len 38 | ; rcx = tmp 39 | ; r10 = tmp2 40 | 41 | mov rax, rcx 42 | 43 | crcloop: 44 | test r8, r8 45 | jz crcend 46 | 47 | mov rcx, rax 48 | shr rcx, 8 49 | mov r10b, byte ptr [rdx] 50 | xor al, r10b 51 | and rax, 255 52 | shl rax, 2 53 | mov r10, offset crctable 54 | mov eax, dword ptr [r10 + rax] 55 | xor rax, rcx 56 | 57 | inc rdx 58 | dec r8 59 | 60 | jmp crcloop 61 | 62 | crcend: 63 | ret 64 | 65 | ; **************************************************** 66 | 67 | ; uint32_t __stdcall calc_crc32c_hw(uint32_t seed, uint8_t* msg, uint32_t msglen); 68 | 69 | PUBLIC calc_crc32c_hw 70 | 71 | calc_crc32c_hw: 72 | 73 | ; rax = crc / seed 74 | ; rdx = buf 75 | ; r8 = len 76 | 77 | mov rax, rcx 78 | 79 | crchw_loop: 80 | cmp r8, 8 81 | jl crchw_stragglers 82 | 83 | crc32 rax, qword ptr [rdx] 84 | 85 | add rdx, 8 86 | sub r8, 8 87 | jmp crchw_loop 88 | 89 | crchw_stragglers: 90 | cmp r8, 4 91 | jl crchw_stragglers2 92 | 93 | crc32 eax, dword ptr [rdx] 94 | 95 | add rdx, 4 96 | sub r8, 4 97 | 98 | crchw_stragglers2: 99 | cmp r8, 2 100 | jl crchw_stragglers3 101 | 102 | crc32 eax, word ptr [rdx] 103 | 104 | add rdx, 2 105 | sub r8, 2 106 | 107 | crchw_stragglers3: 108 | test r8, r8 109 | jz crchw_end 110 | 111 | crc32 eax, byte ptr [rdx] 112 | inc rdx 113 | dec r8 114 | jmp crchw_stragglers3 115 | 116 | crchw_end: 117 | ret 118 | 119 | ELSE 120 | 121 | EXTERN crctable:ABS 122 | 123 | ; uint32_t __stdcall calc_crc32c_sw(uint32_t seed, uint8_t* msg, uint32_t msglen); 124 | 125 | PUBLIC calc_crc32c_sw@12 126 | 127 | calc_crc32c_sw@12: 128 | 129 | push ebp 130 | mov ebp, esp 131 | 132 | push esi 133 | push ebx 134 | 135 | mov eax, [ebp+8] 136 | mov edx, [ebp+12] 137 | mov ebx, [ebp+16] 138 | 139 | ; eax = crc / seed 140 | ; ebx = len 141 | ; esi = tmp 142 | ; edx = buf 143 | ; ecx = tmp2 144 | 145 | crcloop: 146 | test ebx, ebx 147 | jz crcend 148 | 149 | mov esi, eax 150 | shr esi, 8 151 | mov cl, byte ptr [edx] 152 | xor al, cl 153 | and eax, 255 154 | shl eax, 2 155 | mov eax, [crctable + eax] 156 | xor eax, esi 157 | 158 | inc edx 159 | dec ebx 160 | 161 | jmp crcloop 162 | 163 | crcend: 164 | pop ebx 165 | pop esi 166 | 167 | pop ebp 168 | 169 | ret 12 170 | 171 | ; **************************************************** 172 | 173 | ; uint32_t __stdcall calc_crc32c_hw(uint32_t seed, uint8_t* msg, uint32_t msglen); 174 | 175 | PUBLIC calc_crc32c_hw@12 176 | 177 | calc_crc32c_hw@12: 178 | 179 | push ebp 180 | mov ebp, esp 181 | 182 | mov eax, [ebp+8] 183 | mov edx, [ebp+12] 184 | mov ecx, [ebp+16] 185 | 186 | ; eax = crc / seed 187 | ; ecx = len 188 | ; edx = buf 189 | 190 | crchw_loop: 191 | cmp ecx, 4 192 | jl crchw_stragglers 193 | 194 | crc32 eax, dword ptr [edx] 195 | 196 | add edx, 4 197 | sub ecx, 4 198 | jmp crchw_loop 199 | 200 | crchw_stragglers: 201 | cmp ecx, 2 202 | jl crchw_stragglers2 203 | 204 | crc32 eax, word ptr [edx] 205 | 206 | add edx, 2 207 | sub ecx, 2 208 | 209 | crchw_stragglers2: 210 | test ecx, ecx 211 | jz crchw_end 212 | 213 | crc32 eax, byte ptr [edx] 214 | inc edx 215 | dec ecx 216 | jmp crchw_stragglers2 217 | 218 | crchw_end: 219 | pop ebp 220 | 221 | ret 12 222 | 223 | ENDIF 224 | 225 | _TEXT ENDS 226 | 227 | end 228 | -------------------------------------------------------------------------------- /src/crc32c.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #include "crc32c.h" 19 | #include 20 | #include 21 | #include 22 | 23 | crc_func calc_crc32c = calc_crc32c_sw; 24 | 25 | const uint32_t crctable[] = { 26 | 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, 27 | 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 28 | 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, 29 | 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, 30 | 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 31 | 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, 32 | 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, 33 | 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 34 | 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, 35 | 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, 36 | 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 37 | 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, 38 | 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, 39 | 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 40 | 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, 41 | 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, 42 | 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 43 | 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, 44 | 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, 45 | 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 46 | 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, 47 | 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, 48 | 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 49 | 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, 50 | 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, 51 | 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 52 | 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, 53 | 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, 54 | 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 55 | 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, 56 | 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, 57 | 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351, 58 | }; 59 | 60 | // x86 and amd64 versions live in asm files 61 | #if !defined(_X86_) && !defined(_AMD64_) 62 | uint32_t __stdcall calc_crc32c_sw(_In_ uint32_t seed, _In_reads_bytes_(msglen) uint8_t* msg, _In_ uint32_t msglen) { 63 | uint32_t rem = seed; 64 | 65 | for (uint32_t i = 0; i < msglen; i++) { 66 | rem = crctable[(rem ^ msg[i]) & 0xff] ^ (rem >> 8); 67 | } 68 | 69 | return rem; 70 | } 71 | #endif 72 | -------------------------------------------------------------------------------- /src/crc32c.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #if defined(_X86_) || defined(_AMD64_) || defined(_ARM64_) 10 | uint32_t __stdcall calc_crc32c_hw(uint32_t seed, uint8_t* msg, uint32_t msglen); 11 | #endif 12 | 13 | uint32_t __stdcall calc_crc32c_sw(uint32_t seed, uint8_t* msg, uint32_t msglen); 14 | 15 | typedef uint32_t (__stdcall *crc_func)(uint32_t seed, uint8_t* msg, uint32_t msglen); 16 | 17 | extern crc_func calc_crc32c; 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /src/fsrtl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PROJECT: ReactOS Kernel - Vista+ APIs 3 | * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 | * FILE: lib/drivers/ntoskrnl_vista/fsrtl.c 5 | * PURPOSE: FsRtl functions of Vista+ 6 | * PROGRAMMERS: Pierre Schweitzer 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | FORCEINLINE 13 | BOOLEAN 14 | IsNullGuid(IN PGUID Guid) 15 | { 16 | if (Guid->Data1 == 0 && Guid->Data2 == 0 && Guid->Data3 == 0 && 17 | ((ULONG *)Guid->Data4)[0] == 0 && ((ULONG *)Guid->Data4)[1] == 0) 18 | { 19 | return TRUE; 20 | } 21 | 22 | return FALSE; 23 | } 24 | 25 | FORCEINLINE 26 | BOOLEAN 27 | IsEven(IN USHORT Digit) 28 | { 29 | return ((Digit & 1) != 1); 30 | } 31 | 32 | NTSTATUS __stdcall compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer) 33 | { 34 | USHORT DataLength; 35 | ULONG ReparseTag; 36 | PREPARSE_GUID_DATA_BUFFER GuidBuffer; 37 | 38 | /* Validate data size range */ 39 | if (BufferLength < REPARSE_DATA_BUFFER_HEADER_SIZE || BufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) 40 | { 41 | return STATUS_IO_REPARSE_DATA_INVALID; 42 | } 43 | 44 | GuidBuffer = (PREPARSE_GUID_DATA_BUFFER)ReparseBuffer; 45 | DataLength = ReparseBuffer->ReparseDataLength; 46 | ReparseTag = ReparseBuffer->ReparseTag; 47 | 48 | /* Validate size consistency */ 49 | if (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE != BufferLength && DataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE != BufferLength) 50 | { 51 | return STATUS_IO_REPARSE_DATA_INVALID; 52 | } 53 | 54 | /* REPARSE_DATA_BUFFER is reserved for MS tags */ 55 | if (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE == BufferLength && !IsReparseTagMicrosoft(ReparseTag)) 56 | { 57 | return STATUS_IO_REPARSE_DATA_INVALID; 58 | } 59 | 60 | /* If that a GUID data buffer, its GUID cannot be null, and it cannot contain a MS tag */ 61 | if (DataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE == BufferLength && ((!IsReparseTagMicrosoft(ReparseTag) 62 | && IsNullGuid(&GuidBuffer->ReparseGuid)) || (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT || ReparseTag == IO_REPARSE_TAG_SYMLINK))) 63 | { 64 | return STATUS_IO_REPARSE_DATA_INVALID; 65 | } 66 | 67 | /* Check the data for MS non reserved tags */ 68 | if (!(ReparseTag & 0xFFF0000) && ReparseTag != IO_REPARSE_TAG_RESERVED_ZERO && ReparseTag != IO_REPARSE_TAG_RESERVED_ONE) 69 | { 70 | /* If that's a mount point, validate the MountPointReparseBuffer branch */ 71 | if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) 72 | { 73 | /* We need information */ 74 | if (DataLength >= REPARSE_DATA_BUFFER_HEADER_SIZE) 75 | { 76 | /* Substitue must be the first in row */ 77 | if (!ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset) 78 | { 79 | /* Substitude must be null-terminated */ 80 | if (ReparseBuffer->MountPointReparseBuffer.PrintNameOffset == ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(UNICODE_NULL)) 81 | { 82 | /* There must just be the Offset/Length fields + buffer + 2 null chars */ 83 | if (DataLength == ReparseBuffer->MountPointReparseBuffer.PrintNameLength + ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.SubstituteNameOffset)) + 2 * sizeof(UNICODE_NULL)) 84 | { 85 | return STATUS_SUCCESS; 86 | } 87 | } 88 | } 89 | } 90 | } 91 | else 92 | { 93 | #define FIELDS_SIZE (FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset)) 94 | 95 | /* If that's not a symlink, accept the MS tag as it */ 96 | if (ReparseTag != IO_REPARSE_TAG_SYMLINK) 97 | { 98 | return STATUS_SUCCESS; 99 | } 100 | 101 | /* We need information */ 102 | if (DataLength >= FIELDS_SIZE) 103 | { 104 | /* Validate lengths */ 105 | if (ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength && ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength) 106 | { 107 | /* Validate unicode strings */ 108 | if (IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength) && 109 | IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset)) 110 | { 111 | if ((DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset + ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE) 112 | && (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength + ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE)) 113 | { 114 | return STATUS_SUCCESS; 115 | } 116 | } 117 | } 118 | } 119 | #undef FIELDS_SIZE 120 | } 121 | 122 | return STATUS_IO_REPARSE_DATA_INVALID; 123 | } 124 | 125 | return STATUS_IO_REPARSE_TAG_INVALID; 126 | } 127 | -------------------------------------------------------------------------------- /src/galois.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #include "btrfs_drv.h" 19 | 20 | static const uint8_t glog[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, 21 | 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 22 | 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, 23 | 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, 24 | 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 25 | 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, 26 | 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, 27 | 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, 28 | 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, 29 | 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, 30 | 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, 31 | 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, 32 | 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, 33 | 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, 34 | 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16, 35 | 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x01}; 36 | 37 | static const uint8_t gilog[] = {0x00, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, 38 | 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71, 39 | 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, 40 | 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6, 41 | 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, 42 | 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, 43 | 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, 44 | 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, 45 | 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, 46 | 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, 47 | 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, 48 | 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, 49 | 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6, 50 | 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, 51 | 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, 52 | 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf}; 53 | 54 | // divides the bytes in data by 2^div 55 | void galois_divpower(uint8_t* data, uint8_t div, uint32_t len) { 56 | while (len > 0) { 57 | if (data[0] != 0) { 58 | if (gilog[data[0]] <= div) 59 | data[0] = glog[(gilog[data[0]] + (255 - div)) % 255]; 60 | else 61 | data[0] = glog[(gilog[data[0]] - div) % 255]; 62 | } 63 | 64 | data++; 65 | len--; 66 | } 67 | } 68 | 69 | uint8_t gpow2(uint8_t e) { 70 | return glog[e%255]; 71 | } 72 | 73 | uint8_t gmul(uint8_t a, uint8_t b) { 74 | if (a == 0 || b == 0) 75 | return 0; 76 | else 77 | return glog[(gilog[a] + gilog[b]) % 255]; 78 | } 79 | 80 | uint8_t gdiv(uint8_t a, uint8_t b) { 81 | if (b == 0) { 82 | return 0xff; // shouldn't happen 83 | } else if (a == 0) { 84 | return 0; 85 | } else { 86 | if (gilog[a] >= gilog[b]) 87 | return glog[(gilog[a] - gilog[b]) % 255]; 88 | else 89 | return glog[255-((gilog[b] - gilog[a]) % 255)]; 90 | } 91 | } 92 | 93 | // The code from the following functions is derived from the paper 94 | // "The mathematics of RAID-6", by H. Peter Anvin. 95 | // https://www.kernel.org/pub/linux/kernel/people/hpa/raid6.pdf 96 | 97 | #if defined(_AMD64_) || defined(_ARM64_) 98 | __inline static uint64_t galois_double_mask64(uint64_t v) { 99 | v &= 0x8080808080808080; 100 | return (v << 1) - (v >> 7); 101 | } 102 | #else 103 | __inline static uint32_t galois_double_mask32(uint32_t v) { 104 | v &= 0x80808080; 105 | return (v << 1) - (v >> 7); 106 | } 107 | #endif 108 | 109 | void galois_double(uint8_t* data, uint32_t len) { 110 | // FIXME - SIMD? 111 | 112 | #if defined(_AMD64_) || defined(_ARM64_) 113 | while (len > sizeof(uint64_t)) { 114 | uint64_t v = *((uint64_t*)data), vv; 115 | 116 | vv = (v << 1) & 0xfefefefefefefefe; 117 | vv ^= galois_double_mask64(v) & 0x1d1d1d1d1d1d1d1d; 118 | *((uint64_t*)data) = vv; 119 | 120 | data += sizeof(uint64_t); 121 | len -= sizeof(uint64_t); 122 | } 123 | #else 124 | while (len > sizeof(uint32_t)) { 125 | uint32_t v = *((uint32_t*)data), vv; 126 | 127 | vv = (v << 1) & 0xfefefefe; 128 | vv ^= galois_double_mask32(v) & 0x1d1d1d1d; 129 | *((uint32_t*)data) = vv; 130 | 131 | data += sizeof(uint32_t); 132 | len -= sizeof(uint32_t); 133 | } 134 | #endif 135 | 136 | while (len > 0) { 137 | data[0] = (data[0] << 1) ^ ((data[0] & 0x80) ? 0x1d : 0); 138 | data++; 139 | len--; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/mkbtrfs/mkbtrfs.rc.in: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "@CMAKE_CURRENT_SOURCE_DIR@/src/mkbtrfs/resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (United Kingdom) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) 19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK 20 | #pragma code_page(1252) 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Version 51 | // 52 | 53 | VS_VERSION_INFO VERSIONINFO 54 | FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 55 | PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 56 | FILEFLAGSMASK 0x17L 57 | #ifdef _DEBUG 58 | FILEFLAGS 0x1L 59 | #else 60 | FILEFLAGS 0x0L 61 | #endif 62 | FILEOS 0x4L 63 | FILETYPE 0x0L 64 | FILESUBTYPE 0x0L 65 | BEGIN 66 | BLOCK "StringFileInfo" 67 | BEGIN 68 | BLOCK "080904b0" 69 | BEGIN 70 | VALUE "FileDescription", "Btrfs formatting utility" 71 | VALUE "FileVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" 72 | VALUE "InternalName", "mkbtrfs" 73 | VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-24" 74 | VALUE "OriginalFilename", "mkbtrfs.exe" 75 | VALUE "ProductName", "WinBtrfs" 76 | VALUE "ProductVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" 77 | END 78 | END 79 | BLOCK "VarFileInfo" 80 | BEGIN 81 | VALUE "Translation", 0x809, 1200 82 | END 83 | END 84 | 85 | 86 | ///////////////////////////////////////////////////////////////////////////// 87 | // 88 | // String Table 89 | // 90 | 91 | STRINGTABLE 92 | BEGIN 93 | IDS_USAGE "Usage: %s device [label]\n" 94 | IDS_MULTIBYTE_FAILED "MultiByteToWideChar failed (error %lu)" 95 | IDS_CANT_RECOGNIZE_DRIVE "Could not recognize drive %s" 96 | IDS_CANT_LOAD_DLL "Unable to load %s" 97 | IDS_CANT_FIND_FORMATEX "Could not load function FormatEx in %s" 98 | IDS_FORMATEX_ERROR "FormatEx failed" 99 | IDS_SUCCESS "Completed successfully." 100 | IDS_CANT_FIND_SETSIZES "Could not load function SetSizes in %s" 101 | IDS_TOO_MANY_ARGS "Too many arguments." 102 | IDS_UNKNOWN_ARG "Unknown argument." 103 | IDS_NO_SECTOR_SIZE "No sector size specified." 104 | END 105 | 106 | STRINGTABLE 107 | BEGIN 108 | IDS_NO_NODE_SIZE "No node size specified." 109 | IDS_CANT_FIND_FUNCTION "Could not load function %s in %s" 110 | IDS_USAGE2 "The device parameter can either be a drive letter, e.g. D:, or a device path,\nsuch as \\Device\\Harddisk0\\Partition2.\n\nTo format the whole of the first hard disk without using partitions, you would\nneed to use the parameter \\Device\\Harddisk0\\Partition0.\n\nSupported flags:\n\n/sectorsize:num Sets the sector size. This must be a\n multiple of the size that the disk itself\n reports. The default is 4096, which should\n be used unless you have a good reason.\n\n/nodesize:num Sets the node size, i.e. the size of the\n metadata trees. The default is 16384. This\n needs to either be the same as sector size,\n or a power of two multiple.\n \n/csum:id Sets the checksum algorithm to use. Valid\n values are crc32c, xxhash, sha256, and\n blake2.\n\n/mixed Enables or disables mixed block groups,\n/notmixed which store data and and metadata in the\n same chunks. The default is disabled. This\n is only useful for very small filesystems.\n\n/extiref Enables or disables extended inode refs,\n/notextiref which increase the number of hardlinks\n allowed. The default is enabled.\n\n/skinnymetadata Enables or disable skinny metadata, which\n/notskinnymetadata allows more efficient storage of metadata\n refs. The default is enabled.\n\n/noholes Enables or disables whether sparse extents\n/notnoholes should be stored implicitly, which can save\n a little space. The default is enabled.\n\n/freespacetree Enables or disables storing the free-space\n/notfreespacetree cache in a tree rather than a blob.\n Supported from Linux 4.5. The default is\n enabled.\n\n/blockgrouptree Enables or disables the block group tree,\n/notblockgrouptree which can decrease mount times. Supported\n from Linux 6.1. The default is disabled.\n Implies /noholes and /freespacetree." 111 | IDS_NO_CSUM "No csum value given. Valid values are crc32c, xxhash, sha256, and blake2." 112 | IDS_INVALID_CSUM_TYPE "Invalid csum value. Valid values are crc32c, xxhash, sha256, and blake2." 113 | END 114 | 115 | #endif // English (United Kingdom) resources 116 | ///////////////////////////////////////////////////////////////////////////// 117 | 118 | 119 | 120 | #ifndef APSTUDIO_INVOKED 121 | ///////////////////////////////////////////////////////////////////////////// 122 | // 123 | // Generated from the TEXTINCLUDE 3 resource. 124 | // 125 | 126 | 127 | ///////////////////////////////////////////////////////////////////////////// 128 | #endif // not APSTUDIO_INVOKED 129 | 130 | -------------------------------------------------------------------------------- /src/mkbtrfs/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by mkbtrfs.rc 4 | // 5 | #define IDS_USAGE 101 6 | #define IDS_MULTIBYTE_FAILED 102 7 | #define IDS_CANT_RECOGNIZE_DRIVE 103 8 | #define IDS_CANT_LOAD_DLL 104 9 | #define IDS_CANT_FIND_FORMATEX 105 10 | #define IDS_FORMATEX_ERROR 106 11 | #define IDS_SUCCESS 107 12 | #define IDS_CANT_FIND_SETSIZES 108 13 | #define IDS_TOO_MANY_ARGS 109 14 | #define IDS_UNKNOWN_ARG 110 15 | #define IDS_NO_SECTOR_SIZE 111 16 | #define IDS_NO_NODE_SIZE 112 17 | #define IDS_CANT_FIND_FUNCTION 113 18 | #define IDS_USAGE2 114 19 | #define IDS_NO_CSUM 115 20 | #define IDS_INVALID_CSUM_TYPE 116 21 | 22 | // Next default values for new objects 23 | // 24 | #ifdef APSTUDIO_INVOKED 25 | #ifndef APSTUDIO_READONLY_SYMBOLS 26 | #define _APS_NEXT_RESOURCE_VALUE 102 27 | #define _APS_NEXT_COMMAND_VALUE 40001 28 | #define _APS_NEXT_CONTROL_VALUE 1001 29 | #define _APS_NEXT_SYMED_VALUE 101 30 | #endif 31 | #endif 32 | -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by btrfs.rc 4 | // 5 | 6 | // Next default values for new objects 7 | // 8 | #ifdef APSTUDIO_INVOKED 9 | #ifndef APSTUDIO_READONLY_SYMBOLS 10 | #define _APS_NEXT_RESOURCE_VALUE 101 11 | #define _APS_NEXT_COMMAND_VALUE 40001 12 | #define _APS_NEXT_CONTROL_VALUE 1001 13 | #define _APS_NEXT_SYMED_VALUE 101 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /src/sha256.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Public domain code from https://github.com/amosnier/sha-2 5 | 6 | // FIXME - x86 SHA extensions 7 | 8 | #define CHUNK_SIZE 64 9 | #define TOTAL_LEN_LEN 8 10 | 11 | /* 12 | * ABOUT bool: this file does not use bool in order to be as pre-C99 compatible as possible. 13 | */ 14 | 15 | /* 16 | * Comments from pseudo-code at https://en.wikipedia.org/wiki/SHA-2 are reproduced here. 17 | * When useful for clarification, portions of the pseudo-code are reproduced here too. 18 | */ 19 | 20 | /* 21 | * Initialize array of round constants: 22 | * (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311): 23 | */ 24 | static const uint32_t k[] = { 25 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 26 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 27 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 28 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 29 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 30 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 31 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 32 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 33 | }; 34 | 35 | struct buffer_state { 36 | const uint8_t * p; 37 | size_t len; 38 | size_t total_len; 39 | int single_one_delivered; /* bool */ 40 | int total_len_delivered; /* bool */ 41 | }; 42 | 43 | static inline uint32_t right_rot(uint32_t value, unsigned int count) 44 | { 45 | /* 46 | * Defined behaviour in standard C for all count where 0 < count < 32, 47 | * which is what we need here. 48 | */ 49 | return value >> count | value << (32 - count); 50 | } 51 | 52 | static void init_buf_state(struct buffer_state * state, const void * input, size_t len) 53 | { 54 | state->p = input; 55 | state->len = len; 56 | state->total_len = len; 57 | state->single_one_delivered = 0; 58 | state->total_len_delivered = 0; 59 | } 60 | 61 | /* Return value: bool */ 62 | static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state) 63 | { 64 | size_t space_in_chunk; 65 | 66 | if (state->total_len_delivered) { 67 | return 0; 68 | } 69 | 70 | if (state->len >= CHUNK_SIZE) { 71 | memcpy(chunk, state->p, CHUNK_SIZE); 72 | state->p += CHUNK_SIZE; 73 | state->len -= CHUNK_SIZE; 74 | return 1; 75 | } 76 | 77 | memcpy(chunk, state->p, state->len); 78 | chunk += state->len; 79 | space_in_chunk = CHUNK_SIZE - state->len; 80 | state->p += state->len; 81 | state->len = 0; 82 | 83 | /* If we are here, space_in_chunk is one at minimum. */ 84 | if (!state->single_one_delivered) { 85 | *chunk++ = 0x80; 86 | space_in_chunk -= 1; 87 | state->single_one_delivered = 1; 88 | } 89 | 90 | /* 91 | * Now: 92 | * - either there is enough space left for the total length, and we can conclude, 93 | * - or there is too little space left, and we have to pad the rest of this chunk with zeroes. 94 | * In the latter case, we will conclude at the next invokation of this function. 95 | */ 96 | if (space_in_chunk >= TOTAL_LEN_LEN) { 97 | const size_t left = space_in_chunk - TOTAL_LEN_LEN; 98 | size_t len = state->total_len; 99 | int i; 100 | memset(chunk, 0x00, left); 101 | chunk += left; 102 | 103 | /* Storing of len * 8 as a big endian 64-bit without overflow. */ 104 | chunk[7] = (uint8_t) (len << 3); 105 | len >>= 5; 106 | for (i = 6; i >= 0; i--) { 107 | chunk[i] = (uint8_t) len; 108 | len >>= 8; 109 | } 110 | state->total_len_delivered = 1; 111 | } else { 112 | memset(chunk, 0x00, space_in_chunk); 113 | } 114 | 115 | return 1; 116 | } 117 | 118 | /* 119 | * Limitations: 120 | * - Since input is a pointer in RAM, the data to hash should be in RAM, which could be a problem 121 | * for large data sizes. 122 | * - SHA algorithms theoretically operate on bit strings. However, this implementation has no support 123 | * for bit string lengths that are not multiples of eight, and it really operates on arrays of bytes. 124 | * In particular, the len parameter is a number of bytes. 125 | */ 126 | void calc_sha256(uint8_t* hash, const void* input, size_t len) 127 | { 128 | /* 129 | * Note 1: All integers (expect indexes) are 32-bit unsigned integers and addition is calculated modulo 2^32. 130 | * Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 = i = 63 131 | * Note 3: The compression function uses 8 working variables, a through h 132 | * Note 4: Big-endian convention is used when expressing the constants in this pseudocode, 133 | * and when parsing message block data from bytes to words, for example, 134 | * the first word of the input message "abc" after padding is 0x61626380 135 | */ 136 | 137 | /* 138 | * Initialize hash values: 139 | * (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19): 140 | */ 141 | uint32_t h[] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; 142 | unsigned i, j; 143 | 144 | /* 512-bit chunks is what we will operate on. */ 145 | uint8_t chunk[64]; 146 | 147 | struct buffer_state state; 148 | 149 | init_buf_state(&state, input, len); 150 | 151 | while (calc_chunk(chunk, &state)) { 152 | uint32_t ah[8]; 153 | 154 | const uint8_t *p = chunk; 155 | 156 | /* Initialize working variables to current hash value: */ 157 | for (i = 0; i < 8; i++) 158 | ah[i] = h[i]; 159 | 160 | /* Compression function main loop: */ 161 | for (i = 0; i < 4; i++) { 162 | /* 163 | * The w-array is really w[64], but since we only need 164 | * 16 of them at a time, we save stack by calculating 165 | * 16 at a time. 166 | * 167 | * This optimization was not there initially and the 168 | * rest of the comments about w[64] are kept in their 169 | * initial state. 170 | */ 171 | 172 | /* 173 | * create a 64-entry message schedule array w[0..63] of 32-bit words 174 | * (The initial values in w[0..63] don't matter, so many implementations zero them here) 175 | * copy chunk into first 16 words w[0..15] of the message schedule array 176 | */ 177 | uint32_t w[16]; 178 | 179 | for (j = 0; j < 16; j++) { 180 | if (i == 0) { 181 | w[j] = (uint32_t) p[0] << 24 | (uint32_t) p[1] << 16 | 182 | (uint32_t) p[2] << 8 | (uint32_t) p[3]; 183 | p += 4; 184 | } else { 185 | /* Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array: */ 186 | const uint32_t s0 = right_rot(w[(j + 1) & 0xf], 7) ^ right_rot(w[(j + 1) & 0xf], 18) ^ (w[(j + 1) & 0xf] >> 3); 187 | const uint32_t s1 = right_rot(w[(j + 14) & 0xf], 17) ^ right_rot(w[(j + 14) & 0xf], 19) ^ (w[(j + 14) & 0xf] >> 10); 188 | w[j] = w[j] + s0 + w[(j + 9) & 0xf] + s1; 189 | } 190 | const uint32_t s1 = right_rot(ah[4], 6) ^ right_rot(ah[4], 11) ^ right_rot(ah[4], 25); 191 | const uint32_t ch = (ah[4] & ah[5]) ^ (~ah[4] & ah[6]); 192 | const uint32_t temp1 = ah[7] + s1 + ch + k[i << 4 | j] + w[j]; 193 | const uint32_t s0 = right_rot(ah[0], 2) ^ right_rot(ah[0], 13) ^ right_rot(ah[0], 22); 194 | const uint32_t maj = (ah[0] & ah[1]) ^ (ah[0] & ah[2]) ^ (ah[1] & ah[2]); 195 | const uint32_t temp2 = s0 + maj; 196 | 197 | ah[7] = ah[6]; 198 | ah[6] = ah[5]; 199 | ah[5] = ah[4]; 200 | ah[4] = ah[3] + temp1; 201 | ah[3] = ah[2]; 202 | ah[2] = ah[1]; 203 | ah[1] = ah[0]; 204 | ah[0] = temp1 + temp2; 205 | } 206 | } 207 | 208 | /* Add the compressed chunk to the current hash value: */ 209 | for (i = 0; i < 8; i++) 210 | h[i] += ah[i]; 211 | } 212 | 213 | /* Produce the final hash value (big-endian): */ 214 | for (i = 0, j = 0; i < 8; i++) 215 | { 216 | hash[j++] = (uint8_t) (h[i] >> 24); 217 | hash[j++] = (uint8_t) (h[i] >> 16); 218 | hash[j++] = (uint8_t) (h[i] >> 8); 219 | hash[j++] = (uint8_t) h[i]; 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/shellext/balance.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include "../btrfsioctl.h" 22 | 23 | class BtrfsBalance { 24 | public: 25 | BtrfsBalance(const wstring& drive, bool RemoveDevice = false, bool ShrinkDevice = false) { 26 | removing = false; 27 | devices = nullptr; 28 | called_from_RemoveDevice = RemoveDevice; 29 | called_from_ShrinkDevice = ShrinkDevice; 30 | fn = drive; 31 | } 32 | 33 | void ShowBalance(HWND hwndDlg); 34 | INT_PTR CALLBACK BalanceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 35 | INT_PTR CALLBACK BalanceOptsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 36 | 37 | private: 38 | void ShowBalanceOptions(HWND hwndDlg, uint8_t type); 39 | void SaveBalanceOpts(HWND hwndDlg); 40 | void StartBalance(HWND hwndDlg); 41 | void RefreshBalanceDlg(HWND hwndDlg, bool first); 42 | void PauseBalance(HWND hwndDlg); 43 | void StopBalance(HWND hwndDlg); 44 | 45 | uint32_t balance_status; 46 | btrfs_balance_opts data_opts, metadata_opts, system_opts; 47 | uint8_t opts_type; 48 | btrfs_query_balance bqb; 49 | bool cancelling; 50 | bool removing; 51 | bool shrinking; 52 | wstring fn; 53 | btrfs_device* devices; 54 | bool readonly; 55 | bool called_from_RemoveDevice, called_from_ShrinkDevice; 56 | }; 57 | -------------------------------------------------------------------------------- /src/shellext/contextmenu.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #pragma once 19 | 20 | #include 21 | 22 | extern LONG objs_loaded; 23 | 24 | class BtrfsContextMenu : public IShellExtInit, IContextMenu { 25 | public: 26 | BtrfsContextMenu() { 27 | refcount = 0; 28 | ignore = true; 29 | stgm_set = false; 30 | uacicon = nullptr; 31 | allow_snapshot = false; 32 | InterlockedIncrement(&objs_loaded); 33 | } 34 | 35 | virtual ~BtrfsContextMenu() { 36 | if (stgm_set) 37 | ReleaseStgMedium(&stgm); 38 | 39 | if (uacicon) 40 | DeleteObject(uacicon); 41 | 42 | InterlockedDecrement(&objs_loaded); 43 | } 44 | 45 | // IUnknown 46 | 47 | HRESULT __stdcall QueryInterface(REFIID riid, void **ppObj); 48 | 49 | ULONG __stdcall AddRef() { 50 | return InterlockedIncrement(&refcount); 51 | } 52 | 53 | ULONG __stdcall Release() { 54 | LONG rc = InterlockedDecrement(&refcount); 55 | 56 | if (rc == 0) 57 | delete this; 58 | 59 | return rc; 60 | } 61 | 62 | // IShellExtInit 63 | 64 | virtual HRESULT __stdcall Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgID) override; 65 | 66 | // IContextMenu 67 | 68 | virtual HRESULT __stdcall QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) override; 69 | virtual HRESULT __stdcall InvokeCommand(LPCMINVOKECOMMANDINFO pici) override; 70 | virtual HRESULT __stdcall GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchMax) override; 71 | 72 | private: 73 | LONG refcount; 74 | bool ignore, allow_snapshot; 75 | bool bg; 76 | wstring path; 77 | STGMEDIUM stgm; 78 | bool stgm_set; 79 | HBITMAP uacicon; 80 | 81 | void reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir); 82 | void get_uac_icon(); 83 | }; 84 | -------------------------------------------------------------------------------- /src/shellext/devices.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include "../btrfsioctl.h" 24 | 25 | typedef struct { 26 | wstring pnp_name; 27 | wstring friendly_name; 28 | wstring drive; 29 | wstring fstype; 30 | ULONG disk_num; 31 | ULONG part_num; 32 | uint64_t size; 33 | bool has_parts; 34 | BTRFS_UUID fs_uuid; 35 | BTRFS_UUID dev_uuid; 36 | bool ignore; 37 | bool multi_device; 38 | bool is_disk; 39 | } device; 40 | 41 | typedef struct { 42 | const WCHAR* name; 43 | const char* magic; 44 | ULONG magiclen; 45 | uint32_t sboff; 46 | uint32_t kboff; 47 | } fs_identifier; 48 | 49 | // This list is compiled from information in libblkid, part of util-linux 50 | // and likewise under the LGPL. Thanks! 51 | 52 | const static fs_identifier fs_ident[] = { 53 | { L"BeFS", "BFS1", 4, 0x20, 0 }, 54 | { L"BeFS", "1SFB", 4, 0x20, 0 }, 55 | { L"BeFS", "BFS1", 4, 0x220, 0 }, 56 | { L"BeFS", "1SFB", 4, 0x220, 0 }, 57 | { L"BFS", "\xce\xfa\xad\x1b", 4, 0, 0 }, 58 | { L"RomFS", "-rom1fs-", 8, 0, 0 }, 59 | { L"SquashFS", "hsqs", 4, 0, 0 }, 60 | { L"SquashFS", "sqsh", 4, 0, 0 }, 61 | { L"SquashFS", "hsqs", 4, 0, 0 }, 62 | { L"UBIFS", "\x31\x18\x10\x06", 4, 0, 0 }, 63 | { L"XFS", "XFSB", 4, 0, 0 }, 64 | { L"ext2", "\123\357", 2, 0x38, 1 }, 65 | { L"F2FS", "\x10\x20\xF5\xF2", 4, 0, 1 }, 66 | { L"HFS", "BD", 2, 0, 1 }, 67 | { L"HFS", "BD", 2, 0, 1 }, 68 | { L"HFS", "H+", 2, 0, 1 }, 69 | { L"HFS", "HX", 2, 0, 1 }, 70 | { L"Minix", "\177\023", 2, 0x10, 1 }, 71 | { L"Minix", "\217\023", 2, 0x10, 1 }, 72 | { L"Minix", "\023\177", 2, 0x10, 1 }, 73 | { L"Minix", "\023\217", 2, 0x10, 1 }, 74 | { L"Minix", "\150\044", 2, 0x10, 1 }, 75 | { L"Minix", "\170\044", 2, 0x10, 1 }, 76 | { L"Minix", "\044\150", 2, 0x10, 1 }, 77 | { L"Minix", "\044\170", 2, 0x10, 1 }, 78 | { L"Minix", "\132\115", 2, 0x10, 1 }, 79 | { L"Minix", "\115\132", 2, 0x10, 1 }, 80 | { L"OCFS", "OCFSV2", 6, 0, 1 }, 81 | { L"SysV", "\x2b\x55\x44", 3, 0x400, 1 }, 82 | { L"SysV", "\x44\x55\x2b", 3, 0x400, 1 }, 83 | { L"VXFS", "\365\374\001\245", 4, 0, 1 }, 84 | { L"OCFS", "OCFSV2", 6, 0, 2 }, 85 | { L"ExFAT", "EXFAT ", 8, 3, 0 }, 86 | { L"NTFS", "NTFS ", 8, 3, 0 }, 87 | { L"NetWare", "SPB5", 4, 0, 4 }, 88 | { L"OCFS", "OCFSV2", 6, 0, 4 }, 89 | { L"HPFS", "\x49\xe8\x95\xf9", 4, 0, 8 }, 90 | { L"OCFS", "OracleCFS", 9, 0, 8 }, 91 | { L"OCFS", "OCFSV2", 6, 0, 8 }, 92 | { L"ReFS", "\000\000\000ReFS\000", 8, 0, 0 }, 93 | { L"ReiserFS", "ReIsErFs", 8, 0x34, 8 }, 94 | { L"ReiserFS", "ReIsErFs", 8, 20, 8 }, 95 | { L"ISO9660", "CD001", 5, 1, 32 }, 96 | { L"ISO9660", "CDROM", 5, 9, 32 }, 97 | { L"JFS", "JFS1", 4, 0, 32 }, 98 | { L"OCFS", "ORCLDISK", 8, 32, 0 }, 99 | { L"UDF", "BEA01", 5, 1, 32 }, 100 | { L"UDF", "BOOT2", 5, 1, 32 }, 101 | { L"UDF", "CD001", 5, 1, 32 }, 102 | { L"UDF", "CDW02", 5, 1, 32 }, 103 | { L"UDF", "NSR02", 5, 1, 32 }, 104 | { L"UDF", "NSR03", 5, 1, 32 }, 105 | { L"UDF", "TEA01", 5, 1, 32 }, 106 | { L"Btrfs", "_BHRfS_M", 8, 0x40, 64 }, 107 | { L"GFS", "\x01\x16\x19\x70", 4, 0, 64 }, 108 | { L"GFS", "\x01\x16\x19\x70", 4, 0, 64 }, 109 | { L"ReiserFS", "ReIsEr2Fs", 9, 0x34, 64 }, 110 | { L"ReiserFS", "ReIsEr3Fs", 9, 0x34, 64 }, 111 | { L"ReiserFS", "ReIsErFs", 8, 0x34, 64 }, 112 | { L"ReiserFS", "ReIsEr4", 7, 0, 64 }, 113 | { L"VMFS", "\x0d\xd0\x01\xc0", 4, 0, 1024 }, 114 | { L"VMFS", "\x5e\xf1\xab\x2f", 4, 0, 2048 }, 115 | { L"FAT", "MSWIN", 5, 0x52, 0 }, 116 | { L"FAT", "FAT32 ", 8, 0x52, 0 }, 117 | { L"FAT", "MSDOS", 5, 0x36, 0 }, 118 | { L"FAT", "FAT16 ", 8, 0x36, 0 }, 119 | { L"FAT", "FAT12 ", 8, 0x36, 0 }, 120 | { L"FAT", "FAT ", 8, 0x36, 0 }, 121 | { L"FAT", "\353", 1, 0, 0 }, 122 | { L"FAT", "\351", 1, 0, 0 }, 123 | { L"FAT", "\125\252", 2, 0x1fe, 0 }, 124 | { nullptr, nullptr, 0, 0, 0 } 125 | }; 126 | 127 | class BtrfsDeviceAdd { 128 | public: 129 | INT_PTR CALLBACK DeviceAddDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 130 | void ShowDialog(); 131 | void AddDevice(HWND hwndDlg); 132 | BtrfsDeviceAdd(HINSTANCE hinst, HWND hwnd, WCHAR* cmdline); 133 | 134 | private: 135 | void populate_device_tree(HWND tree); 136 | 137 | HINSTANCE hinst; 138 | HWND hwnd; 139 | WCHAR* cmdline; 140 | device* sel; 141 | vector device_list; 142 | }; 143 | 144 | class BtrfsDeviceResize { 145 | public: 146 | INT_PTR CALLBACK DeviceResizeDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 147 | void ShowDialog(HWND hwnd, const wstring& fn, uint64_t dev_id); 148 | 149 | private: 150 | void do_resize(HWND hwndDlg); 151 | 152 | uint64_t dev_id, new_size; 153 | wstring fn; 154 | WCHAR new_size_text[255]; 155 | btrfs_device dev_info; 156 | }; 157 | -------------------------------------------------------------------------------- /src/shellext/factory.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #include "shellext.h" 19 | #include 20 | #include "factory.h" 21 | #include "iconoverlay.h" 22 | #include "contextmenu.h" 23 | #include "propsheet.h" 24 | #include "volpropsheet.h" 25 | 26 | HRESULT __stdcall Factory::QueryInterface(const IID& iid, void** ppv) { 27 | if (iid == IID_IUnknown || iid == IID_IClassFactory) { 28 | *ppv = static_cast(this); 29 | } else { 30 | *ppv = nullptr; 31 | return E_NOINTERFACE; 32 | } 33 | 34 | reinterpret_cast(*ppv)->AddRef(); 35 | 36 | return S_OK; 37 | } 38 | 39 | HRESULT __stdcall Factory::LockServer(BOOL) { 40 | return E_NOTIMPL; 41 | } 42 | 43 | HRESULT __stdcall Factory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) { 44 | if (pUnknownOuter) 45 | return CLASS_E_NOAGGREGATION; 46 | 47 | switch (type) { 48 | case FactoryIconHandler: 49 | if (iid == IID_IUnknown || iid == IID_IShellIconOverlayIdentifier) { 50 | BtrfsIconOverlay* bio = new BtrfsIconOverlay; 51 | if (!bio) 52 | return E_OUTOFMEMORY; 53 | 54 | return bio->QueryInterface(iid, ppv); 55 | } 56 | break; 57 | 58 | case FactoryContextMenu: 59 | if (iid == IID_IUnknown || iid == IID_IContextMenu || iid == IID_IShellExtInit) { 60 | BtrfsContextMenu* bcm = new BtrfsContextMenu; 61 | if (!bcm) 62 | return E_OUTOFMEMORY; 63 | 64 | return bcm->QueryInterface(iid, ppv); 65 | } 66 | break; 67 | 68 | case FactoryPropSheet: 69 | if (iid == IID_IUnknown || iid == IID_IShellPropSheetExt || iid == IID_IShellExtInit) { 70 | BtrfsPropSheet* bps = new BtrfsPropSheet; 71 | if (!bps) 72 | return E_OUTOFMEMORY; 73 | 74 | return bps->QueryInterface(iid, ppv); 75 | } 76 | break; 77 | 78 | case FactoryVolPropSheet: 79 | if (iid == IID_IUnknown || iid == IID_IShellPropSheetExt || iid == IID_IShellExtInit) { 80 | BtrfsVolPropSheet* bps = new BtrfsVolPropSheet; 81 | if (!bps) 82 | return E_OUTOFMEMORY; 83 | 84 | return bps->QueryInterface(iid, ppv); 85 | } 86 | break; 87 | 88 | default: 89 | break; 90 | } 91 | 92 | *ppv = nullptr; 93 | return E_NOINTERFACE; 94 | } 95 | -------------------------------------------------------------------------------- /src/shellext/factory.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #pragma once 19 | 20 | extern LONG objs_loaded; 21 | 22 | typedef enum { 23 | FactoryUnknown, 24 | FactoryIconHandler, 25 | FactoryContextMenu, 26 | FactoryPropSheet, 27 | FactoryVolPropSheet 28 | } factory_type; 29 | 30 | class Factory : public IClassFactory { 31 | public: 32 | Factory() { 33 | refcount = 0; 34 | type = FactoryUnknown; 35 | InterlockedIncrement(&objs_loaded); 36 | } 37 | 38 | virtual ~Factory() { 39 | InterlockedDecrement(&objs_loaded); 40 | } 41 | 42 | // IUnknown 43 | 44 | HRESULT __stdcall QueryInterface(REFIID riid, void **ppObj); 45 | 46 | ULONG __stdcall AddRef() { 47 | return InterlockedIncrement(&refcount); 48 | } 49 | 50 | ULONG __stdcall Release() { 51 | LONG rc = InterlockedDecrement(&refcount); 52 | 53 | if (rc == 0) 54 | delete this; 55 | 56 | return rc; 57 | } 58 | 59 | // IClassFactory 60 | 61 | virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) override; 62 | virtual HRESULT __stdcall LockServer(BOOL bLock) override; 63 | 64 | factory_type type; 65 | 66 | private: 67 | LONG refcount; 68 | }; 69 | -------------------------------------------------------------------------------- /src/shellext/iconoverlay.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #include "shellext.h" 19 | #include 20 | #include 21 | #include "iconoverlay.h" 22 | #include "../btrfsioctl.h" 23 | 24 | HRESULT __stdcall BtrfsIconOverlay::QueryInterface(REFIID riid, void **ppObj) { 25 | if (riid == IID_IUnknown || riid == IID_IShellIconOverlayIdentifier) { 26 | *ppObj = static_cast(this); 27 | AddRef(); 28 | return S_OK; 29 | } 30 | 31 | *ppObj = nullptr; 32 | return E_NOINTERFACE; 33 | } 34 | 35 | HRESULT __stdcall BtrfsIconOverlay::GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int* pIndex, DWORD* pdwFlags) noexcept { 36 | if (GetModuleFileNameW(module, pwszIconFile, cchMax) == 0) 37 | return E_FAIL; 38 | 39 | if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 40 | return E_FAIL; 41 | 42 | if (!pIndex) 43 | return E_INVALIDARG; 44 | 45 | if (!pdwFlags) 46 | return E_INVALIDARG; 47 | 48 | *pIndex = 0; 49 | *pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX; 50 | 51 | return S_OK; 52 | } 53 | 54 | HRESULT __stdcall BtrfsIconOverlay::GetPriority(int *pPriority) noexcept { 55 | if (!pPriority) 56 | return E_INVALIDARG; 57 | 58 | *pPriority = 0; 59 | 60 | return S_OK; 61 | } 62 | 63 | HRESULT __stdcall BtrfsIconOverlay::IsMemberOf(PCWSTR pwszPath, DWORD) noexcept { 64 | win_handle h; 65 | NTSTATUS Status; 66 | IO_STATUS_BLOCK iosb; 67 | btrfs_get_file_ids bgfi; 68 | 69 | h = CreateFileW(pwszPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 70 | 71 | if (h == INVALID_HANDLE_VALUE) 72 | return S_FALSE; 73 | 74 | Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_FILE_IDS, nullptr, 0, &bgfi, sizeof(btrfs_get_file_ids)); 75 | 76 | if (!NT_SUCCESS(Status)) 77 | return S_FALSE; 78 | 79 | return (bgfi.inode == 0x100 && !bgfi.top) ? S_OK : S_FALSE; 80 | } 81 | -------------------------------------------------------------------------------- /src/shellext/iconoverlay.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #pragma once 19 | 20 | #include 21 | 22 | extern LONG objs_loaded; 23 | 24 | class BtrfsIconOverlay : public IShellIconOverlayIdentifier { 25 | public: 26 | BtrfsIconOverlay() { 27 | refcount = 0; 28 | InterlockedIncrement(&objs_loaded); 29 | } 30 | 31 | virtual ~BtrfsIconOverlay() { 32 | InterlockedDecrement(&objs_loaded); 33 | } 34 | 35 | // IUnknown 36 | 37 | HRESULT __stdcall QueryInterface(REFIID riid, void **ppObj); 38 | 39 | ULONG __stdcall AddRef() { 40 | return InterlockedIncrement(&refcount); 41 | } 42 | 43 | ULONG __stdcall Release() { 44 | LONG rc = InterlockedDecrement(&refcount); 45 | 46 | if (rc == 0) 47 | delete this; 48 | 49 | return rc; 50 | } 51 | 52 | // IShellIconOverlayIdentifier 53 | 54 | virtual HRESULT __stdcall GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int* pIndex, DWORD* pdwFlags) noexcept override; 55 | virtual HRESULT __stdcall GetPriority(int *pPriority) noexcept override; 56 | virtual HRESULT __stdcall IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib) noexcept override; 57 | 58 | private: 59 | LONG refcount; 60 | }; 61 | -------------------------------------------------------------------------------- /src/shellext/mountmgr.cpp: -------------------------------------------------------------------------------- 1 | #include "shellext.h" 2 | #include "mountmgr.h" 3 | #include 4 | 5 | using namespace std; 6 | 7 | mountmgr::mountmgr() { 8 | UNICODE_STRING us; 9 | OBJECT_ATTRIBUTES attr; 10 | IO_STATUS_BLOCK iosb; 11 | NTSTATUS Status; 12 | 13 | RtlInitUnicodeString(&us, MOUNTMGR_DEVICE_NAME); 14 | InitializeObjectAttributes(&attr, &us, 0, nullptr, nullptr); 15 | 16 | Status = NtOpenFile(&h, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb, 17 | FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT); 18 | 19 | if (!NT_SUCCESS(Status)) 20 | throw ntstatus_error(Status); 21 | } 22 | 23 | mountmgr::~mountmgr() { 24 | NtClose(h); 25 | } 26 | 27 | void mountmgr::create_point(wstring_view symlink, wstring_view device) const { 28 | NTSTATUS Status; 29 | IO_STATUS_BLOCK iosb; 30 | 31 | vector buf(sizeof(MOUNTMGR_CREATE_POINT_INPUT) + ((symlink.length() + device.length()) * sizeof(WCHAR))); 32 | auto mcpi = reinterpret_cast(buf.data()); 33 | 34 | mcpi->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT); 35 | mcpi->SymbolicLinkNameLength = (USHORT)(symlink.length() * sizeof(WCHAR)); 36 | mcpi->DeviceNameOffset = (USHORT)(mcpi->SymbolicLinkNameOffset + mcpi->SymbolicLinkNameLength); 37 | mcpi->DeviceNameLength = (USHORT)(device.length() * sizeof(WCHAR)); 38 | 39 | memcpy((uint8_t*)mcpi + mcpi->SymbolicLinkNameOffset, symlink.data(), symlink.length() * sizeof(WCHAR)); 40 | memcpy((uint8_t*)mcpi + mcpi->DeviceNameOffset, device.data(), device.length() * sizeof(WCHAR)); 41 | 42 | Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_CREATE_POINT, 43 | buf.data(), (ULONG)buf.size(), nullptr, 0); 44 | 45 | if (!NT_SUCCESS(Status)) 46 | throw ntstatus_error(Status); 47 | } 48 | 49 | void mountmgr::delete_points(wstring_view symlink, wstring_view unique_id, wstring_view device_name) const { 50 | NTSTATUS Status; 51 | IO_STATUS_BLOCK iosb; 52 | 53 | vector buf(sizeof(MOUNTMGR_MOUNT_POINT) + ((symlink.length() + unique_id.length() + device_name.length()) * sizeof(WCHAR))); 54 | auto mmp = reinterpret_cast(buf.data()); 55 | 56 | memset(mmp, 0, sizeof(MOUNTMGR_MOUNT_POINT)); 57 | 58 | if (symlink.length() > 0) { 59 | mmp->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); 60 | mmp->SymbolicLinkNameLength = (USHORT)(symlink.length() * sizeof(WCHAR)); 61 | memcpy((uint8_t*)mmp + mmp->SymbolicLinkNameOffset, symlink.data(), symlink.length() * sizeof(WCHAR)); 62 | } 63 | 64 | if (unique_id.length() > 0) { 65 | if (mmp->SymbolicLinkNameLength == 0) 66 | mmp->UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINT); 67 | else 68 | mmp->UniqueIdOffset = mmp->SymbolicLinkNameOffset + mmp->SymbolicLinkNameLength; 69 | 70 | mmp->UniqueIdLength = (USHORT)(unique_id.length() * sizeof(WCHAR)); 71 | memcpy((uint8_t*)mmp + mmp->UniqueIdOffset, unique_id.data(), unique_id.length() * sizeof(WCHAR)); 72 | } 73 | 74 | if (device_name.length() > 0) { 75 | if (mmp->SymbolicLinkNameLength == 0 && mmp->UniqueIdOffset == 0) 76 | mmp->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); 77 | else if (mmp->SymbolicLinkNameLength != 0) 78 | mmp->DeviceNameOffset = mmp->SymbolicLinkNameOffset + mmp->SymbolicLinkNameLength; 79 | else 80 | mmp->DeviceNameOffset = mmp->UniqueIdOffset + mmp->UniqueIdLength; 81 | 82 | mmp->DeviceNameLength = (USHORT)(device_name.length() * sizeof(WCHAR)); 83 | memcpy((uint8_t*)mmp + mmp->DeviceNameOffset, device_name.data(), device_name.length() * sizeof(WCHAR)); 84 | } 85 | 86 | vector buf2(sizeof(MOUNTMGR_MOUNT_POINTS)); 87 | auto mmps = reinterpret_cast(buf2.data()); 88 | 89 | Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_DELETE_POINTS, 90 | buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size()); 91 | 92 | if (Status == STATUS_BUFFER_OVERFLOW) { 93 | buf2.resize(mmps->Size); 94 | 95 | Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_DELETE_POINTS, 96 | buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size()); 97 | } 98 | 99 | if (!NT_SUCCESS(Status)) 100 | throw ntstatus_error(Status); 101 | } 102 | 103 | vector mountmgr::query_points(wstring_view symlink, wstring_view unique_id, wstring_view device_name) const { 104 | NTSTATUS Status; 105 | IO_STATUS_BLOCK iosb; 106 | vector v; 107 | 108 | vector buf(sizeof(MOUNTMGR_MOUNT_POINT) + ((symlink.length() + unique_id.length() + device_name.length()) * sizeof(WCHAR))); 109 | auto mmp = reinterpret_cast(buf.data()); 110 | 111 | memset(mmp, 0, sizeof(MOUNTMGR_MOUNT_POINT)); 112 | 113 | if (symlink.length() > 0) { 114 | mmp->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); 115 | mmp->SymbolicLinkNameLength = (USHORT)(symlink.length() * sizeof(WCHAR)); 116 | memcpy((uint8_t*)mmp + mmp->SymbolicLinkNameOffset, symlink.data(), symlink.length() * sizeof(WCHAR)); 117 | } 118 | 119 | if (unique_id.length() > 0) { 120 | if (mmp->SymbolicLinkNameLength == 0) 121 | mmp->UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINT); 122 | else 123 | mmp->UniqueIdOffset = mmp->SymbolicLinkNameOffset + mmp->SymbolicLinkNameLength; 124 | 125 | mmp->UniqueIdLength = (USHORT)(unique_id.length() * sizeof(WCHAR)); 126 | memcpy((uint8_t*)mmp + mmp->UniqueIdOffset, unique_id.data(), unique_id.length() * sizeof(WCHAR)); 127 | } 128 | 129 | if (device_name.length() > 0) { 130 | if (mmp->SymbolicLinkNameLength == 0 && mmp->UniqueIdOffset == 0) 131 | mmp->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); 132 | else if (mmp->SymbolicLinkNameLength != 0) 133 | mmp->DeviceNameOffset = mmp->SymbolicLinkNameOffset + mmp->SymbolicLinkNameLength; 134 | else 135 | mmp->DeviceNameOffset = mmp->UniqueIdOffset + mmp->UniqueIdLength; 136 | 137 | mmp->DeviceNameLength = (USHORT)(device_name.length() * sizeof(WCHAR)); 138 | memcpy((uint8_t*)mmp + mmp->DeviceNameOffset, device_name.data(), device_name.length() * sizeof(WCHAR)); 139 | } 140 | 141 | vector buf2(sizeof(MOUNTMGR_MOUNT_POINTS)); 142 | auto mmps = reinterpret_cast(buf2.data()); 143 | 144 | Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_QUERY_POINTS, 145 | buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size()); 146 | 147 | if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 148 | throw ntstatus_error(Status); 149 | 150 | buf2.resize(mmps->Size); 151 | mmps = reinterpret_cast(buf2.data()); 152 | 153 | Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_QUERY_POINTS, 154 | buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size()); 155 | 156 | if (!NT_SUCCESS(Status)) 157 | throw ntstatus_error(Status); 158 | 159 | for (ULONG i = 0; i < mmps->NumberOfMountPoints; i++) { 160 | wstring_view mpsl, mpdn; 161 | string_view mpuid; 162 | 163 | if (mmps->MountPoints[i].SymbolicLinkNameLength) 164 | mpsl = wstring_view((WCHAR*)((uint8_t*)mmps + mmps->MountPoints[i].SymbolicLinkNameOffset), mmps->MountPoints[i].SymbolicLinkNameLength / sizeof(WCHAR)); 165 | 166 | if (mmps->MountPoints[i].UniqueIdLength) 167 | mpuid = string_view((char*)((uint8_t*)mmps + mmps->MountPoints[i].UniqueIdOffset), mmps->MountPoints[i].UniqueIdLength); 168 | 169 | if (mmps->MountPoints[i].DeviceNameLength) 170 | mpdn = wstring_view((WCHAR*)((uint8_t*)mmps + mmps->MountPoints[i].DeviceNameOffset), mmps->MountPoints[i].DeviceNameLength / sizeof(WCHAR)); 171 | 172 | v.emplace_back(mpsl, mpuid, mpdn); 173 | } 174 | 175 | return v; 176 | } 177 | -------------------------------------------------------------------------------- /src/shellext/mountmgr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class mountmgr_point { 11 | public: 12 | mountmgr_point(std::wstring_view symlink, std::string_view unique_id, std::wstring_view device_name) : symlink(symlink), device_name(device_name), unique_id(unique_id) { 13 | } 14 | 15 | std::wstring symlink, device_name; 16 | std::string unique_id; 17 | }; 18 | 19 | class mountmgr { 20 | public: 21 | mountmgr(); 22 | ~mountmgr(); 23 | void create_point(std::wstring_view symlink, std::wstring_view device) const; 24 | void delete_points(std::wstring_view symlink, std::wstring_view unique_id = L"", std::wstring_view device_name = L"") const; 25 | std::vector query_points(std::wstring_view symlink = L"", std::wstring_view unique_id = L"", std::wstring_view device_name = L"") const; 26 | 27 | private: 28 | HANDLE h; 29 | }; 30 | -------------------------------------------------------------------------------- /src/shellext/propsheet.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include "../btrfsioctl.h" 23 | 24 | #ifndef S_IRUSR 25 | #define S_IRUSR 0000400 26 | #endif 27 | 28 | #ifndef S_IWUSR 29 | #define S_IWUSR 0000200 30 | #endif 31 | 32 | #ifndef S_IXUSR 33 | #define S_IXUSR 0000100 34 | #endif 35 | 36 | #ifndef S_IRGRP 37 | #define S_IRGRP (S_IRUSR >> 3) 38 | #endif 39 | 40 | #ifndef S_IWGRP 41 | #define S_IWGRP (S_IWUSR >> 3) 42 | #endif 43 | 44 | #ifndef S_IXGRP 45 | #define S_IXGRP (S_IXUSR >> 3) 46 | #endif 47 | 48 | #ifndef S_IROTH 49 | #define S_IROTH (S_IRGRP >> 3) 50 | #endif 51 | 52 | #ifndef S_IWOTH 53 | #define S_IWOTH (S_IWGRP >> 3) 54 | #endif 55 | 56 | #ifndef S_IXOTH 57 | #define S_IXOTH (S_IXGRP >> 3) 58 | #endif 59 | 60 | #ifndef S_ISUID 61 | #define S_ISUID 0004000 62 | #endif 63 | 64 | #ifndef S_ISGID 65 | #define S_ISGID 0002000 66 | #endif 67 | 68 | #ifndef S_ISVTX 69 | #define S_ISVTX 0001000 70 | #endif 71 | 72 | #define BTRFS_INODE_NODATASUM 0x001 73 | #define BTRFS_INODE_NODATACOW 0x002 74 | #define BTRFS_INODE_READONLY 0x004 75 | #define BTRFS_INODE_NOCOMPRESS 0x008 76 | #define BTRFS_INODE_PREALLOC 0x010 77 | #define BTRFS_INODE_SYNC 0x020 78 | #define BTRFS_INODE_IMMUTABLE 0x040 79 | #define BTRFS_INODE_APPEND 0x080 80 | #define BTRFS_INODE_NODUMP 0x100 81 | #define BTRFS_INODE_NOATIME 0x200 82 | #define BTRFS_INODE_DIRSYNC 0x400 83 | #define BTRFS_INODE_COMPRESS 0x800 84 | 85 | extern LONG objs_loaded; 86 | 87 | class BtrfsPropSheet : public IShellExtInit, IShellPropSheetExt { 88 | public: 89 | BtrfsPropSheet() { 90 | refcount = 0; 91 | ignore = true; 92 | stgm_set = false; 93 | readonly = false; 94 | flags_changed = false; 95 | perms_changed = false; 96 | uid_changed = false; 97 | gid_changed = false; 98 | compress_type_changed = false; 99 | ro_changed = false; 100 | can_change_perms = false; 101 | show_admin_button = false; 102 | thread = nullptr; 103 | mode = mode_set = 0; 104 | flags = flags_set = 0; 105 | has_subvols = false; 106 | filename = L""; 107 | 108 | sizes[0] = sizes[1] = sizes[2] = sizes[3] = sizes[4] = 0; 109 | totalsize = allocsize = sparsesize = 0; 110 | num_extents = 0; 111 | sector_size = 0; 112 | size_format[0] = 0; 113 | cr_format[0] = 0; 114 | frag_format[0] = 0; 115 | 116 | InterlockedIncrement(&objs_loaded); 117 | } 118 | 119 | virtual ~BtrfsPropSheet() { 120 | if (stgm_set) 121 | ReleaseStgMedium(&stgm); 122 | 123 | InterlockedDecrement(&objs_loaded); 124 | } 125 | 126 | // IUnknown 127 | 128 | HRESULT __stdcall QueryInterface(REFIID riid, void **ppObj); 129 | 130 | ULONG __stdcall AddRef() { 131 | return InterlockedIncrement(&refcount); 132 | } 133 | 134 | ULONG __stdcall Release() { 135 | LONG rc = InterlockedDecrement(&refcount); 136 | 137 | if (rc == 0) 138 | delete this; 139 | 140 | return rc; 141 | } 142 | 143 | // IShellExtInit 144 | 145 | virtual HRESULT __stdcall Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgID) override; 146 | 147 | // IShellPropSheetExt 148 | 149 | virtual HRESULT __stdcall AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) override; 150 | virtual HRESULT __stdcall ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam) override; 151 | 152 | void init_propsheet(HWND hwndDlg); 153 | void change_inode_flag(HWND hDlg, uint64_t flag, UINT state); 154 | void change_perm_flag(HWND hDlg, ULONG perm, UINT state); 155 | void change_uid(HWND hDlg, uint32_t uid); 156 | void change_gid(HWND hDlg, uint32_t gid); 157 | void apply_changes(HWND hDlg); 158 | void set_size_on_disk(HWND hwndDlg); 159 | DWORD search_list_thread(); 160 | void do_search(const wstring& fn); 161 | void update_size_details_dialog(HWND hDlg); 162 | void open_as_admin(HWND hwndDlg); 163 | void set_cmdline(const wstring& cmdline); 164 | 165 | bool readonly; 166 | bool can_change_perms; 167 | bool can_change_nocow; 168 | WCHAR size_format[255], cr_format[255], frag_format[255]; 169 | HANDLE thread; 170 | uint32_t min_mode, max_mode, mode, mode_set; 171 | uint64_t min_flags, max_flags, flags, flags_set; 172 | uint64_t subvol, inode, rdev; 173 | uint8_t type, min_compression_type, max_compression_type, compress_type; 174 | uint32_t uid, gid; 175 | bool various_subvols, various_inodes, various_types, various_uids, various_gids, compress_type_changed, has_subvols, 176 | ro_subvol, various_ro, ro_changed, show_admin_button; 177 | 178 | private: 179 | LONG refcount; 180 | bool ignore; 181 | STGMEDIUM stgm; 182 | bool stgm_set; 183 | bool flags_changed, perms_changed, uid_changed, gid_changed; 184 | uint64_t sizes[5], totalsize, allocsize, sparsesize, num_extents; 185 | deque search_list; 186 | wstring filename; 187 | uint32_t sector_size; 188 | 189 | void apply_changes_file(HWND hDlg, const wstring& fn); 190 | HRESULT check_file(const wstring& fn, UINT i, UINT num_files, UINT* sv); 191 | HRESULT load_file_list(); 192 | }; 193 | -------------------------------------------------------------------------------- /src/shellext/recv.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2017 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include "../btrfs.h" 22 | 23 | extern LONG objs_loaded; 24 | 25 | typedef struct { 26 | BTRFS_UUID uuid; 27 | uint64_t transid; 28 | wstring path; 29 | } subvol_cache; 30 | 31 | class BtrfsRecv { 32 | public: 33 | BtrfsRecv() { 34 | thread = nullptr; 35 | master = INVALID_HANDLE_VALUE; 36 | dir = INVALID_HANDLE_VALUE; 37 | running = false; 38 | cancelling = false; 39 | stransid = 0; 40 | num_received = 0; 41 | hwnd = nullptr; 42 | cache.clear(); 43 | } 44 | 45 | virtual ~BtrfsRecv() { 46 | cache.clear(); 47 | } 48 | 49 | void Open(HWND hwnd, const wstring& file, const wstring& path, bool quiet); 50 | DWORD recv_thread(); 51 | INT_PTR CALLBACK RecvProgressDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 52 | 53 | private: 54 | void cmd_subvol(btrfs_send_command* cmd, uint8_t* data, const win_handle& parent); 55 | void cmd_snapshot(btrfs_send_command* cmd, uint8_t* data, const win_handle& parent); 56 | void cmd_mkfile(btrfs_send_command* cmd, uint8_t* data); 57 | void cmd_rename(btrfs_send_command* cmd, uint8_t* data); 58 | void cmd_link(btrfs_send_command* cmd, uint8_t* data); 59 | void cmd_unlink(btrfs_send_command* cmd, uint8_t* data); 60 | void cmd_rmdir(btrfs_send_command* cmd, uint8_t* data); 61 | void cmd_setxattr(btrfs_send_command* cmd, uint8_t* data); 62 | void cmd_removexattr(btrfs_send_command* cmd, uint8_t* data); 63 | void cmd_write(btrfs_send_command* cmd, uint8_t* data); 64 | void cmd_clone(btrfs_send_command* cmd, uint8_t* data); 65 | void cmd_truncate(btrfs_send_command* cmd, uint8_t* data); 66 | void cmd_chmod(btrfs_send_command* cmd, uint8_t* data); 67 | void cmd_chown(btrfs_send_command* cmd, uint8_t* data); 68 | void cmd_utimes(btrfs_send_command* cmd, uint8_t* data); 69 | void add_cache_entry(BTRFS_UUID* uuid, uint64_t transid, const wstring& path); 70 | bool find_tlv(uint8_t* data, ULONG datalen, uint16_t type, void** value, ULONG* len); 71 | void do_recv(const win_handle& f, uint64_t* pos, uint64_t size, const win_handle& parent); 72 | 73 | HANDLE dir, master, thread, lastwritefile; 74 | HWND hwnd; 75 | wstring streamfile, dirpath, subvolpath, lastwritepath; 76 | DWORD lastwriteatt; 77 | ULONG num_received; 78 | uint64_t stransid; 79 | BTRFS_UUID subvol_uuid; 80 | bool running, cancelling; 81 | vector cache; 82 | }; 83 | -------------------------------------------------------------------------------- /src/shellext/scrub.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2017 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include "../btrfs.h" 22 | #include "../btrfsioctl.h" 23 | 24 | class BtrfsScrub { 25 | public: 26 | BtrfsScrub(const wstring& drive) { 27 | fn = drive; 28 | } 29 | 30 | INT_PTR CALLBACK ScrubDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 31 | 32 | private: 33 | void RefreshScrubDlg(HWND hwndDlg, bool first_time); 34 | void UpdateTextBox(HWND hwndDlg, btrfs_query_scrub* bqs); 35 | void StartScrub(HWND hwndDlg); 36 | void PauseScrub(HWND hwndDlg); 37 | void StopScrub(HWND hwndDlg); 38 | 39 | wstring fn; 40 | uint32_t status; 41 | uint64_t chunks_left; 42 | uint32_t num_errors; 43 | }; 44 | -------------------------------------------------------------------------------- /src/shellext/send.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2017 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #pragma once 19 | 20 | #include "../btrfs.h" 21 | 22 | class BtrfsSend { 23 | public: 24 | BtrfsSend() { 25 | started = false; 26 | file[0] = 0; 27 | dirh = INVALID_HANDLE_VALUE; 28 | stream = INVALID_HANDLE_VALUE; 29 | subvol = L""; 30 | buf = nullptr; 31 | incremental = false; 32 | } 33 | 34 | ~BtrfsSend() { 35 | if (buf) 36 | free(buf); 37 | } 38 | 39 | void Open(HWND hwnd, WCHAR* path); 40 | INT_PTR SendDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 41 | DWORD Thread(); 42 | 43 | private: 44 | void StartSend(HWND hwnd); 45 | void Browse(HWND hwnd); 46 | void BrowseParent(HWND hwnd); 47 | void AddClone(HWND hwnd); 48 | void RemoveClone(HWND hwnd); 49 | 50 | bool started; 51 | bool incremental; 52 | WCHAR file[MAX_PATH], closetext[255]; 53 | HANDLE thread, dirh, stream; 54 | HWND hwnd; 55 | wstring subvol; 56 | char* buf; 57 | vector clones; 58 | }; 59 | -------------------------------------------------------------------------------- /src/shellext/shellbtrfs.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DllCanUnloadNow PRIVATE 3 | DllGetClassObject PRIVATE 4 | DllRegisterServer PRIVATE 5 | DllUnregisterServer PRIVATE 6 | DllInstall PRIVATE 7 | AddDeviceW PRIVATE 8 | RemoveDeviceW PRIVATE 9 | StartBalanceW PRIVATE 10 | PauseBalanceW PRIVATE 11 | StopBalanceW PRIVATE 12 | ShowScrubW PRIVATE 13 | ResetStatsW PRIVATE 14 | ShowPropSheetW PRIVATE 15 | RecvSubvolGUIW PRIVATE 16 | SendSubvolGUIW PRIVATE 17 | CreateSubvolW PRIVATE 18 | CreateSnapshotW PRIVATE 19 | ReflinkCopyW PRIVATE 20 | StartScrubW PRIVATE 21 | StopScrubW PRIVATE 22 | SendSubvolW PRIVATE 23 | RecvSubvolW PRIVATE 24 | ResizeDeviceW PRIVATE 25 | ShowChangeDriveLetterW PRIVATE 26 | MappingsTest PRIVATE 27 | -------------------------------------------------------------------------------- /src/shellext/shellbtrfs.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinBtrfs shell extension 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/shellext/shellext.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #pragma once 19 | 20 | #define ISOLATION_AWARE_ENABLED 1 21 | #define STRSAFE_NO_DEPRECATE 22 | 23 | #define WINVER 0x0A00 // Windows 10 24 | #define _WIN32_WINNT 0x0A00 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "../btrfs.h" 32 | #include "../btrfsioctl.h" 33 | 34 | using namespace std; 35 | 36 | #define STATUS_SUCCESS (NTSTATUS)0x00000000 37 | #define STATUS_BUFFER_OVERFLOW (NTSTATUS)0x80000005 38 | #define STATUS_END_OF_FILE (NTSTATUS)0xc0000011 39 | #define STATUS_MORE_PROCESSING_REQUIRED (NTSTATUS)0xc0000016 40 | #define STATUS_BUFFER_TOO_SMALL (NTSTATUS)0xc0000023 41 | #define STATUS_DEVICE_NOT_READY (NTSTATUS)0xc00000a3 42 | #define STATUS_CANNOT_DELETE (NTSTATUS)0xc0000121 43 | #define STATUS_NOT_FOUND (NTSTATUS)0xc0000225 44 | 45 | #define BLOCK_FLAG_DATA 0x001 46 | #define BLOCK_FLAG_SYSTEM 0x002 47 | #define BLOCK_FLAG_METADATA 0x004 48 | #define BLOCK_FLAG_RAID0 0x008 49 | #define BLOCK_FLAG_RAID1 0x010 50 | #define BLOCK_FLAG_DUPLICATE 0x020 51 | #define BLOCK_FLAG_RAID10 0x040 52 | #define BLOCK_FLAG_RAID5 0x080 53 | #define BLOCK_FLAG_RAID6 0x100 54 | 55 | #define BTRFS_TYPE_FILE 1 56 | #define BTRFS_TYPE_DIRECTORY 2 57 | #define BTRFS_TYPE_CHARDEV 3 58 | #define BTRFS_TYPE_BLOCKDEV 4 59 | #define BTRFS_TYPE_FIFO 5 60 | #define BTRFS_TYPE_SOCKET 6 61 | #define BTRFS_TYPE_SYMLINK 7 62 | 63 | #ifdef _MSC_VER 64 | #define funcname __FUNCTION__ 65 | #else 66 | #define funcname __func__ 67 | #endif 68 | 69 | #ifdef _MSC_VER 70 | #pragma warning(disable: 4800) 71 | #endif 72 | 73 | extern "C" { 74 | NTSTATUS NTAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, 75 | ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key); 76 | 77 | NTSTATUS WINAPI NtSetEaFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length); 78 | 79 | NTSTATUS WINAPI NtSetSecurityObject(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor); 80 | 81 | #ifdef _MSC_VER 82 | NTSYSCALLAPI NTSTATUS NTAPI NtFsControlFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, 83 | PIO_STATUS_BLOCK IoStatusBlock, ULONG FsControlCode, PVOID InputBuffer, ULONG InputBufferLength, 84 | PVOID OutputBuffer, ULONG OutputBufferLength); 85 | NTSTATUS NTAPI NtQueryInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS FileInformationClass); 86 | 87 | NTSTATUS NTAPI NtSetInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS FileInformationClass); 88 | 89 | #define FileBasicInformation (FILE_INFORMATION_CLASS)4 90 | #define FileStandardInformation (FILE_INFORMATION_CLASS)5 91 | #define FileDispositionInformation (FILE_INFORMATION_CLASS)13 92 | #define FileEndOfFileInformation (FILE_INFORMATION_CLASS)20 93 | #define FileStreamInformation (FILE_INFORMATION_CLASS)22 94 | 95 | typedef enum _FSINFOCLASS { 96 | FileFsVolumeInformation = 1, 97 | FileFsLabelInformation, 98 | FileFsSizeInformation, 99 | FileFsDeviceInformation, 100 | FileFsAttributeInformation, 101 | FileFsControlInformation, 102 | FileFsFullSizeInformation, 103 | FileFsObjectIdInformation, 104 | FileFsDriverPathInformation, 105 | FileFsVolumeFlagsInformation, 106 | FileFsSectorSizeInformation, 107 | FileFsDataCopyInformation, 108 | FileFsMetadataSizeInformation, 109 | FileFsFullSizeInformationEx, 110 | FileFsMaximumInformation 111 | } FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; 112 | 113 | typedef struct _FILE_STREAM_INFORMATION { 114 | ULONG NextEntryOffset; 115 | ULONG StreamNameLength; 116 | LARGE_INTEGER StreamSize; 117 | LARGE_INTEGER StreamAllocationSize; 118 | WCHAR StreamName[1]; 119 | } FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION; 120 | #endif 121 | 122 | NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, 123 | FS_INFORMATION_CLASS FsInformationClass); 124 | } 125 | 126 | typedef struct _REPARSE_DATA_BUFFER { 127 | ULONG ReparseTag; 128 | USHORT ReparseDataLength; 129 | USHORT Reserved; 130 | 131 | union { 132 | struct { 133 | USHORT SubstituteNameOffset; 134 | USHORT SubstituteNameLength; 135 | USHORT PrintNameOffset; 136 | USHORT PrintNameLength; 137 | ULONG Flags; 138 | WCHAR PathBuffer[1]; 139 | } SymbolicLinkReparseBuffer; 140 | 141 | struct { 142 | USHORT SubstituteNameOffset; 143 | USHORT SubstituteNameLength; 144 | USHORT PrintNameOffset; 145 | USHORT PrintNameLength; 146 | WCHAR PathBuffer[1]; 147 | } MountPointReparseBuffer; 148 | 149 | struct { 150 | UCHAR DataBuffer[1]; 151 | } GenericReparseBuffer; 152 | }; 153 | } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; 154 | 155 | #define SYMLINK_FLAG_RELATIVE 1 156 | 157 | #ifndef _MSC_VER 158 | 159 | typedef struct _DUPLICATE_EXTENTS_DATA { 160 | HANDLE FileHandle; 161 | LARGE_INTEGER SourceFileOffset; 162 | LARGE_INTEGER TargetFileOffset; 163 | LARGE_INTEGER ByteCount; 164 | } DUPLICATE_EXTENTS_DATA, *PDUPLICATE_EXTENTS_DATA; 165 | 166 | typedef struct _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER { 167 | WORD ChecksumAlgorithm; 168 | WORD Reserved; 169 | DWORD Flags; 170 | DWORD ChecksumChunkSizeInBytes; 171 | DWORD ClusterSizeInBytes; 172 | } FSCTL_GET_INTEGRITY_INFORMATION_BUFFER, *PFSCTL_GET_INTEGRITY_INFORMATION_BUFFER; 173 | 174 | typedef struct _FSCTL_SET_INTEGRITY_INFORMATION_BUFFER { 175 | WORD ChecksumAlgorithm; 176 | WORD Reserved; 177 | DWORD Flags; 178 | } FSCTL_SET_INTEGRITY_INFORMATION_BUFFER, *PFSCTL_SET_INTEGRITY_INFORMATION_BUFFER; 179 | 180 | #endif 181 | 182 | class win_handle { 183 | public: 184 | win_handle() { 185 | } 186 | 187 | win_handle(HANDLE nh) { 188 | h = nh; 189 | } 190 | 191 | ~win_handle() { 192 | if (h != INVALID_HANDLE_VALUE) 193 | CloseHandle(h); 194 | } 195 | 196 | operator HANDLE() const { 197 | return h; 198 | } 199 | 200 | win_handle& operator=(const HANDLE nh) { 201 | if (h != INVALID_HANDLE_VALUE) 202 | CloseHandle(h); 203 | 204 | h = nh; 205 | 206 | return *this; 207 | } 208 | 209 | HANDLE* operator&() { 210 | return &h; 211 | } 212 | 213 | private: 214 | HANDLE h = INVALID_HANDLE_VALUE; 215 | }; 216 | 217 | class fff_handle { 218 | public: 219 | fff_handle() { 220 | } 221 | 222 | fff_handle(HANDLE nh) { 223 | h = nh; 224 | } 225 | 226 | ~fff_handle() { 227 | if (h != INVALID_HANDLE_VALUE) 228 | FindClose(h); 229 | } 230 | 231 | operator HANDLE() const { 232 | return h; 233 | } 234 | 235 | fff_handle& operator=(const HANDLE nh) { 236 | if (h != INVALID_HANDLE_VALUE) 237 | FindClose(h); 238 | 239 | h = nh; 240 | 241 | return *this; 242 | } 243 | 244 | HANDLE* operator&() { 245 | return &h; 246 | } 247 | 248 | private: 249 | HANDLE h = INVALID_HANDLE_VALUE; 250 | }; 251 | 252 | class nt_handle { 253 | public: 254 | nt_handle() { 255 | } 256 | 257 | nt_handle(HANDLE nh) { 258 | h = nh; 259 | } 260 | 261 | ~nt_handle() { 262 | if (h != INVALID_HANDLE_VALUE) 263 | NtClose(h); 264 | } 265 | 266 | operator HANDLE() const { 267 | return h; 268 | } 269 | 270 | nt_handle& operator=(const HANDLE nh) { 271 | if (h != INVALID_HANDLE_VALUE) 272 | NtClose(h); 273 | 274 | h = nh; 275 | 276 | return *this; 277 | } 278 | 279 | HANDLE* operator&() { 280 | return &h; 281 | } 282 | 283 | private: 284 | HANDLE h = INVALID_HANDLE_VALUE; 285 | }; 286 | 287 | class string_error : public exception { 288 | public: 289 | string_error(int resno, ...); 290 | 291 | const char* what() const noexcept { 292 | return msg.c_str(); 293 | } 294 | 295 | private: 296 | string msg; 297 | }; 298 | 299 | 300 | class last_error : public exception { 301 | public: 302 | last_error(DWORD errnum); 303 | 304 | const char* what() const noexcept { 305 | return msg.c_str(); 306 | } 307 | 308 | private: 309 | string msg; 310 | }; 311 | 312 | class ntstatus_error : public exception { 313 | public: 314 | ntstatus_error(NTSTATUS Status); 315 | 316 | const char* what() const noexcept { 317 | return msg.c_str(); 318 | } 319 | 320 | NTSTATUS Status; 321 | 322 | private: 323 | string msg; 324 | }; 325 | 326 | class global_lock { 327 | public: 328 | global_lock(HGLOBAL mem) : mem(mem) { 329 | ptr = GlobalLock(mem); 330 | } 331 | 332 | ~global_lock() { 333 | if (ptr) 334 | GlobalUnlock(mem); 335 | } 336 | 337 | void* ptr; 338 | 339 | private: 340 | HGLOBAL mem; 341 | }; 342 | 343 | extern HMODULE module; 344 | void format_size(uint64_t size, wstring& s, bool show_bytes); 345 | void set_dpi_aware(); 346 | wstring format_message(ULONG last_error); 347 | wstring format_ntstatus(NTSTATUS Status); 348 | bool load_string(HMODULE module, UINT id, wstring& s); 349 | void wstring_sprintf(wstring& s, wstring fmt, ...); 350 | void command_line_to_args(LPWSTR cmdline, vector& args); 351 | wstring utf8_to_utf16(string_view utf8); 352 | void error_message(HWND hwnd, const char* msg); 353 | -------------------------------------------------------------------------------- /src/shellext/subvol.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maharmstone/btrfs/ce2997cbe111f0a57523af456c805a32fb7b4591/src/shellext/subvol.ico -------------------------------------------------------------------------------- /src/shellext/volpropsheet.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include "../btrfsioctl.h" 22 | #include "../btrfs.h" 23 | #include "balance.h" 24 | #include "scrub.h" 25 | 26 | extern LONG objs_loaded; 27 | 28 | class BtrfsVolPropSheet : public IShellExtInit, IShellPropSheetExt { 29 | public: 30 | BtrfsVolPropSheet() { 31 | refcount = 0; 32 | ignore = true; 33 | stgm_set = false; 34 | devices = nullptr; 35 | 36 | InterlockedIncrement(&objs_loaded); 37 | 38 | balance = nullptr; 39 | } 40 | 41 | virtual ~BtrfsVolPropSheet() { 42 | if (stgm_set) 43 | ReleaseStgMedium(&stgm); 44 | 45 | if (devices) 46 | free(devices); 47 | 48 | InterlockedDecrement(&objs_loaded); 49 | 50 | if (balance) 51 | delete balance; 52 | } 53 | 54 | // IUnknown 55 | 56 | HRESULT __stdcall QueryInterface(REFIID riid, void **ppObj); 57 | 58 | ULONG __stdcall AddRef() { 59 | return InterlockedIncrement(&refcount); 60 | } 61 | 62 | ULONG __stdcall Release() { 63 | LONG rc = InterlockedDecrement(&refcount); 64 | 65 | if (rc == 0) 66 | delete this; 67 | 68 | return rc; 69 | } 70 | 71 | // IShellExtInit 72 | 73 | virtual HRESULT __stdcall Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgID) override; 74 | 75 | // IShellPropSheetExt 76 | 77 | virtual HRESULT __stdcall AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) override; 78 | virtual HRESULT __stdcall ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam) override; 79 | 80 | void FormatUsage(HWND hwndDlg, wstring& s, btrfs_usage* usage); 81 | void RefreshUsage(HWND hwndDlg); 82 | void ShowUsage(HWND hwndDlg); 83 | INT_PTR CALLBACK UsageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 84 | void RefreshDevList(HWND devlist); 85 | INT_PTR CALLBACK DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 86 | void ShowDevices(HWND hwndDlg); 87 | void ShowScrub(HWND hwndDlg); 88 | void ShowChangeDriveLetter(HWND hwndDlg); 89 | INT_PTR CALLBACK StatsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 90 | void ShowStats(HWND hwndDlg, uint64_t devid); 91 | void ResetStats(HWND hwndDlg); 92 | 93 | btrfs_device* devices; 94 | bool readonly; 95 | BtrfsBalance* balance; 96 | BTRFS_UUID uuid; 97 | bool uuid_set; 98 | 99 | private: 100 | LONG refcount; 101 | bool ignore; 102 | STGMEDIUM stgm; 103 | bool stgm_set; 104 | wstring fn; 105 | uint64_t stats_dev; 106 | }; 107 | 108 | class BtrfsChangeDriveLetter { 109 | public: 110 | BtrfsChangeDriveLetter(HWND hwnd, wstring_view fn) : hwnd(hwnd), fn(fn) { 111 | } 112 | 113 | void show(); 114 | INT_PTR DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 115 | 116 | private: 117 | void do_change(HWND hwndDlg); 118 | 119 | HWND hwnd; 120 | wstring fn; 121 | vector letters; 122 | }; 123 | -------------------------------------------------------------------------------- /src/tests/manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | UTF-8 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/tests/overwrite.cpp: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | using namespace std; 4 | 5 | void test_overwrite(const u16string& dir) { 6 | unique_handle h; 7 | 8 | test("Try overwriting non-existent file", [&]() { 9 | exp_status([&]() { 10 | create_file(dir + u"\\nonsuch", MAXIMUM_ALLOWED, 0, 0, FILE_OVERWRITE, 11 | 0, FILE_OVERWRITTEN); 12 | }, STATUS_OBJECT_NAME_NOT_FOUND); 13 | }); 14 | 15 | test("Create readonly file", [&]() { 16 | h = create_file(dir + u"\\overwritero", MAXIMUM_ALLOWED, FILE_ATTRIBUTE_READONLY, 0, FILE_CREATE, 17 | 0, FILE_CREATED); 18 | }); 19 | 20 | if (h) { 21 | h.reset(); 22 | 23 | test("Try overwriting readonly file", [&]() { 24 | exp_status([&]() { 25 | create_file(dir + u"\\overwritero", MAXIMUM_ALLOWED, 0, 0, FILE_OVERWRITE, 26 | 0, FILE_OVERWRITTEN); 27 | }, STATUS_ACCESS_DENIED); 28 | }); 29 | } 30 | 31 | test("Create file", [&]() { 32 | h = create_file(dir + u"\\overwrite", MAXIMUM_ALLOWED, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 33 | FILE_CREATE, 0, FILE_CREATED); 34 | }); 35 | 36 | if (h) { 37 | test("Try overwriting open file", [&]() { 38 | create_file(dir + u"\\overwrite", MAXIMUM_ALLOWED, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 39 | FILE_OVERWRITE, 0, FILE_OVERWRITTEN); 40 | }); 41 | 42 | h.reset(); 43 | 44 | test("Overwrite file", [&]() { 45 | h = create_file(dir + u"\\overwrite", MAXIMUM_ALLOWED, 0, 0, FILE_OVERWRITE, 46 | 0, FILE_OVERWRITTEN); 47 | }); 48 | } 49 | 50 | if (h) { 51 | h.reset(); 52 | 53 | test("Overwrite file adding readonly flag", [&]() { 54 | create_file(dir + u"\\overwrite", MAXIMUM_ALLOWED, FILE_ATTRIBUTE_READONLY, 0, FILE_OVERWRITE, 55 | 0, FILE_OVERWRITTEN); 56 | }); 57 | } 58 | 59 | test("Create file", [&]() { 60 | h = create_file(dir + u"\\overwrite2", MAXIMUM_ALLOWED, 0, 0, FILE_CREATE, 61 | 0, FILE_CREATED); 62 | }); 63 | 64 | if (h) { 65 | h.reset(); 66 | 67 | test("Try overwriting file, changing to directory", [&]() { 68 | exp_status([&]() { 69 | create_file(dir + u"\\overwrite2", MAXIMUM_ALLOWED, 0, 0, FILE_OVERWRITE, 70 | FILE_DIRECTORY_FILE, FILE_OVERWRITTEN); 71 | }, STATUS_INVALID_PARAMETER); 72 | }); 73 | 74 | test("Overwrite file adding hidden flag", [&]() { 75 | h = create_file(dir + u"\\overwrite2", MAXIMUM_ALLOWED, FILE_ATTRIBUTE_HIDDEN, 0, FILE_OVERWRITE, 76 | 0, FILE_OVERWRITTEN); 77 | }); 78 | } 79 | 80 | if (h) { 81 | h.reset(); 82 | 83 | test("Try overwriting file clearing hidden flag", [&]() { 84 | exp_status([&]() { 85 | create_file(dir + u"\\overwrite2", MAXIMUM_ALLOWED, 0, 0, FILE_OVERWRITE, 86 | 0, FILE_OVERWRITTEN); 87 | }, STATUS_ACCESS_DENIED); 88 | }); 89 | } 90 | 91 | test("Overwrite file adding system flag", [&]() { 92 | h = create_file(dir + u"\\overwrite2", MAXIMUM_ALLOWED, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, 0, 93 | FILE_OVERWRITE, 0, FILE_OVERWRITTEN); 94 | }); 95 | 96 | if (h) { 97 | h.reset(); 98 | 99 | test("Try overwriting file clearing system flag", [&]() { 100 | exp_status([&]() { 101 | create_file(dir + u"\\overwrite2", MAXIMUM_ALLOWED, FILE_ATTRIBUTE_HIDDEN, 0, FILE_OVERWRITE, 102 | 0, FILE_OVERWRITTEN); 103 | }, STATUS_ACCESS_DENIED); 104 | }); 105 | } 106 | 107 | test("Create directory", [&]() { 108 | h = create_file(dir + u"\\overwritedir", MAXIMUM_ALLOWED, 0, 0, FILE_CREATE, 109 | FILE_DIRECTORY_FILE, FILE_CREATED); 110 | }); 111 | 112 | if (h) { 113 | h.reset(); 114 | 115 | test("Try overwriting directory", [&]() { 116 | exp_status([&]() { 117 | create_file(dir + u"\\overwritedir", MAXIMUM_ALLOWED, 0, 0, FILE_OVERWRITE, 118 | FILE_DIRECTORY_FILE, FILE_OVERWRITTEN); 119 | }, STATUS_INVALID_PARAMETER); 120 | }); 121 | 122 | test("Try overwriting directory, changing to file", [&]() { 123 | exp_status([&]() { 124 | create_file(dir + u"\\overwritedir", MAXIMUM_ALLOWED, 0, 0, FILE_OVERWRITE, 125 | FILE_NON_DIRECTORY_FILE, FILE_OVERWRITTEN); 126 | }, STATUS_FILE_IS_A_DIRECTORY); 127 | }); 128 | } 129 | 130 | test("Create file", [&]() { 131 | h = create_file(dir + u"\\overwrite3", MAXIMUM_ALLOWED, 0, 0, FILE_CREATE, 132 | 0, FILE_CREATED); 133 | }); 134 | 135 | if (h) { 136 | h.reset(); 137 | 138 | test("Overwrite file with different case", [&]() { 139 | h = create_file(dir + u"\\OVERWRITE3", MAXIMUM_ALLOWED, 0, 0, FILE_OVERWRITE, 140 | 0, FILE_OVERWRITTEN); 141 | }); 142 | 143 | if (h) { 144 | test("Check name", [&]() { 145 | auto fn = query_file_name_information(h.get()); 146 | 147 | static const u16string_view ends_with = u"\\overwrite3"; 148 | 149 | if (fn.size() < ends_with.size() || fn.substr(fn.size() - ends_with.size()) != ends_with) 150 | throw runtime_error("Name did not end with \"\\overwrite3\"."); 151 | }); 152 | } 153 | } 154 | 155 | test("Create file with FILE_OPEN_IF", [&]() { 156 | h = create_file(dir + u"\\overwriteif", MAXIMUM_ALLOWED, 0, 0, FILE_OVERWRITE_IF, 0, FILE_CREATED); 157 | }); 158 | 159 | if (h) { 160 | h.reset(); 161 | 162 | test("Open file with FILE_OVERWRITE_IF", [&]() { 163 | create_file(dir + u"\\overwriteif", MAXIMUM_ALLOWED, 0, 0, FILE_OVERWRITE_IF, 0, FILE_OVERWRITTEN); 164 | }); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/tests/supersede.cpp: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | using namespace std; 4 | 5 | void test_supersede(const u16string& dir) { 6 | unique_handle h; 7 | 8 | test("Create file by FILE_SUPERSEDE", [&]() { 9 | h = create_file(dir + u"\\supersede", MAXIMUM_ALLOWED, FILE_ATTRIBUTE_READONLY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 10 | FILE_SUPERSEDE, 0, FILE_CREATED); 11 | }); 12 | 13 | if (h) { 14 | test("Check attributes", [&]() { 15 | auto fbi = query_information(h.get()); 16 | 17 | if (fbi.FileAttributes != (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_ARCHIVE)) { 18 | throw formatted_error("attributes were {:x}, expected FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_ARCHIVE", 19 | fbi.FileAttributes); 20 | } 21 | }); 22 | 23 | test("Try superseding open file", [&]() { 24 | create_file(dir + u"\\supersede", MAXIMUM_ALLOWED, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 25 | FILE_SUPERSEDE, 0, FILE_SUPERSEDED); 26 | }); 27 | 28 | h.reset(); 29 | } 30 | 31 | test("Supersede file", [&]() { 32 | h = create_file(dir + u"\\supersede", MAXIMUM_ALLOWED, 0, 0, FILE_SUPERSEDE, 33 | 0, FILE_SUPERSEDED); 34 | }); 35 | 36 | if (h) { 37 | test("Check attributes", [&]() { 38 | auto fbi = query_information(h.get()); 39 | 40 | if (fbi.FileAttributes != FILE_ATTRIBUTE_ARCHIVE) { 41 | throw formatted_error("attributes were {:x}, expected FILE_ATTRIBUTE_ARCHIVE", 42 | fbi.FileAttributes); 43 | } 44 | }); 45 | 46 | h.reset(); 47 | } 48 | 49 | test("Supersede adding hidden flag", [&]() { 50 | create_file(dir + u"\\supersede", MAXIMUM_ALLOWED, FILE_ATTRIBUTE_HIDDEN, 0, 51 | FILE_SUPERSEDE, 0, FILE_SUPERSEDED); 52 | }); 53 | 54 | test("Try superseding while clearing hidden flag", [&]() { 55 | exp_status([&]() { 56 | create_file(dir + u"\\supersede", MAXIMUM_ALLOWED, 0, 0, FILE_SUPERSEDE, 57 | 0, FILE_SUPERSEDED); 58 | }, STATUS_ACCESS_DENIED); 59 | }); 60 | 61 | test("Supersede adding system flag", [&]() { 62 | create_file(dir + u"\\supersede", MAXIMUM_ALLOWED, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, 0, 63 | FILE_SUPERSEDE, 0, FILE_SUPERSEDED); 64 | }); 65 | 66 | test("Try superseding while clearing system flag", [&]() { 67 | exp_status([&]() { 68 | create_file(dir + u"\\supersede", MAXIMUM_ALLOWED, FILE_ATTRIBUTE_HIDDEN, 0, 69 | FILE_SUPERSEDE, 0, FILE_SUPERSEDED); 70 | }, STATUS_ACCESS_DENIED); 71 | }); 72 | 73 | test("Try creating directory by FILE_SUPERSEDE", [&]() { 74 | exp_status([&]() { 75 | create_file(dir + u"\\supersededir", MAXIMUM_ALLOWED, 0, 0, FILE_SUPERSEDE, 76 | FILE_DIRECTORY_FILE, FILE_CREATED); 77 | }, STATUS_INVALID_PARAMETER); 78 | }); 79 | 80 | test("Create file", [&]() { 81 | h = create_file(dir + u"\\supersede2", MAXIMUM_ALLOWED, 0, 0, FILE_CREATE, 82 | 0, FILE_CREATED); 83 | }); 84 | 85 | if (h) { 86 | h.reset(); 87 | 88 | test("Supersede file with different case", [&]() { 89 | h = create_file(dir + u"\\SUPERSEDE2", MAXIMUM_ALLOWED, 0, 0, FILE_SUPERSEDE, 90 | 0, FILE_SUPERSEDED); 91 | }); 92 | 93 | if (h) { 94 | test("Check name", [&]() { 95 | auto fn = query_file_name_information(h.get()); 96 | 97 | static const u16string_view ends_with = u"\\supersede2"; 98 | 99 | if (fn.size() < ends_with.size() || fn.substr(fn.size() - ends_with.size()) != ends_with) 100 | throw runtime_error("Name did not end with \"\\supersede2\"."); 101 | }); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/tests/test.rc.in: -------------------------------------------------------------------------------- 1 | #define APSTUDIO_READONLY_SYMBOLS 2 | #include 3 | #undef APSTUDIO_READONLY_SYMBOLS 4 | 5 | ///////////////////////////////////////////////////////////////////////////// 6 | // English (United Kingdom) resources 7 | 8 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) 9 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK 10 | #pragma code_page(1252) 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | // 14 | // Version 15 | // 16 | 17 | VS_VERSION_INFO VERSIONINFO 18 | FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 19 | PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 20 | FILEFLAGSMASK 0x17L 21 | #ifdef _DEBUG 22 | FILEFLAGS 0x1L 23 | #else 24 | FILEFLAGS 0x0L 25 | #endif 26 | FILEOS 0x4L 27 | FILETYPE 0x1L 28 | FILESUBTYPE 0x0L 29 | BEGIN 30 | BLOCK "StringFileInfo" 31 | BEGIN 32 | BLOCK "080904b0" 33 | BEGIN 34 | VALUE "FileDescription", "WinBtrfs test program" 35 | VALUE "FileVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" 36 | VALUE "InternalName", "test" 37 | VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2021-24" 38 | VALUE "OriginalFilename", "test.exe" 39 | VALUE "ProductName", "WinBtrfs" 40 | VALUE "ProductVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" 41 | END 42 | END 43 | BLOCK "VarFileInfo" 44 | BEGIN 45 | VALUE "Translation", 0x809, 1200 46 | END 47 | END 48 | 49 | 1 RT_MANIFEST "@CMAKE_CURRENT_SOURCE_DIR@/src/tests/manifest.xml" 50 | 51 | #endif // English (United Kingdom) resources 52 | ///////////////////////////////////////////////////////////////////////////// 53 | -------------------------------------------------------------------------------- /src/ubtrfs/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by ubtrfs.rc 4 | // 5 | 6 | // Next default values for new objects 7 | // 8 | #ifdef APSTUDIO_INVOKED 9 | #ifndef APSTUDIO_READONLY_SYMBOLS 10 | #define _APS_NEXT_RESOURCE_VALUE 101 11 | #define _APS_NEXT_COMMAND_VALUE 40001 12 | #define _APS_NEXT_CONTROL_VALUE 1001 13 | #define _APS_NEXT_SYMED_VALUE 101 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /src/ubtrfs/ubtrfs.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | ChkdskEx PRIVATE 3 | FormatEx PRIVATE 4 | GetFilesystemInformation PRIVATE 5 | SetSizes PRIVATE 6 | SetIncompatFlags PRIVATE 7 | SetCsumType PRIVATE 8 | SetCompatROFlags PRIVATE 9 | -------------------------------------------------------------------------------- /src/ubtrfs/ubtrfs.rc.in: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "@CMAKE_CURRENT_SOURCE_DIR@/src/ubtrfs/resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (United Kingdom) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) 19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK 20 | #pragma code_page(1252) 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Version 51 | // 52 | 53 | VS_VERSION_INFO VERSIONINFO 54 | FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 55 | PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 56 | FILEFLAGSMASK 0x17L 57 | #ifdef _DEBUG 58 | FILEFLAGS 0x1L 59 | #else 60 | FILEFLAGS 0x0L 61 | #endif 62 | FILEOS 0x4L 63 | FILETYPE 0x2L 64 | FILESUBTYPE 0x0L 65 | BEGIN 66 | BLOCK "StringFileInfo" 67 | BEGIN 68 | BLOCK "080904b0" 69 | BEGIN 70 | VALUE "FileDescription", "Btrfs utility DLL" 71 | VALUE "FileVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" 72 | VALUE "InternalName", "ubtrfs" 73 | VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-24" 74 | VALUE "OriginalFilename", "ubtrfs.dll" 75 | VALUE "ProductName", "WinBtrfs" 76 | VALUE "ProductVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" 77 | END 78 | END 79 | BLOCK "VarFileInfo" 80 | BEGIN 81 | VALUE "Translation", 0x809, 1200 82 | END 83 | END 84 | 85 | #endif // English (United Kingdom) resources 86 | ///////////////////////////////////////////////////////////////////////////// 87 | 88 | 89 | 90 | #ifndef APSTUDIO_INVOKED 91 | ///////////////////////////////////////////////////////////////////////////// 92 | // 93 | // Generated from the TEXTINCLUDE 3 resource. 94 | // 95 | 96 | 97 | ///////////////////////////////////////////////////////////////////////////// 98 | #endif // not APSTUDIO_INVOKED 99 | 100 | -------------------------------------------------------------------------------- /src/worker-thread.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2016-17 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | #include "btrfs_drv.h" 19 | 20 | typedef struct { 21 | device_extension* Vcb; 22 | PIRP Irp; 23 | WORK_QUEUE_ITEM item; 24 | } job_info; 25 | 26 | NTSTATUS do_read_job(PIRP Irp) { 27 | NTSTATUS Status; 28 | ULONG bytes_read; 29 | bool top_level = is_top_level(Irp); 30 | PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 31 | PFILE_OBJECT FileObject = IrpSp->FileObject; 32 | fcb* fcb = FileObject->FsContext; 33 | bool acquired_fcb_lock = false; 34 | 35 | Irp->IoStatus.Information = 0; 36 | 37 | if (!ExIsResourceAcquiredSharedLite(fcb->Header.Resource)) { 38 | ExAcquireResourceSharedLite(fcb->Header.Resource, true); 39 | acquired_fcb_lock = true; 40 | } 41 | 42 | try { 43 | Status = do_read(Irp, true, &bytes_read); 44 | } except (EXCEPTION_EXECUTE_HANDLER) { 45 | Status = GetExceptionCode(); 46 | } 47 | 48 | if (acquired_fcb_lock) 49 | ExReleaseResourceLite(fcb->Header.Resource); 50 | 51 | if (!NT_SUCCESS(Status)) 52 | ERR("do_read returned %08lx\n", Status); 53 | 54 | Irp->IoStatus.Status = Status; 55 | 56 | TRACE("read %Iu bytes\n", Irp->IoStatus.Information); 57 | 58 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 59 | 60 | if (top_level) 61 | IoSetTopLevelIrp(NULL); 62 | 63 | TRACE("returning %08lx\n", Status); 64 | 65 | return Status; 66 | } 67 | 68 | NTSTATUS do_write_job(device_extension* Vcb, PIRP Irp) { 69 | bool top_level = is_top_level(Irp); 70 | NTSTATUS Status; 71 | 72 | try { 73 | Status = write_file(Vcb, Irp, true, true); 74 | } except (EXCEPTION_EXECUTE_HANDLER) { 75 | Status = GetExceptionCode(); 76 | } 77 | 78 | if (!NT_SUCCESS(Status)) 79 | ERR("write_file returned %08lx\n", Status); 80 | 81 | Irp->IoStatus.Status = Status; 82 | 83 | TRACE("wrote %Iu bytes\n", Irp->IoStatus.Information); 84 | 85 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 86 | 87 | if (top_level) 88 | IoSetTopLevelIrp(NULL); 89 | 90 | TRACE("returning %08lx\n", Status); 91 | 92 | return Status; 93 | } 94 | 95 | _Function_class_(WORKER_THREAD_ROUTINE) 96 | static void __stdcall do_job(void* context) { 97 | job_info* ji = context; 98 | PIO_STACK_LOCATION IrpSp = ji->Irp ? IoGetCurrentIrpStackLocation(ji->Irp) : NULL; 99 | 100 | if (IrpSp->MajorFunction == IRP_MJ_READ) { 101 | do_read_job(ji->Irp); 102 | } else if (IrpSp->MajorFunction == IRP_MJ_WRITE) { 103 | do_write_job(ji->Vcb, ji->Irp); 104 | } 105 | 106 | ExFreePool(ji); 107 | } 108 | 109 | bool add_thread_job(device_extension* Vcb, PIRP Irp) { 110 | job_info* ji; 111 | 112 | ji = ExAllocatePoolWithTag(NonPagedPool, sizeof(job_info), ALLOC_TAG); 113 | if (!ji) { 114 | ERR("out of memory\n"); 115 | return false; 116 | } 117 | 118 | ji->Vcb = Vcb; 119 | ji->Irp = Irp; 120 | 121 | if (!Irp->MdlAddress) { 122 | PMDL Mdl; 123 | LOCK_OPERATION op; 124 | ULONG len; 125 | PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 126 | 127 | if (IrpSp->MajorFunction == IRP_MJ_READ) { 128 | op = IoWriteAccess; 129 | len = IrpSp->Parameters.Read.Length; 130 | } else if (IrpSp->MajorFunction == IRP_MJ_WRITE) { 131 | op = IoReadAccess; 132 | len = IrpSp->Parameters.Write.Length; 133 | } else { 134 | ERR("unexpected major function %u\n", IrpSp->MajorFunction); 135 | ExFreePool(ji); 136 | return false; 137 | } 138 | 139 | Mdl = IoAllocateMdl(Irp->UserBuffer, len, false, false, Irp); 140 | 141 | if (!Mdl) { 142 | ERR("out of memory\n"); 143 | ExFreePool(ji); 144 | return false; 145 | } 146 | 147 | try { 148 | MmProbeAndLockPages(Mdl, Irp->RequestorMode, op); 149 | } except(EXCEPTION_EXECUTE_HANDLER) { 150 | ERR("MmProbeAndLockPages raised status %08lx\n", GetExceptionCode()); 151 | 152 | IoFreeMdl(Mdl); 153 | Irp->MdlAddress = NULL; 154 | ExFreePool(ji); 155 | 156 | return false; 157 | } 158 | } 159 | 160 | ExInitializeWorkItem(&ji->item, do_job, ji); 161 | ExQueueWorkItem(&ji->item, DelayedWorkQueue); 162 | 163 | return true; 164 | } 165 | -------------------------------------------------------------------------------- /src/xor-gas.S: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Mark Harmstone 2020 2 | * 3 | * This file is part of WinBtrfs. 4 | * 5 | * WinBtrfs is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public Licence as published by 7 | * the Free Software Foundation, either version 3 of the Licence, or 8 | * (at your option) any later version. 9 | * 10 | * WinBtrfs is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public Licence for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public Licence 16 | * along with WinBtrfs. If not, see . */ 17 | 18 | .intel_syntax noprefix 19 | 20 | #ifdef __x86_64__ 21 | 22 | .global do_xor_sse2 23 | 24 | /* void do_xor_sse2(uint8_t* buf1, uint8_t* buf2, uint32_t len); */ 25 | do_xor_sse2: 26 | /* rcx = buf1 27 | * rdx = buf2 28 | * r8d = len 29 | * rax = tmp1 30 | * r9 = tmp2 31 | * xmm0 = tmp3 32 | * xmm1 = tmp4 */ 33 | 34 | mov rax, rcx 35 | and rax, 15 36 | cmp rax, 0 37 | jne stragglers2 38 | 39 | mov rax, rdx 40 | and rax, 15 41 | cmp rax, 0 42 | jne stragglers2 43 | 44 | do_xor_sse2_loop: 45 | cmp r8d, 16 46 | jl stragglers2 47 | 48 | movdqa xmm0, [rcx] 49 | movdqa xmm1, [rdx] 50 | pxor xmm0, xmm1 51 | movdqa [rcx], xmm0 52 | 53 | add rcx, 16 54 | add rdx, 16 55 | sub r8d, 16 56 | 57 | jmp do_xor_sse2_loop 58 | 59 | stragglers2: 60 | 61 | cmp r8d, 8 62 | jl stragglers 63 | 64 | mov rax, [rcx] 65 | mov r9, [rdx] 66 | xor rax, r9 67 | mov [rcx], rax 68 | 69 | add rcx, 8 70 | add rdx, 8 71 | sub r8d, 8 72 | 73 | jmp stragglers2 74 | 75 | stragglers: 76 | 77 | cmp r8d, 0 78 | je do_xor_sse2_end 79 | 80 | mov al, [rcx] 81 | mov r9b, [rdx] 82 | xor al, r9b 83 | mov [rcx], al 84 | 85 | inc rcx 86 | inc rdx 87 | dec r8d 88 | 89 | jmp stragglers 90 | 91 | do_xor_sse2_end: 92 | ret 93 | 94 | .global do_xor_avx2 95 | 96 | /* void do_xor_avx2(uint8_t* buf1, uint8_t* buf2, uint32_t len); */ 97 | do_xor_avx2: 98 | /* rcx = buf1 99 | * rdx = buf2 100 | * r8d = len 101 | * rax = tmp1 102 | * r9 = tmp2 103 | * xmm0 = tmp3 104 | * xmm1 = tmp4 */ 105 | 106 | mov rax, rcx 107 | and rax, 31 108 | cmp rax, 0 109 | jne stragglers4 110 | 111 | mov rax, rdx 112 | and rax, 31 113 | cmp rax, 0 114 | jne stragglers4 115 | 116 | do_xor_avx2_loop: 117 | cmp r8d, 32 118 | jl stragglers4 119 | 120 | vmovdqa ymm0, [rcx] 121 | vmovdqa ymm1, [rdx] 122 | vpxor ymm0, ymm0, ymm1 123 | vmovdqa [rcx], ymm0 124 | 125 | add rcx, 32 126 | add rdx, 32 127 | sub r8d, 32 128 | 129 | jmp do_xor_avx2_loop 130 | 131 | stragglers4: 132 | 133 | cmp r8d, 8 134 | jl stragglers3 135 | 136 | mov rax, [rcx] 137 | mov r9, [rdx] 138 | xor rax, r9 139 | mov [rcx], rax 140 | 141 | add rcx, 8 142 | add rdx, 8 143 | sub r8d, 8 144 | 145 | jmp stragglers4 146 | 147 | stragglers3: 148 | 149 | cmp r8d, 0 150 | je do_xor_avx2_end 151 | 152 | mov al, [rcx] 153 | mov r9b, [rdx] 154 | xor al, r9b 155 | mov [rcx], al 156 | 157 | inc rcx 158 | inc rdx 159 | dec r8d 160 | 161 | jmp stragglers3 162 | 163 | do_xor_avx2_end: 164 | ret 165 | 166 | #else 167 | 168 | .global _do_xor_sse2@12 169 | 170 | /* void __stdcall do_xor_sse2(uint8_t* buf1, uint8_t* buf2, uint32_t len); */ 171 | _do_xor_sse2@12: 172 | /* edi = buf1 173 | * edx = buf2 174 | * esi = len 175 | * eax = tmp1 176 | * ecx = tmp2 177 | * xmm0 = tmp3 178 | * xmm1 = tmp4 */ 179 | 180 | push ebp 181 | mov ebp, esp 182 | 183 | push esi 184 | push edi 185 | 186 | mov edi, [ebp+8] 187 | mov edx, [ebp+12] 188 | mov esi, [ebp+16] 189 | 190 | mov eax, edi 191 | and eax, 15 192 | cmp eax, 0 193 | jne stragglers2 194 | 195 | mov eax, edx 196 | and eax, 15 197 | cmp eax, 0 198 | jne stragglers2 199 | 200 | do_xor_sse2_loop: 201 | cmp esi, 16 202 | jl stragglers2 203 | 204 | movdqa xmm0, [edi] 205 | movdqa xmm1, [edx] 206 | pxor xmm0, xmm1 207 | movdqa [edi], xmm0 208 | 209 | add edi, 16 210 | add edx, 16 211 | sub esi, 16 212 | 213 | jmp do_xor_sse2_loop 214 | 215 | stragglers2: 216 | 217 | cmp esi, 4 218 | jl stragglers 219 | 220 | mov eax, [edi] 221 | mov ecx, [edx] 222 | xor eax, ecx 223 | mov [edi], eax 224 | 225 | add edi, 4 226 | add edx, 4 227 | sub esi, 4 228 | 229 | jmp stragglers2 230 | 231 | stragglers: 232 | 233 | cmp esi, 0 234 | je do_xor_sse2_end 235 | 236 | mov al, [edi] 237 | mov cl, [edx] 238 | xor al, cl 239 | mov [edi], al 240 | 241 | inc edi 242 | inc edx 243 | dec esi 244 | 245 | jmp stragglers 246 | 247 | do_xor_sse2_end: 248 | pop edi 249 | pop esi 250 | pop ebp 251 | 252 | ret 12 253 | 254 | .global _do_xor_avx2@12 255 | 256 | /* void __stdcall do_xor_avx2(uint8_t* buf1, uint8_t* buf2, uint32_t len); */ 257 | _do_xor_avx2@12: 258 | /* edi = buf1 259 | * edx = buf2 260 | * esi = len 261 | * eax = tmp1 262 | * ecx = tmp2 263 | * xmm0 = tmp3 264 | * xmm1 = tmp4 */ 265 | 266 | push ebp 267 | mov ebp, esp 268 | 269 | push esi 270 | push edi 271 | 272 | mov edi, [ebp+8] 273 | mov edx, [ebp+12] 274 | mov esi, [ebp+16] 275 | 276 | mov eax, edi 277 | and eax, 31 278 | cmp eax, 0 279 | jne stragglers4 280 | 281 | mov eax, edx 282 | and eax, 31 283 | cmp eax, 0 284 | jne stragglers4 285 | 286 | do_xor_avx2_loop: 287 | cmp esi, 32 288 | jl stragglers4 289 | 290 | vmovdqa ymm0, [edi] 291 | vmovdqa ymm1, [edx] 292 | vpxor ymm0, ymm0, ymm1 293 | vmovdqa [edi], ymm0 294 | 295 | add edi, 32 296 | add edx, 32 297 | sub esi, 32 298 | 299 | jmp do_xor_avx2_loop 300 | 301 | stragglers4: 302 | 303 | cmp esi, 4 304 | jl stragglers3 305 | 306 | mov eax, [edi] 307 | mov ecx, [edx] 308 | xor eax, ecx 309 | mov [edi], eax 310 | 311 | add edi, 4 312 | add edx, 4 313 | sub esi, 4 314 | 315 | jmp stragglers4 316 | 317 | stragglers3: 318 | 319 | cmp esi, 0 320 | je do_xor_avx2_end 321 | 322 | mov al, [edi] 323 | mov cl, [edx] 324 | xor al, cl 325 | mov [edi], al 326 | 327 | inc edi 328 | inc edx 329 | dec esi 330 | 331 | jmp stragglers3 332 | 333 | do_xor_avx2_end: 334 | pop edi 335 | pop esi 336 | pop ebp 337 | 338 | ret 12 339 | 340 | #endif 341 | -------------------------------------------------------------------------------- /src/xor-masm.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Mark Harmstone 2020 2 | ; 3 | ; This file is part of WinBtrfs. 4 | ; 5 | ; WinBtrfs is free software: you can redistribute it and/or modify 6 | ; it under the terms of the GNU Lesser General Public Licence as published by 7 | ; the Free Software Foundation, either version 3 of the Licence, or 8 | ; (at your option) any later version. 9 | ; 10 | ; WinBtrfs is distributed in the hope that it will be useful, 11 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ; GNU Lesser General Public Licence for more details. 14 | ; 15 | ; You should have received a copy of the GNU Lesser General Public Licence 16 | ; along with WinBtrfs. If not, see . 17 | 18 | IFDEF RAX 19 | ELSE 20 | .686P 21 | .xmm 22 | ENDIF 23 | 24 | _TEXT SEGMENT 25 | 26 | IFDEF RAX 27 | 28 | PUBLIC do_xor_sse2 29 | 30 | ; void do_xor_sse2(uint8_t* buf1, uint8_t* buf2, uint32_t len); 31 | do_xor_sse2: 32 | ; rcx = buf1 33 | ; rdx = buf2 34 | ; r8d = len 35 | ; rax = tmp1 36 | ; r9 = tmp2 37 | ; xmm0 = tmp3 38 | ; xmm1 = tmp4 39 | 40 | mov rax, rcx 41 | and rax, 15 42 | cmp rax, 0 43 | jne stragglers2 44 | 45 | mov rax, rdx 46 | and rax, 15 47 | cmp rax, 0 48 | jne stragglers2 49 | 50 | do_xor_sse2_loop: 51 | cmp r8d, 16 52 | jl stragglers2 53 | 54 | movdqa xmm0, [rcx] 55 | movdqa xmm1, [rdx] 56 | pxor xmm0, xmm1 57 | movdqa [rcx], xmm0 58 | 59 | add rcx, 16 60 | add rdx, 16 61 | sub r8d, 16 62 | 63 | jmp do_xor_sse2_loop 64 | 65 | stragglers2: 66 | 67 | cmp r8d, 8 68 | jl stragglers 69 | 70 | mov rax, [rcx] 71 | mov r9, [rdx] 72 | xor rax, r9 73 | mov [rcx], rax 74 | 75 | add rcx, 8 76 | add rdx, 8 77 | sub r8d, 8 78 | 79 | jmp stragglers2 80 | 81 | stragglers: 82 | 83 | cmp r8d, 0 84 | je do_xor_sse2_end 85 | 86 | mov al, [rcx] 87 | mov r9b, [rdx] 88 | xor al, r9b 89 | mov [rcx], al 90 | 91 | inc rcx 92 | inc rdx 93 | dec r8d 94 | 95 | jmp stragglers 96 | 97 | do_xor_sse2_end: 98 | ret 99 | 100 | PUBLIC do_xor_avx2 101 | 102 | ; void do_xor_avx2(uint8_t* buf1, uint8_t* buf2, uint32_t len); 103 | do_xor_avx2: 104 | ; rcx = buf1 105 | ; rdx = buf2 106 | ; r8d = len 107 | ; rax = tmp1 108 | ; r9 = tmp2 109 | ; xmm0 = tmp3 110 | ; xmm1 = tmp4 111 | 112 | mov rax, rcx 113 | and rax, 31 114 | cmp rax, 0 115 | jne stragglers4 116 | 117 | mov rax, rdx 118 | and rax, 31 119 | cmp rax, 0 120 | jne stragglers4 121 | 122 | do_xor_avx2_loop: 123 | cmp r8d, 32 124 | jl stragglers4 125 | 126 | vmovdqa ymm0, YMMWORD PTR[rcx] 127 | vmovdqa ymm1, YMMWORD PTR[rdx] 128 | vpxor ymm0, ymm0, ymm1 129 | vmovdqa YMMWORD PTR[rcx], ymm0 130 | 131 | add rcx, 32 132 | add rdx, 32 133 | sub r8d, 32 134 | 135 | jmp do_xor_avx2_loop 136 | 137 | stragglers4: 138 | 139 | cmp r8d, 8 140 | jl stragglers3 141 | 142 | mov rax, [rcx] 143 | mov r9, [rdx] 144 | xor rax, r9 145 | mov [rcx], rax 146 | 147 | add rcx, 8 148 | add rdx, 8 149 | sub r8d, 8 150 | 151 | jmp stragglers4 152 | 153 | stragglers3: 154 | 155 | cmp r8d, 0 156 | je do_xor_avx2_end 157 | 158 | mov al, [rcx] 159 | mov r9b, [rdx] 160 | xor al, r9b 161 | mov [rcx], al 162 | 163 | inc rcx 164 | inc rdx 165 | dec r8d 166 | 167 | jmp stragglers3 168 | 169 | do_xor_avx2_end: 170 | ret 171 | 172 | ELSE 173 | 174 | PUBLIC do_xor_sse2@12 175 | 176 | ; void __stdcall do_xor_sse2(uint8_t* buf1, uint8_t* buf2, uint32_t len); 177 | do_xor_sse2@12: 178 | ; edi = buf1 179 | ; edx = buf2 180 | ; esi = len 181 | ; eax = tmp1 182 | ; ecx = tmp2 183 | ; xmm0 = tmp3 184 | ; xmm1 = tmp4 185 | 186 | push ebp 187 | mov ebp, esp 188 | 189 | push esi 190 | push edi 191 | 192 | mov edi, [ebp+8] 193 | mov edx, [ebp+12] 194 | mov esi, [ebp+16] 195 | 196 | mov eax, edi 197 | and eax, 15 198 | cmp eax, 0 199 | jne stragglers2 200 | 201 | mov eax, edx 202 | and eax, 15 203 | cmp eax, 0 204 | jne stragglers2 205 | 206 | do_xor_sse2_loop: 207 | cmp esi, 16 208 | jl stragglers2 209 | 210 | movdqa xmm0, [edi] 211 | movdqa xmm1, [edx] 212 | pxor xmm0, xmm1 213 | movdqa [edi], xmm0 214 | 215 | add edi, 16 216 | add edx, 16 217 | sub esi, 16 218 | 219 | jmp do_xor_sse2_loop 220 | 221 | stragglers2: 222 | 223 | cmp esi, 4 224 | jl stragglers 225 | 226 | mov eax, [edi] 227 | mov ecx, [edx] 228 | xor eax, ecx 229 | mov [edi], eax 230 | 231 | add edi, 4 232 | add edx, 4 233 | sub esi, 4 234 | 235 | jmp stragglers2 236 | 237 | stragglers: 238 | 239 | cmp esi, 0 240 | je do_xor_sse2_end 241 | 242 | mov al, [edi] 243 | mov cl, [edx] 244 | xor al, cl 245 | mov [edi], al 246 | 247 | inc edi 248 | inc edx 249 | dec esi 250 | 251 | jmp stragglers 252 | 253 | do_xor_sse2_end: 254 | pop edi 255 | pop esi 256 | pop ebp 257 | 258 | ret 12 259 | 260 | PUBLIC do_xor_avx2@12 261 | 262 | ; void __stdcall do_xor_avx2(uint8_t* buf1, uint8_t* buf2, uint32_t len); 263 | do_xor_avx2@12: 264 | ; edi = buf1 265 | ; edx = buf2 266 | ; esi = len 267 | ; eax = tmp1 268 | ; ecx = tmp2 269 | ; xmm0 = tmp3 270 | ; xmm1 = tmp4 271 | 272 | push ebp 273 | mov ebp, esp 274 | 275 | push esi 276 | push edi 277 | 278 | mov edi, [ebp+8] 279 | mov edx, [ebp+12] 280 | mov esi, [ebp+16] 281 | 282 | mov eax, edi 283 | and eax, 31 284 | cmp eax, 0 285 | jne stragglers4 286 | 287 | mov eax, edx 288 | and eax, 31 289 | cmp eax, 0 290 | jne stragglers4 291 | 292 | do_xor_avx2_loop: 293 | cmp esi, 32 294 | jl stragglers4 295 | 296 | vmovdqa ymm0, YMMWORD PTR[edi] 297 | vmovdqa ymm1, YMMWORD PTR[edx] 298 | vpxor ymm0, ymm0, ymm1 299 | vmovdqa YMMWORD PTR[edi], ymm0 300 | 301 | add edi, 32 302 | add edx, 32 303 | sub esi, 32 304 | 305 | jmp do_xor_avx2_loop 306 | 307 | stragglers4: 308 | 309 | cmp esi, 4 310 | jl stragglers3 311 | 312 | mov eax, [edi] 313 | mov ecx, [edx] 314 | xor eax, ecx 315 | mov [edi], eax 316 | 317 | add edi, 4 318 | add edx, 4 319 | sub esi, 4 320 | 321 | jmp stragglers4 322 | 323 | stragglers3: 324 | 325 | cmp esi, 0 326 | je do_xor_avx2_end 327 | 328 | mov al, [edi] 329 | mov cl, [edx] 330 | xor al, cl 331 | mov [edi], al 332 | 333 | inc edi 334 | inc edx 335 | dec esi 336 | 337 | jmp stragglers3 338 | 339 | do_xor_avx2_end: 340 | pop edi 341 | pop esi 342 | pop ebp 343 | 344 | ret 12 345 | 346 | ENDIF 347 | 348 | _TEXT ENDS 349 | 350 | end 351 | -------------------------------------------------------------------------------- /src/zstd-shim.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static void* ZSTD_malloc(size_t size) { 5 | return NULL; 6 | } 7 | 8 | static void* ZSTD_calloc(size_t nmemb, size_t size) { 9 | return NULL; 10 | } 11 | 12 | static void ZSTD_free(void* ptr) { 13 | } 14 | 15 | #ifdef _MSC_VER 16 | 17 | #include 18 | 19 | #pragma intrinsic(_byteswap_uint64) 20 | #pragma intrinsic(_byteswap_ulong) 21 | #pragma intrinsic(_rotl) 22 | #pragma intrinsic(_rotl64) 23 | 24 | #endif 25 | --------------------------------------------------------------------------------