Full Code of maharmstone/btrfs for AI

master b415418815f6 cached
117 files
4.0 MB
1.0M tokens
1292 symbols
1 requests
Download .txt
Showing preview only (4,162K chars total). Download the full file or copy to clipboard to get everything.
Repository: maharmstone/btrfs
Branch: master
Commit: b415418815f6
Files: 117
Total size: 4.0 MB

Directory structure:
gitextract_g2azv67f/

├── .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
    │   ├── 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

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/build.yml
================================================
name: build
on: [push]
env:
   PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/etc/eselect/wine/bin
jobs:
  cmake:
    runs-on: msvc-wine
    container:
      volumes:
        - /var/run/pcscd/pcscd.comm:/var/run/pcscd/pcscd.comm
    steps:
      - run: echo "SHORT_SHA=`echo ${{ github.sha }} | cut -c1-8`" >> $GITHUB_ENV
      - run: git clone --recurse-submodules -j`nproc` ${{ github.server_url }}/${{ github.repository }} ${SHORT_SHA}
      - run: cd ${SHORT_SHA} && git checkout ${{ github.sha }}
      - run: mkdir -p build/debug/{amd64,x86,aarch64,arm}
      - run: mkdir -p build/release/{amd64,x86,aarch64,arm}
      - run: mkdir -p build/pdb/{debug,release}/{amd64,x86,aarch64,arm}
      - 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`
      - 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`
      - 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`
      - 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`
      - 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`
      - 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`
      - 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`
      - 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`
      - run: mv build/debug/amd64/*.pdb build/pdb/debug/amd64/
      - run: mv build/debug/x86/*.pdb build/pdb/debug/x86/
      - run: mv build/debug/aarch64/*.pdb build/pdb/debug/aarch64/
      - run: mv build/debug/arm/*.pdb build/pdb/debug/arm/
      - run: mv build/release/amd64/*.pdb build/pdb/release/amd64/
      - run: mv build/release/x86/*.pdb build/pdb/release/x86/
      - run: mv build/release/aarch64/*.pdb build/pdb/release/aarch64/
      - run: mv build/release/arm/*.pdb build/pdb/release/arm/
      - run: cp ${SHORT_SHA}/src/{btrfs,btrfs-vol}.inf build/debug/
      - run: cp ${SHORT_SHA}/src/{btrfs,btrfs-vol}.inf build/release/
      - run: stampinf -f build/debug/btrfs.inf -d \* -v \*
      - run: stampinf -f build/debug/btrfs-vol.inf -d \* -v \*
      - run: stampinf -f build/release/btrfs.inf -d \* -v \*
      - run: stampinf -f build/release/btrfs-vol.inf -d \* -v \*
      - run: cd build/debug && makecat ../../${SHORT_SHA}/src/btrfs.cdf
      - run: cd build/release && makecat ../../${SHORT_SHA}/src/btrfs.cdf
      - env:
          CERTIFICATE: ${{ secrets.CERTIFICATE }}
        run: echo "${CERTIFICATE}" > codesigning.crt
      - env:
          PKCS11CERT: ${{ secrets.PKCS11CERT }}
          PKCS11KEY: ${{ secrets.PKCS11KEY }}
        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
      - env:
          PKCS11CERT: ${{ secrets.PKCS11CERT }}
          PKCS11KEY: ${{ secrets.PKCS11KEY }}
        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
      - uses: actions/upload-artifact@v3
        with:
          name: ${{ github.sha }}
          overwrite: true
          path: |
            build/**/btrfs.sys
            build/**/mkbtrfs.exe
            build/**/shellbtrfs.dll
            build/**/ubtrfs.dll
            build/**/*.inf
            build/**/*.cat
            build/pdb


================================================
FILE: .gitmodules
================================================
[submodule "src/zstd"]
	path = src/zstd
	url = https://github.com/facebook/zstd
[submodule "src/zlib"]
	path = src/zlib
	url = https://github.com/madler/zlib


================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.15)

project(btrfs VERSION 1.9.0)

option(WITH_TEST "Compile test program" ON)

if(MSVC) # cmake bug 15170
    if(MSVC_C_ARCHITECTURE_ID STREQUAL "X86")
        set(CMAKE_SYSTEM_PROCESSOR "x86")
    elseif(MSVC_C_ARCHITECTURE_ID STREQUAL "x64")
        set(CMAKE_SYSTEM_PROCESSOR "x86_64")
    elseif(MSVC_C_ARCHITECTURE_ID STREQUAL "ARMV7")
        set(CMAKE_SYSTEM_PROCESSOR "arm")
    elseif(MSVC_C_ARCHITECTURE_ID STREQUAL "ARM64")
        set(CMAKE_SYSTEM_PROCESSOR "aarch64")
    endif()
endif()

# zstd

set(ZSTD_SRC_FILES src/zstd/lib/common/entropy_common.c
    src/zstd/lib/common/error_private.c
    src/zstd/lib/compress/fse_compress.c
    src/zstd/lib/common/fse_decompress.c
    src/zstd/lib/compress/hist.c
    src/zstd/lib/compress/huf_compress.c
    src/zstd/lib/decompress/huf_decompress.c
    src/zstd/lib/common/zstd_common.c
    src/zstd/lib/compress/zstd_compress.c
    src/zstd/lib/compress/zstd_compress_literals.c
    src/zstd/lib/compress/zstd_compress_sequences.c
    src/zstd/lib/compress/zstd_compress_superblock.c
    src/zstd/lib/decompress/zstd_ddict.c
    src/zstd/lib/decompress/zstd_decompress.c
    src/zstd/lib/decompress/zstd_decompress_block.c
    src/zstd/lib/compress/zstd_double_fast.c
    src/zstd/lib/compress/zstd_fast.c
    src/zstd/lib/compress/zstd_lazy.c
    src/zstd/lib/compress/zstd_ldm.c
    src/zstd/lib/compress/zstd_opt.c
    src/zstd/lib/common/xxhash.c)

add_library(zstd STATIC ${ZSTD_SRC_FILES})
target_compile_definitions(zstd PRIVATE -DZSTD_DEPS_MALLOC -DXXH_NO_STDLIB)

if(NOT MSVC)
    target_compile_options(zstd PRIVATE -ffunction-sections -include ${CMAKE_SOURCE_DIR}/src/zstd-shim.h)
else()
    target_compile_options(zstd PRIVATE /Gy /FI ${CMAKE_SOURCE_DIR}/src/zstd-shim.h)
    set_property(TARGET zstd PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()

if(MSVC AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
    target_compile_options(zstd PUBLIC /Gz) # stdcall
endif()

# zlib

set(ZLIB_SRC_FILES src/zlib/adler32.c
    src/zlib/deflate.c
    src/zlib/inffast.c
    src/zlib/inflate.c
    src/zlib/inftrees.c
    src/zlib/trees.c
    src/zlib/zutil.c)

add_library(zlib STATIC ${ZLIB_SRC_FILES})
target_compile_definitions(zlib PRIVATE -DNO_GZIP -DZ_SOLO)

if(NOT MSVC)
    target_compile_options(zlib PRIVATE -ffunction-sections)
else()
    target_compile_options(zlib PRIVATE /Gy)
endif()

if(MSVC AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
    target_compile_options(zlib PUBLIC /Gz) # stdcall
endif()

# btrfs.sys

set(SRC_FILES src/balance.c
    src/blake2b-ref.c
    src/boot.c
    src/btrfs.c
    src/cache.c
    src/calcthread.c
    src/compress.c
    src/crc32c.c
    src/create.c
    src/devctrl.c
    src/dirctrl.c
    src/extent-tree.c
    src/fastio.c
    src/fileinfo.c
    src/flushthread.c
    src/free-space.c
    src/fsctl.c
    src/fsrtl.c
    src/galois.c
    src/pnp.c
    src/read.c
    src/registry.c
    src/reparse.c
    src/scrub.c
    src/search.c
    src/security.c
    src/send.c
    src/sha256.c
    src/treefuncs.c
    src/volume.c
    src/worker-thread.c
    src/write.c
    ${CMAKE_CURRENT_BINARY_DIR}/btrfs.rc)

# Work around bug in MSVC version of cmake - see https://gitlab.kitware.com/cmake/cmake/-/merge_requests/4257
set(CMAKE_ASM_MASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         "")
set(CMAKE_ASM_MASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      "")
set(CMAKE_ASM_MASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    "")
set(CMAKE_ASM_MASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "")

set(CMAKE_ASM_MASM_FLAGS "/Zd")

if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
    if(MSVC)
        enable_language(ASM_MASM)
        set(SRC_FILES ${SRC_FILES}
            src/crc32c-masm.asm
            src/xor-masm.asm)
    else()
        enable_language(ASM)
        set(SRC_FILES ${SRC_FILES}
            src/crc32c-gas.S
            src/xor-gas.S)
    endif()
endif()

if(MSVC AND (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64"))
    # see cmake bug 24317 if armasm64 fails (should be fixed in CMake 3.29)
    enable_language(ASM_MARMASM)
    set(SRC_FILES ${SRC_FILES}
        src/crc32c-aarch64.asm)
endif()

configure_file(src/btrfs.rc.in btrfs.rc)

if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
    add_definitions(-D_AMD64_)
    set(MS_ARCH "x64")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
    add_definitions(-D_X86_)
    set(MS_ARCH "x86")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm")
    add_definitions(-D_ARM_)
    set(MS_ARCH "arm")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
    add_definitions(-D_ARM64_)
    set(MS_ARCH "arm64")
endif()

if(MSVC)
    include_directories("$ENV{WindowsSdkDir}Include\\$ENV{WindowsSDKLibVersion}km")
    link_directories("$ENV{WindowsSdkDir}Lib\\$ENV{WindowsSDKLibVersion}km\\${MS_ARCH}")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND WIN32)
    include_directories("${CMAKE_FIND_ROOT_PATH}/usr/include/ddk")
endif()

add_library(btrfs SHARED ${SRC_FILES})
target_link_libraries(btrfs zstd zlib)

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    add_definitions(-D_DEBUG)
endif()

if(NOT MSVC)
    target_compile_options(btrfs PUBLIC -U__NO_INLINE__)
    add_definitions(-D__USE_MINGW_ANSI_STDIO=0)
endif()

target_compile_definitions(btrfs PUBLIC _KERNEL_MODE WIN9X_COMPAT_SPINLOCK)

if(MSVC)
    if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
        target_compile_options(btrfs PUBLIC /Gz) # stdcall
    endif()

    target_link_libraries(btrfs ntoskrnl hal)

    if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
        target_link_libraries(btrfs bufferoverflowfastfailk)
    else()
        target_link_libraries(btrfs BufferOverflowK)
    endif()

    if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm")
        target_link_libraries(btrfs armrt)
    elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
        target_link_libraries(btrfs arm64rt)
    endif()

    target_link_libraries(btrfs rtlver)
    target_link_options(btrfs PUBLIC /SUBSYSTEM:NATIVE /NODEFAULTLIB /MANIFEST:NO /Driver /ENTRY:DriverEntry)

    # strip out flags for MSVC's runtime checks
    string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
    string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
else()
    target_compile_options(btrfs PUBLIC -Wall -Werror-implicit-function-declaration -Werror=incompatible-pointer-types -Wno-expansion-to-defined -Wunused-parameter -Wtype-limits -Wextra)

    if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
        target_compile_options(btrfs PUBLIC -Werror=cast-function-type -Wold-style-declaration)
    elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
        target_compile_options(btrfs PUBLIC -Wno-pragma-pack) # ignore warning in mingw headers
    endif()

    target_link_libraries(btrfs ntoskrnl hal gcc)
    target_link_options(btrfs PUBLIC -nostdlib -Wl,--subsystem,native -Wl,--file-alignment,0x1000 -Wl,--section-alignment,0x1000 -Wl,--exclude-all-symbols)

    if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
        target_link_options(btrfs PUBLIC -Wl,--entry,_DriverEntry@8)
    else()
        target_link_options(btrfs PUBLIC -Wl,--entry,DriverEntry)
    endif()
endif()

set_target_properties(btrfs PROPERTIES PREFIX "")
set_target_properties(btrfs PROPERTIES SUFFIX ".sys")

# --------------------------------------

# shellbtrfs.dll

set(SHELLEXT_SRC_FILES src/shellext/balance.cpp
    src/shellext/contextmenu.cpp
    src/shellext/devices.cpp
    src/shellext/factory.cpp
    src/shellext/iconoverlay.cpp
    src/shellext/main.cpp
    src/shellext/mappings.cpp
    src/shellext/mountmgr.cpp
    src/shellext/propsheet.cpp
    src/shellext/recv.cpp
    src/shellext/scrub.cpp
    src/shellext/send.cpp
    src/shellext/volpropsheet.cpp
    src/crc32c.c
    src/shellext/shellbtrfs.def
    ${CMAKE_CURRENT_BINARY_DIR}/shellbtrfs.rc)

if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
    if(MSVC)
        enable_language(ASM_MASM)
        set(SHELLEXT_SRC_FILES ${SHELLEXT_SRC_FILES} src/crc32c-masm.asm)
    else()
        enable_language(ASM)
        set(SHELLEXT_SRC_FILES ${SHELLEXT_SRC_FILES} src/crc32c-gas.S)
    endif()
endif()

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)

configure_file(src/shellext/shellbtrfs.rc.in shellbtrfs.rc)

add_library(shellbtrfs SHARED ${SHELLEXT_SRC_FILES})

if(NOT MSVC)
    target_link_options(shellbtrfs PUBLIC -static -static-libgcc)
    target_link_libraries(shellbtrfs pthread)

    target_compile_options(shellbtrfs PUBLIC -Wall -Wno-expansion-to-defined -Wunused-parameter -Wtype-limits -Wextra)
else()
    target_compile_options(shellbtrfs PUBLIC /EHsc)
    target_link_options(shellbtrfs PUBLIC /MANIFEST:NO)
endif()

target_link_libraries(shellbtrfs comctl32 ntdll setupapi uxtheme shlwapi windowscodecs gdi32 advapi32 shell32 ole32)

if(MSVC AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
    target_compile_options(shellbtrfs PUBLIC /Gz) # stdcall
endif()

set_target_properties(shellbtrfs PROPERTIES PREFIX "")

if(MSVC)
    set_property(TARGET shellbtrfs PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()

# --------------------------------------

# ubtrfs.dll

set(UBTRFS_SRC_FILES src/ubtrfs/ubtrfs.c
    src/crc32c.c
    src/sha256.c
    src/blake2b-ref.c
    src/ubtrfs/ubtrfs.def
    ${CMAKE_CURRENT_BINARY_DIR}/ubtrfs.rc)

if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
    if(MSVC)
        enable_language(ASM_MASM)
        set(UBTRFS_SRC_FILES ${UBTRFS_SRC_FILES} src/crc32c-masm.asm)
    else()
        enable_language(ASM)
        set(UBTRFS_SRC_FILES ${UBTRFS_SRC_FILES} src/crc32c-gas.S)
    endif()
endif()

configure_file(src/ubtrfs/ubtrfs.rc.in ubtrfs.rc)

add_library(ubtrfs SHARED ${UBTRFS_SRC_FILES})

if(MSVC)
    set_property(TARGET ubtrfs PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()

target_compile_definitions(ubtrfs PUBLIC _USRDLL)
target_link_libraries(ubtrfs ntdll advapi32)
target_link_libraries(ubtrfs zstd)

if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
    target_compile_options(ubtrfs PUBLIC -Wno-pragma-pack) # ignore warning in mingw headers
endif()

if(MSVC AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
    target_compile_options(ubtrfs PUBLIC /Gz) # stdcall
endif()

if(NOT MSVC)
    target_compile_options(ubtrfs PUBLIC -Werror-implicit-function-declaration)
    target_link_options(ubtrfs PUBLIC -static -static-libgcc -static-libstdc++)
endif()

set_target_properties(ubtrfs PROPERTIES PREFIX "")

# --------------------------------------

# mkbtrfs.exe

set(MKBTRFS_SRC_FILES src/mkbtrfs/mkbtrfs.c
    ${CMAKE_CURRENT_BINARY_DIR}/mkbtrfs.rc)

configure_file(src/mkbtrfs/mkbtrfs.rc.in mkbtrfs.rc)

add_executable(mkbtrfs ${MKBTRFS_SRC_FILES})

if(MSVC)
    set_property(TARGET mkbtrfs PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
else()
    target_link_options(mkbtrfs PUBLIC -static -static-libgcc)
endif()

# --------------------------------------

# test.exe

if(WITH_TEST)
    set(CMAKE_CXX_STANDARD 20)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)

    configure_file(src/tests/test.rc.in test.rc)

    set(TEST_SRC_FILES src/tests/test.cpp
        ${CMAKE_CURRENT_BINARY_DIR}/test.rc
        src/tests/create.cpp
        src/tests/supersede.cpp
        src/tests/overwrite.cpp
        src/tests/io.cpp
        src/tests/mmap.cpp
        src/tests/rename.cpp
        src/tests/delete.cpp
        src/tests/links.cpp
        src/tests/oplock.cpp
        src/tests/cs.cpp
        src/tests/reparse.cpp
        src/tests/streams.cpp
        src/tests/ea.cpp
        src/tests/fileinfo.cpp
        src/tests/security.cpp)

    add_executable(test ${TEST_SRC_FILES})

    if(MSVC)
        set_property(TARGET test PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
    else()
        target_link_options(test PUBLIC -static -static-libgcc -municode)
        target_compile_options(test PUBLIC -Wall -Wno-expansion-to-defined -Wunused-parameter -Wtype-limits -Wextra)
    endif()

    target_link_libraries(test ntdll version advapi32)
endif()

# --------------------------------------

# install

install(TARGETS btrfs DESTINATION bin)
install(TARGETS shellbtrfs DESTINATION bin)
install(TARGETS ubtrfs DESTINATION bin)
install(TARGETS mkbtrfs DESTINATION bin)


================================================
FILE: CMakeSettings.json
================================================
{
  "configurations": [
    {
      "name": "x64-Debug",
      "generator": "Ninja",
      "configurationType": "Debug",
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "inheritEnvironments": [ "msvc_x64_x64" ],
      "variables": []
    },
    {
      "name": "x86-Debug",
      "generator": "Ninja",
      "configurationType": "Debug",
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "inheritEnvironments": [ "msvc_x86_x64" ],
      "variables": []
    },
    {
      "name": "arm-Debug",
      "generator": "Ninja",
      "configurationType": "Debug",
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "inheritEnvironments": [ "msvc_arm_x64" ],
      "variables": []
    },
    {
      "name": "arm64-Debug",
      "generator": "Ninja",
      "configurationType": "Debug",
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "inheritEnvironments": [ "msvc_arm64_x64" ],
      "variables": []
    },
    {
      "name": "x64-Release",
      "generator": "Ninja",
      "configurationType": "RelWithDebInfo",
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "inheritEnvironments": [ "msvc_x64_x64" ],
      "variables": []
    },
    {
      "name": "x86-Release",
      "generator": "Ninja",
      "configurationType": "RelWithDebInfo",
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "inheritEnvironments": [ "msvc_x86_x64" ],
      "variables": []
    },
    {
      "name": "arm-Release",
      "generator": "Ninja",
      "configurationType": "RelWithDebInfo",
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "inheritEnvironments": [ "msvc_arm_x64" ],
      "variables": []
    },
    {
      "name": "arm64-Release",
      "generator": "Ninja",
      "configurationType": "RelWithDebInfo",
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "inheritEnvironments": [ "msvc_arm64_x64" ],
      "variables": []
    }
  ]
}


================================================
FILE: LICENCE
================================================
                   GNU LESSER GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.


  This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.

  0. Additional Definitions.

  As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.

  "The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.

  An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.

  A "Combined Work" is a work produced by combining or linking an
Application with the Library.  The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".

  The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.

  The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.

  1. Exception to Section 3 of the GNU GPL.

  You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.

  2. Conveying Modified Versions.

  If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:

   a) under this License, provided that you make a good faith effort to
   ensure that, in the event an Application does not supply the
   function or data, the facility still operates, and performs
   whatever part of its purpose remains meaningful, or

   b) under the GNU GPL, with none of the additional permissions of
   this License applicable to that copy.

  3. Object Code Incorporating Material from Library Header Files.

  The object code form of an Application may incorporate material from
a header file that is part of the Library.  You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:

   a) Give prominent notice with each copy of the object code that the
   Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the object code with a copy of the GNU GPL and this license
   document.

  4. Combined Works.

  You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:

   a) Give prominent notice with each copy of the Combined Work that
   the Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the Combined Work with a copy of the GNU GPL and this license
   document.

   c) For a Combined Work that displays copyright notices during
   execution, include the copyright notice for the Library among
   these notices, as well as a reference directing the user to the
   copies of the GNU GPL and this license document.

   d) Do one of the following:

       0) Convey the Minimal Corresponding Source under the terms of this
       License, and the Corresponding Application Code in a form
       suitable for, and under terms that permit, the user to
       recombine or relink the Application with a modified version of
       the Linked Version to produce a modified Combined Work, in the
       manner specified by section 6 of the GNU GPL for conveying
       Corresponding Source.

       1) Use a suitable shared library mechanism for linking with the
       Library.  A suitable mechanism is one that (a) uses at run time
       a copy of the Library already present on the user's computer
       system, and (b) will operate properly with a modified version
       of the Library that is interface-compatible with the Linked
       Version.

   e) Provide Installation Information, but only if you would otherwise
   be required to provide such information under section 6 of the
   GNU GPL, and only to the extent that such information is
   necessary to install and execute a modified version of the
   Combined Work produced by recombining or relinking the
   Application with a modified version of the Linked Version. (If
   you use option 4d0, the Installation Information must accompany
   the Minimal Corresponding Source and Corresponding Application
   Code. If you use option 4d1, you must provide the Installation
   Information in the manner specified by section 6 of the GNU GPL
   for conveying Corresponding Source.)

  5. Combined Libraries.

  You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:

   a) Accompany the combined library with a copy of the same work based
   on the Library, uncombined with any other library facilities,
   conveyed under the terms of this License.

   b) Give prominent notice with the combined library that part of it
   is a work based on the Library, and explaining where to find the
   accompanying uncombined form of the same work.

  6. Revised Versions of the GNU Lesser General Public License.

  The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.

  Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.

  If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.


================================================
FILE: README.md
================================================
WinBtrfs v1.9
-------------

WinBtrfs is a Windows driver for the next-generation Linux filesystem Btrfs.
A reimplementation from scratch, it contains no code from the Linux kernel,
and should work on any version from Windows XP onwards. It is also included
as part of the free operating system [ReactOS](https://www.reactos.org/).

If your Btrfs filesystem is on a MD software RAID device created by Linux, you
will also need [WinMD](https://github.com/maharmstone/winmd) to get this to appear
under Windows.

See also [Quibble](https://github.com/maharmstone/quibble), an experimental
bootloader allowing Windows to boot from Btrfs, and [Ntfs2btrfs](https://github.com/maharmstone/ntfs2btrfs),
a tool which allows in-place conversion of NTFS filesystems.

First, a disclaimer:

You use this software at your own risk. I take no responsibility for any damage
it may do to your filesystem. It ought to be suitable for day-to-day use, but
make sure you take backups anyway.

Everything here is released under the GNU Lesser General Public Licence (LGPL);
see the file LICENCE for more info. You are encouraged to play about with the
source code as you will, and I'd appreciate a note (mark@harmstone.com) if you
come up with anything nifty.

See at the end of this document for copyright details of third-party code that's
included here.

Features
--------

* Reading and writing of Btrfs filesystems
* Basic RAID: RAID0, RAID1, and RAID10
* Advanced RAID: RAID5 and RAID6
* Caching
* Discovery of Btrfs partitions, even if Windows would normally ignore them
* Getting and setting of Access Control Lists (ACLs), using the xattr
  security.NTACL
* Alternate Data Streams (e.g. :Zone.Identifier is stored as the xattr
  user.Zone.Identifier)
* Mappings from Linux users to Windows ones (see below)
* Symlinks and other reparse points
* Shell extension to identify and create subvolumes, including snapshots
* Hard links
* Sparse files
* Free-space cache
* Preallocation
* Asynchronous reading and writing
* Partition-less Btrfs volumes
* Per-volume registry mount options (see below)
* zlib compression
* LZO compression
* LXSS ("Ubuntu on Windows") support
* Balancing (including resuming balances started on Linux)
* Device addition and removal
* Creation of new filesystems with `mkbtrfs.exe` and `ubtrfs.dll`
* Scrubbing
* TRIM/DISCARD
* Reflink copy
* Subvol send and receive
* Degraded mounts
* Free space tree (compat_ro flag `free_space_cache`)
* Shrinking and expanding
* Passthrough of permissions etc. for LXSS
* Zstd compression
* Windows 10 case-sensitive directory flag
* Oplocks
* Metadata UUID incompat flag (Linux 5.0)
* Three- and four-disk RAID1 (Linux 5.5)
* New checksum types (xxhash, sha256, blake2) (Linux 5.5)
* Block group tree (Linux 6.1)

Todo
----

* Full fs-verity support (Linux 5.15)
* Zoned support (Linux 5.11) (HM-SMR not supported on Windows?)
* Defragmentation
* Support for Btrfs quotas
* Full transaction log support
* Support for Windows transactions (TxF)

Installation
------------

To install the driver, [download and extract the latest release](https://github.com/maharmstone/btrfs/releases),
right-click btrfs.inf, and choose Install. The driver is signed, so should work out
of the box on modern versions of Windows.

If you using Windows 10 or 11 and have Secure Boot enabled, you may have to make a Registry
change in order for the driver to be loaded - see [below](#secureboot). It's easier though
just to turn off Secure Boot in your BIOS, unless you have a particular need for it. Bear in
mind that Windows 11 soft-requires Secure Boot to be installed, but will work fine afterwords
with it turned off.

WinBtrfs is also available on the following package managers:

* [Chocolatey](https://chocolatey.org/packages/winbtrfs)
```
choco install winbtrfs
```
* [Scoop](https://scoop.sh/#/apps?q=%22winbtrfs-np%22&s=0&d=1&o=true)
```
scoop bucket add nonportable
scoop install winbtrfs-np -g
```

Uninstalling
------------

If you want to uninstall, from a command prompt run:

```
RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection DefaultUninstall 132 btrfs.inf
```

You may need to give the full path to btrfs.inf.

You can also go to Device Manager, find "Btrfs controller" under
"Storage volumes", right click and choose "Uninstall". Tick the checkbox to
uninstall the driver as well, and let Windows reboot itself.

If you need to uninstall via the registry, open regedit and set the value of
HKLM\SYSTEM\CurrentControlSet\services\btrfs\Start to 4, to disable the service.
After you reboot, you can then delete the btrfs key and remove
C:\Windows\System32\drivers\btrfs.sys.

Compilation
-----------

To compile with Visual C++ 2019, open the directory and let CMake do its thing.
If you have the Windows DDK installed correctly, it should just work.

To compile with GCC on Linux, you will need a cross-compiler set up, for either
`i686-w64-mingw32` or `x86_64-w64-mingw32`. Create a build directory, then use
either `mingw-x86.cmake` or `mingw-amd64.cmake` as CMake toolchain files to
generate your Makefile.

Mappings
--------

The user mappings are stored in the registry key
HKLM\SYSTEM\CurrentControlSet\services\btrfs\Mappings. Create a DWORD with the
name of your Windows SID (e.g. S-1-5-21-1379886684-2432464051-424789967-1001),
and the value of your Linux uid (e.g. 1000). It will take effect next time the
driver is loaded.

You can find your current SID by running `wmic useraccount get name,sid`.

Similarly, the group mappings are stored in under GroupMappings. The default
entry maps Windows' Users group to gid 100, which is usually "users" on Linux.
You can also specify user SIDs here to force files created by a user to belong
to a certain group. The setgid flag also works as on Linux.

Note that processes running under User Access Control tokens create files as
the BUILTIN\Administrators SID (S-1-5-32-544), rather as a user account.

LXSS ("Ubuntu on Windows" / "Windows Subsystem for Linux")
----------------------------------------------------------

The driver will passthrough Linux metadata to recent versions of LXSS, but you
will have to let Windows know that you wish to do this. From a Bash prompt on
Windows, edit `/etc/wsl.conf` to look like the following:

```
[automount]
enabled = true
options = "metadata"
mountFsTab = false
```

It will then take effect next time you reboot. Yes, you should be able to chroot
into an actual Linux installation, if you wish.

Commands
--------

The DLL file shellbtrfs.dll provides the GUI interface, but it can also be used
with rundll32.exe to carry out some tasks from the command line, which may be
useful if you wish to schedule something to run periodically.

Bear in mind that rundll32 provides no mechanism to return any error codes, so
any of these commands may fail silently.

* `rundll32.exe shellbtrfs.dll,CreateSubvol <path>`

* `rundll32.exe shellbtrfs.dll,CreateSnapshot <source> <destination>`

* `rundll32.exe shellbtrfs.dll,ReflinkCopy <source> <destination>`
This also accepts wildcards, and any number of source files.

The following commands need various privileges, and so must be run as Administrator
to work:

* `rundll32.exe shellbtrfs.dll,SendSubvol <source> [-p <parent>] [-c <clone subvol>] <stream file>`
The -p and -c flags are as `btrfs send` on Linux. You can specify any number of
clone subvolumes.

* `rundll32.exe shellbtrfs.dll,RecvSubvol <stream file> <destination>`

* `rundll32.exe shellbtrfs.dll,StartScrub <drive>`

* `rundll32.exe shellbtrfs.dll,StopScrub <drive>`

Troubleshooting
---------------

* How do I debug this?

On the releases page, there's zip files to download containing the PDBs. Or you
can try the symbols server http://symbols.burntcomma.com/ - in windbg, set your
symbol path to something like this:

```symsrv*symsrv.dll*C:\symbols*http://msdl.microsoft.com/download/symbols;symsrv*symsrv.dll*C:\symbols*http://symbols.burntcomma.com```

* The filenames are weird!
or
* I get strange errors on certain files or directories!

The driver assumes that all filenames are encoded in UTF-8. This should be the
default on most setups nowadays - if you're not using UTF-8, it's probably worth
looking into converting your files.

* <a name="secureboot"></a>How do I get this working with Secure Boot turned on?

For the later versions of Windows 10, Microsoft introduced more onerous
requirements for signing, which seemingly aren't available for open-source drivers.

To work around this, go to `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CI\Policy` in Regedit,
create a new DWORD value called `UpgradedSystem` and set to 1, and reboot.

Or you could always just turn off Secure Boot in your BIOS settings.

* The root of the drive isn't case-sensitive in LXSS

This is something Microsoft hardcoded into LXSS, presumably to stop people hosing
their systems by running `mkdir /mnt/c/WiNdOwS`.

* How do I change the drive letter?

With the shell extension installed, right-click the drive in Explorer, click Properties,
and go to the Btrfs tab. There should be a button which allows you to change the drive
letter.

* I'm still having problems with drive letters

In Regedit, try deleting the relevant entries in `HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices`,
then rebooting.

* How do I format a partition as Btrfs?

Use the included command line program mkbtrfs.exe. We can't add Btrfs to Windows' own
dialog box, unfortunately, as its list of filesystems has been hardcoded. You can also
run `format /fs:btrfs`, if you don't need to set any Btrfs-specific options.

* I can't reformat a mounted Btrfs filesystem

If Windows' Format dialog box refuses to appear, try running format.com with the /fs
flag, e.g. `format /fs:ntfs D:`.

* I can't mount a Synology NAS

Synology seems to use LVM for its block devices. Until somebody writes an LVM driver
for Windows, you're out of luck.

* I can't mount a Thecus NAS

Thecus uses Linux's MD raid for its block devices. You will need to install [WinMD](https://github.com/maharmstone/winmd)
as well.

* 64-bit Windows 7 won't load the driver

Make sure that you have [KB3033929](https://www.microsoft.com/en-gb/download/details.aspx?id=46148) installed.
Or consider installing from an "escrow" ISO which includes all updates.

* The drive doesn't show up and Paragon software has been installed

Paragon's filesystem-reading software is known to disable automount. Disable or
uninstall Paragon, then re-enable automount by running `diskpart` and typing
`automount enable`.

* The drive doesn't show up on very old versions of Windows

On very old versions of Windows (XP, Server 2003?), Windows ignores Linux partitions
entirely. If this is the case for you, try running `fdisk` on Linux and changing your
partition type from 83 to 7.

* I can edit files on Windows that I shouldn't be able to

There's no mapping between Windows and POSIX permission models, they're too
different for this to be practical. If this bothers you, you can create a
Windows ACL on files that you don't want to be able to edit.

Changelog
---------

v1.9 (2024-03-15):
* Added support for block group tree (Linux 6.1)
* Fixed hang when system under heavy load
* Added /blockgrouptree and /freespacetree options to mkbtrfs
* Follow Linux in defaulting /noholes to on in mkbtrfs
* Added support for CRC32C instructions on aarch64

v1.8.2 (2023-01-10):
* Fixed UAC not working
* Fixed Smartlocker crash on Windows 11 22H2
* Rejigged INF file to work better on Windows 11
* Files now signed with SHA256 hash rather than SHA1

v1.8.1 (2022-08-23):
* Fixed use-after-free when flushing
* Fixed crash when opening volume when AppLocker installed
* Compression now disabled for no-COW files, as on Linux
* Flushing now scales better on very fast drives
* Fixed small files getting padded to 4,096 bytes by lazy writer
* Added NoDataCOW registry option

v1.8 (2022-03-12):
* Added minimal support for fs-verity
* Added test suite
* Fixed incorrect disk usage statistics
* Fixed potential crashes when renaming stream to file or file to stream
* Fixed potential crashes when querying hard links on file
* Fixed potential hang when opening oplocked file
* Fixed minor issues also uncovered by test suite

v1.7.9 (2021-10-02):
* Fixed deadlock when mounting on Windows 11
* Added support for BitLocker-encrypted volumes
* Improved filename checks when renaming or creating hard links
* Miscellaneous bug fixes

v1.7.8.1 (2021-06-13):
* Fixed bug preventing new directories from appearing in listings
* Fixed Release version of driver still not working on XP

v1.7.8 (2021-06-09):
* Upgraded zstd to version 1.5.0
* Fixed regression stopping driver from working under XP
* Fixed compilation on clang
* Fixed corruption issue when Linux mount option `inode_cache` had been used
* Fixed recursion issue involving virtual directory \\$Root

v1.7.7 (2021-04-12):
* Fixed deadlock on high load
* Fixed free space issue when installing Genshin Impact
* Fixed issue when copying files with wildcards in command prompt
* Increased speed of directory lookups

v1.7.6 (2021-01-14):
* Fixed race condition when booting with Quibble
* No longer need to restart Windows after initial installation
* Forced maximum file name to 255 UTF-8 characters, to match Linux driver
* Fixed issue where directories could be created with trailing backslash
* Fixed potential deadlock when Windows calls NtCreateSection during flush
* Miscellaneous bug fixes

v1.7.5 (2020-10-31):
* Fixed text display issue in shell extension
* Added support for mingw 8
* Fixed LXSS permissions not working in new versions of Windows
* Fixed issue where truncating an inline file wouldn't change its size
* Fixed crash with Quibble where driver would try to use AVX2 before Windows had enabled it

v1.7.4 (2020-08-23):
* Fixed issue when running compressed EXEs
* Changed build system to cmake
* Upgraded zstd to version 1.4.5
* Added support for FSCTL_GET_RETRIEVAL_POINTERS
* Miscellaneous bug fixes

v1.7.3 (2020-05-24):
* Fixed crash when sending file change notifications
* Improved symlink handling with LXSS
* Added support for undocumented flag SL_IGNORE_READONLY_ATTRIBUTE
* Fixed corruption caused by edge case, where address allocated and freed in same flush
* Improved handling of free space tree
* Improved handling of very full volumes
* Fixed spurious warnings raised by GCC 10 static analyser
* Replaced multiplications and divisions with bit shift operations where appropriate
* Fixed combobox stylings in shell extension

v1.7.2 (2020-04-10):
* Added more fixes for booting from Btrfs on Windows 10
* Fixed occasional deadlock when deleting or closing files on Windows 10 1909
* Fixed crash when reading large ADSes
* Fixed occasional crash when writing files on RAID5/6
* Miscellaneous bug fixes

v1.7.1 (2020-03-02):
* Fixed crash when reading beyond end of file
* Fixed spurious checksum errors when doing unaligned read

v1.7 (2020-02-26):
* Added support for metadata_uuid incompat flag (Linux 5.0)
* Added support for three- and four-disk RAID1 (Linux 5.5)
* Added support for new checksum types: xxhash, sha256, blake2 (Linux 5.5)
* Greatly increased checksumming speed
* Greatly increased compression and decompression speed
* Fixed bug causing incorrect free-space reporting when data is DUP
* Fixed issue creating directories on LXSS when `case=dir` option set

v1.6 (2020-02-04):
* Added experimental (i.e. untested) ARM support (thanks to [DjArt](https://github.com/DjArt) for this)
* Added fixes for booting from Btrfs on Windows 10
* Volumes will now get remounted if changed while Windows is asleep or hibernating
* Fixed corruption when mounting volume that hasn't been unmounted cleanly by Linux
* Fixed crash when deleting subvolume

v1.5 (2019-11-10):
* More fixes for booting from Btrfs
* Added virtual $Root directory (see "NoRootDir" below)
* Added support for Windows XP
* Added support for renaming alternative data streams
* Added oplock support
* Fixed potential deadlock on boot
* Fixed possible crash on shutdown
* Fixed a bunch of memory leaks
* Many other miscellaneous bug fixes

v1.4 (2019-08-31):
* Added fragmentation percentage to property sheet
* Added support for Windows Server 2003 and Windows Vista
* Added pagefile support
* Improved support for file locking
* Added support for booting from Btrfs on Windows Server 2003 (see https://www.youtube.com/watch?v=-5E2CHmHEUs)
* Fixed issue where driver could open same inode twice
* Other miscellaneous bug fixes

v1.3 (2019-06-10):
* Added support for new rename and delete functions introduced to Windows 10
* Added support for Windows 10's flag for case-sensitive directories
* Changed free-space calculation method to be more like that of the Linux driver
* Added more support for 128-bit file IDs
* Fixed bug causing outdated root items
* Fixed bug preventing writing to VHDs

v1.2.1 (2019-05-06):
* Reverted commit affecting the creation of streams

v1.2 (2019-05-05):
* Dramatic speed increase when opening many small files, such as with a Git repository
* Fixed crash on surprise removals of removable devices
* Added ability to change drive letters easily
* No longer creates free-space cache for very small chunks, so as not to confuse the Linux driver
* Fixed corruption when very large file created and then immediately deleted
* Minor bug fixes

v1.1 (2018-12-15):
* Support for Zstd compression
* Passthrough of Linux metadata to LXSS
* Refactored shell extension
* Fixed memory leaks
* Many other bug fixes

v1.0.2 (2018-05-19):
* Minor bug fixes

v1.0.1 (2017-10-15):
* Fixed deadlock
* Binaries now signed
* Minor bug fixes

v1.0 (2017-09-04):
* First non-beta release!
* Degraded mounts
* New free space cache (compat_ro flag `free_space_cache`)
* Shrinking and expanding of volumes
* Registry options now re-read when changed, rather than just on startup
* Improved balancing on very full filesystems
* Fixed problem preventing user profile directory being stored on btrfs on Windows 8 and above
* Better Plug and Play support
* Miscellaneous bug fixes

v0.10 (2017-05-02):
* Reflink copy
* Sending and receiving subvolumes
* Group mappings (see Mappings section above)
* Added commands for scripting etc. (see Commands section above)
* Fixed an issue preventing mounting on non-PNP devices, such as VeraCrypt
* Fixed an issue preventing new versions of LXSS from working
* Fixed problem with the ordering of extent refs, which caused problems on Linux but wasn't picked up by `btrfs check`
* Added support for reading compressed inline extents
* Many miscellaneous bug fixes

v0.9 (2017-03-05):
* Scrubbing
* TRIM/DISCARD
* Better handling of multi-device volumes
* Performance increases when reading from RAID filesystems
* No longer lies about being NTFS, except when it has to
* Volumes will now go readonly if there is an unrecoverable error, rather than blue-screening
* Filesystems can now be created with Windows' inbuilt format.com
* Zlib upgraded to version 1.2.11
* Miscellaneous performance increases
* Miscellaneous bug fixes

v0.8 (2016-12-30):
* Volume property sheet, for:
 * Balances
 * Adding and removing devices
 * Showing disk usage, i.e. the equivalent to `btrfs fi usage`
* Checksums now calculated in parallel where appropriate
* Creation of new filesystems, with mkbtrfs.exe
* Plug and play support for RAID devices
* Disk usage now correctly allocated to processes in taskmgr
* Performance increases
* Miscellaneous bug fixes

v0.7 (2016-10-24):
* Support for RAID5/6 (incompat flag `raid56`)
* Seeding support
* LXSS ("Ubuntu on Windows") support
* Support for Windows Extended Attributes
* Improved removable device support
* Better snapshot support
* Recovery from RAID checksum errors
* Fixed issue where creating a lot of new files was taking a long time
* Miscellaneous speed increases and bug fixes

v0.6 (2016-08-21):
* Compression support (both zlib and lzo)
* Mixed groups support
* No-holes support
* Added inode property sheet to shell extension
* Many more mount options (see below)
* Better support for removable devices
* Page file support
* Many miscellaneous bug fixes

v0.5 (2016-07-24):
* Massive speed increases (from "sluggish" to "blistering")
* Massive stability improvements
* RAID support: RAID0, RAID1, and RAID10
* Asynchronous reading and writing
* Partition-less Btrfs volumes
* Windows sparse file support
* Object ID support
* Beginnings of per-volume mount options
* Security improvements
* Notification improvements
* Miscellaneous bug fixes

v0.4 (2016-05-02):
* Subvolume creation and deletion
* Snapshots
* Preallocation
* Reparse points
* Hard links
* Plug and play
* Free-space cache
* Fix problems preventing volume from being shared over the network
* Miscellaneous bug fixes

v0.3 (2016-03-25):
* Bug fixes:
 * Fixed crashes when metadata blocks were SINGLE, such as on SSDs
 * Fixed crash when splitting an internal tree
 * Fixed tree traversal failing when first item in tree had been deleted
 * Fixed emptying out of whole tree (probably only relevant to checksum tree)
 * Fixed "incorrect local backref count" message appearing in `btrfs check`
 * Miscellaneous other fixes
* Added beginnings of shell extension, which currently only changes the icon of subvolumes

v0.2 (2016-03-13):
* Bug fix release:
 * Check memory allocations succeed
 * Check tree items are the size we're expecting
 * Added rollbacks, so failed operations are completely undone
 * Fixed driver claiming all unrecognized partitions (thanks Pierre Schweitzer)
 * Fixed deadlock within `CcCopyRead`
 * Fixed changing properties of a JPEG within Explorer
 * Lie about FS type, so UAC works
 * Many, many miscellaneous bug fixes
* Rudimentary security support
* Debug log support (see below)

v0.1 (2016-02-21):
* Initial alpha release.

Debug log
---------

WinBtrfs has three levels of debug messages: errors and FIXMEs, warnings, and traces.
The release version of the driver only displays the errors and FIXMEs, which it logs
via `DbgPrint`. You can view these messages via the Microsoft program DebugView, available
at https://technet.microsoft.com/en-gb/sysinternals/debugview.

If you want to report a problem, it'd be of great help if you could also attach a full
debug log. To do this, you will need to use the debug versions of the drivers; copy the files
in Debug\x64 or Debug\x86 into x64 or x86. You will also need to set the registry entries in
HKLM\SYSTEM\CurrentControlSet\Services\btrfs:

* `DebugLogLevel` (DWORD): 0 for no messages, 1 for errors and FIXMEs, 2 for warnings also,
and 3 for absolutely everything, including traces.
* `LogDevice` (string, optional): the serial device you want to output to, such as
`\Device\Serial0`. This is probably only useful on virtual machines.
* `LogFile` (string, optional): the file you wish to output to, if `LogDevice` isn't set.
Bear in mind this is a kernel filename, so you'll have to prefix it with "\\??\\" (e.g.,
"\\??\\C:\\btrfs.log"). It probably goes without saying, but don't store this on a volume the
driver itself is using, or you'll cause an infinite loop.

Mount options
-------------

The driver will create subkeys in the registry under HKLM\SYSTEM\CurrentControlSet\Services\btrfs
for each mounted filesystem, named after its UUID. If you're unsure which UUID refers to which
volume, you can check using `btrfs fi show` on Linux. You can add per-volume mount options to this
subkey, which will take effect on reboot. If a value is set in the key above this, it will use this
by default.

* `Ignore` (DWORD): set this to 1 to tell the driver not to attempt loading this filesystem. With the
`Readonly` flag, this is probably redundant.

* `Readonly` (DWORD): set this to 1 to tell the driver not to allow writing to this volume. This is
the equivalent of the `ro` flag on Linux.

* `Compress` (DWORD): set this to 1 to tell the driver to write files as compressed by default. This is
the equivalent of the `compress` flag on Linux.

* `CompressForce` (DWORD): set this to 1 to force compression, i.e. to ignore the `nocompress` inode
flag and even attempt compression of incompressible files. This isn't a good idea, but is the equivalent
of the `compress-force` flag on Linux.

* `CompressType` (DWORD): set this to 1 to prefer zlib compression, 2 to prefer lzo compression, or 3
to prefer zstd compression. The default is 0, which uses zstd or lzo compression if the incompat flags
are set, and zlib otherwise.

* `FlushInterval` (DWORD): the interval in seconds between metadata flushes. The default is 30, as on Linux -
the parameter is called `commit` there.

* `ZlibLevel` (DWORD): a number between -1 and 9, which determines how much CPU time is spent trying to
compress files. You might want to fiddle with this if you have a fast CPU but a slow disk, or vice versa.
The default is 3, which is the hard-coded value on Linux.

* `MaxInline` (DWORD): the maximum size that will be allowed for "inline" files, i.e. those stored in the
metadata. The default is 2048, which is also the default on modern versions of Linux - the parameter is
called `max_inline` there. It will be clipped to the maximum value, which unless you've changed your node
size will be a shade under 16 KB.

* `SubvolId` (QWORD): the ID of the subvolume that we will attempt to mount as the root. If it doesn't
exist, this parameter will be silently ignored. The subvolume ID can be found on the inode property
sheet; it's in hex there, as opposed to decimal on the Linux tools. The default is whatever has been set
via `btrfs subvolume set-default`; or, failing that, subvolume 5. The equivalent parameter on Linux is
called `subvolid`.

* `SkipBalance` (DWORD): set to 1 to tell the driver not to attempt resuming a balance which was running
when the system last powered down. The default is 0. The equivalent parameter on Linux is `skip_balance`.

* `NoPNP` (DWORD): useful for debugging only, this forces any volumes to appear rather than exposing them
via the usual Plug and Play method.

* `ZstdLevel` (DWORD): Zstd compression level, default 3.

* `NoTrim` (DWORD): set this to 1 to disable TRIM support.

* `AllowDegraded` (DWORD): set this to 1 to allow mounting a degraded volume, i.e. one with a device
missing. You are strongly advised not to enable this unless you need to.

* `NoRootDir` (DWORD): if you have changed your default subvolume, either natively or by a registry option,
there will be a hidden directory called $Root which points to where the root would normally be. Set this
value to 1 to prevent this appearing.

* `NoDataCOW` (DWORD): set this to 1 to disable copy-on-write for new files. This is the equivalent of the
`nodatacow` flag on Linux.

Contact
-------

I'd appreciate any feedback you might have, positive or negative:
mark@harmstone.com.

Copyright
---------

This code contains portions of the following software:

### Zlib

  Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

### LZO

WinBtrfs contains portions of an early version of lzo, which is copyright 1996
Markus Oberhumer. Modern versions are licensed under the GPL, but this was
licensed under the LGPL, so I believe it is okay to use.

### Zstd

Copyright (c) 2016-present, Facebook, Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither the name Facebook nor the names of its contributors may be used to
   endorse or promote products derived from this software without specific
   prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

### BLAKE2

[https://github.com/BLAKE2/BLAKE2](https://github.com/BLAKE2/BLAKE2) (public domain)

### SHA256

[https://github.com/amosnier/sha-2](https://github.com/amosnier/sha-2) (public domain)


================================================
FILE: btrfs-dump.pl
================================================
#!/usr/bin/perl

# Quick and dirty btrfs tree dumper. Great for diff'ing, which btrfs-debug-tree isn't...
# Do something like:
#
# qemu-nbd -r -n -c /dev/nbd0 ~/vms/win7/win7-32.img ; sleep 1 ; chmod 666 /dev/nbd0p3
# ./btrfs-dump.pl /dev/nbd0p3 > dump2.txt
# diff -u dump1.txt dump2.txt > diff2.txt

# Like btrfs.h, I'm disclaiming any copyright on this file, but I'd appreciate
# hearing about what you do with it: mark@harmstone.com.

use Data::Dumper;
use strict;
use integer;

if (scalar(@ARGV) < 1) {
    my @dp = split(/\//, $0);

    print "Usage: " . $dp[$#dp] . " [BLOCKDEVICE]\n";
    exit;
}

my %devs = ();
for (my $i = 1; $i <= $#ARGV; $i++) {
    my ($file, $sb);

    open($file, $ARGV[$i]) || die "Error opening " . $ARGV[$i] . ": $!";
    binmode($file);

    seek($file, 0x10000, 0);
    read($file, $sb, 0x1000);
    my @b = unpack("Vx28a16QQA8QQQQQQQQQVVVVVQQQQvCCCa98a256QQx240a2048a672", $sb);

    if ($b[4] ne "_BHRfS_M") {
        die $ARGV[$i] . ": not Btrfs";
    }

    my @di = unpack("QQQVVVQQQVCCa16a16", $b[27]);
    $devs{$di[0]} = $file;
}

my ($f, $chunktree, $roottree, $logtree, $nodesize, $blocksize);

open($f, $ARGV[0]) || die "Error opening " . $ARGV[0] . ": $!";
binmode($f);

my %roots = ();
my %logroots = ();
my @l2p = ();
my @l2p_bs = ();
my $csum_type;

read_superblock($f);

print "CHUNK:\n";
dump_tree($chunktree, "", 1);
print "\n";

print "ROOT:\n";
dump_tree($roottree, "", 0);
print "\n";

if ($logtree != 0) {
    print "LOG:\n";
    dump_tree($logtree, "", 0);
    print "\n";
}

my @rs = sort { $a <=> $b } (keys(%roots));

foreach my $r (@rs) {
    printf("Tree %x:\n", $r);
    dump_tree($roots{$r}, "");
    print "\n";
}

my @lrs = sort { $a <=> $b } (keys(%logroots));

foreach my $lr (@lrs) {
    printf("Tree %x (log):\n", $lr);
    dump_tree($logroots{$lr}, "");
    print "\n";
}

close($f);

sub incompat_flags {
    my ($f) = @_;
    my @l;

    if ($f & 0x1) {
        push @l, "mixed_backref";
        $f &= ~0x1;
    }

    if ($f & 0x2) {
        push @l, "default_subvol";
        $f &= ~0x2;
    }

    if ($f & 0x4) {
        push @l, "mixed_groups";
        $f &= ~0x4;
    }

    if ($f & 0x8) {
        push @l, "compress_lzo";
        $f &= ~0x8;
    }

    if ($f & 0x10) {
        push @l, "compress_zstd";
        $f &= ~0x10;
    }

    if ($f & 0x20) {
        push @l, "big_metadata";
        $f &= ~0x20;
    }

    if ($f & 0x40) {
        push @l, "extended_iref";
        $f &= ~0x40;
    }

    if ($f & 0x80) {
        push @l, "raid56";
        $f &= ~0x80;
    }

    if ($f & 0x100) {
        push @l, "skinny_metadata";
        $f &= ~0x100;
    }

    if ($f & 0x200) {
        push @l, "no_holes";
        $f &= ~0x200;
    }

    if ($f & 0x400) {
        push @l, "metadata_uuid";
        $f &= ~0x400;
    }

    if ($f & 0x800) {
        push @l, "raid1c34";
        $f &= ~0x800;
    }

    if ($f & 0x1000) {
        push @l, "zoned";
        $f &= ~0x1000;
    }

    if ($f & 0x2000) {
        push @l, "extent_tree_v2";
        $f &= ~0x2000;
    }

    if ($f & 0x4000) {
        push @l, "raid_stripe_tree";
        $f &= ~0x4000;
    }

    if ($f & 0x10000) {
        push @l, "simple_quota";
        $f &= ~0x10000;
    }

    if ($f != 0 || $#l == -1) {
        push @l, sprintf("%x", $f);
    }

    return join(',', @l);
}

sub compat_ro_flags {
    my ($f) = @_;
    my @l;

    if ($f & 1) {
        push @l, "free_space_tree";
        $f &= ~1;
    }

    if ($f & 2) {
        push @l, "free_space_tree_valid";
        $f &= ~2;
    }

    if ($f & 4) {
        push @l, "verity";
        $f &= ~4;
    }

    if ($f & 8) {
        push @l, "block_group_tree";
        $f &= ~8;
    }

    if ($f != 0 || $#l == -1) {
        push @l, sprintf("%x", $f);
    }

    return join(',', @l);
}

sub format_super_flags {
    my ($f) = @_;
    my @l;

    if ($f & 1) {
        push @l, "written";
        $f &= ~1;
    }

    if ($f & 2) {
        push @l, "reloc";
        $f &= ~2;
    }

    if ($f & 4) {
        push @l, "error";
        $f &= ~4;
    }

    if ($f & 0x100000000) {
        push @l, "seeding";
        $f &= ~0x100000000;
    }

    if ($f & 0x200000000) {
        push @l, "metadump";
        $f &= ~0x200000000;
    }

    if ($f & 0x400000000) {
        push @l, "metadump_v2";
        $f &= ~0x400000000;
    }

    if ($f & 0x800000000) {
        push @l, "changing_fsid";
        $f &= ~0x800000000;
    }

    if ($f & 0x1000000000) {
        push @l, "changing_fsid_v2";
        $f &= ~0x1000000000;
    }

    if ($f & 0x4000000000) {
        push @l, "changing_bg_tree";
        $f &= ~0x4000000000;
    }

    if ($f & 0x8000000000) {
        push @l, "changing_data_csum";
        $f &= ~0x8000000000;
    }

    if ($f & 0x10000000000) {
        push @l, "changin_meta_csum";
        $f &= ~0x10000000000;
    }

    if ($f != 0 || $#l == -1) {
        push @l, sprintf("%x", $f);
    }

    return join(',', @l);
}

sub csum_type {
    my ($t) = @_;

    if ($t == 0) {
        return "crc32";
    } elsif ($t == 1) {
        return "xxhash";
    } elsif ($t == 2) {
        return "sha256";
    } elsif ($t == 3) {
        return "blake2";
    } else {
        return sprintf("%x", $t);
    }
}

sub read_superblock {
    my ($f) = @_;
    my ($sb, @b, @b2, @di, $csum);

    seek($f, 0x10000, 0);
    read($f, $sb, 0x1000);
    ($roottree, $chunktree, $logtree) = unpack("x80QQQ", $sb);
    @b = unpack("a32a16QQa8QQQQQQQQQVVVVVQQQQvCCCa98A256QQa16x224a2048a672", $sb);
    @di = unpack("QQQVVVQQQVCCa16a16", $b[27]);

    $csum_type = $b[23];

    if ($csum_type == 1) {
        $csum = sprintf("%016x", unpack("Q", $b[0]));
    } elsif ($csum_type == 2 || $csum_type == 3) {
        $csum = sprintf("%016x%016x%016x%016x", unpack("QQQQ", $b[0]));
    } else {
        $csum = sprintf("%08x", unpack("V", $b[0]));
    }

    printf("superblock csum=%s fsid=%s bytenr=%x flags=%s magic=%s generation=%x root=%x chunk_root=%x log_root=%x log_root_transid=%x total_bytes=%x bytes_used=%x root_dir_objectid=%x num_devices=%x sectorsize=%x nodesize=%x leafsize=%x stripesize=%x sys_chunk_array_size=%x chunk_root_generation=%x compat_flags=%x compat_ro_flags=%s incompat_flags=%s csum_type=%s root_level=%x chunk_root_level=%x log_root_level=%x (dev_item devid=%x total_bytes=%x bytes_used=%x io_align=%x io_width=%x sector_size=%x type=%x generation=%x start_offset=%x dev_group=%x seek_speed=%x bandwidth=%x uuid=%s fsid=%s) label=%s cache_generation=%x uuid_tree_generation=%x metadata_uuid=%s\n", $csum, format_uuid($b[1]), $b[2], format_super_flags($b[3]), $b[4], $b[5], $b[6], $b[7], $b[8], $b[9], $b[10], $b[11], $b[12], $b[13], $b[14], $b[15], $b[16], $b[17], $b[18], $b[19], $b[20], compat_ro_flags($b[21]), incompat_flags($b[22]), csum_type($b[23]), $b[24], $b[25], $b[26], $di[0], $di[1], $di[2], $di[3], $di[4], $di[5], $di[6], $di[7], $di[8], $di[9], $di[10], $di[11], format_uuid($di[12]), format_uuid($di[13]), $b[28], $b[29], $b[30], format_uuid($b[31]));

    my $devid = format_uuid($di[12]);

    $blocksize = $b[14];
    $nodesize = $b[15];

    $devs{$di[0]} = $f;

    my $bootstrap = substr($b[32], 0, $b[18]);

    while (length($bootstrap) > 0) {
        #print Dumper($bootstrap)."\n";
        @b2 = unpack("QCQ", $bootstrap);
        printf("bootstrap %x,%x,%x\n", @b2[0], @b2[1], @b2[2]);
        $bootstrap = substr($bootstrap, 0x11);

        my @c = unpack("QQQQVVVvv", $bootstrap);
        dump_item(0xe4, substr($bootstrap, 0, 0x30 + ($c[7] * 0x20)), "", 0);

        $bootstrap = substr($bootstrap, 0x30);

        my %obj;

        $obj{'offset'} = $b2[2];
        $obj{'size'} = $c[0];
        $obj{'type'} = $c[3];
        $obj{'num_stripes'} = $c[7];
        $obj{'stripe_len'} = $c[2];
        $obj{'sub_stripes'} = $c[8];

        for (my $i = 0; $i < $c[7]; $i++) {
            my @cis = unpack("QQa16", $bootstrap);
            $bootstrap = substr($bootstrap, 0x20);

            $obj{'stripes'}[$i]{'physoffset'} = $cis[1];
            $obj{'stripes'}[$i]{'devid'} = $cis[0];
        }

        push @l2p_bs, \%obj;
    }

    my $backups = $b[33];

    while (length($backups) > 0) {
        my $backup = substr($backups, 0, 168);
        $backups = substr($backups, 168);

        my @b3 = unpack("QQQQQQQQQQQQQQQx32CCCCCCx10", $backup);

        printf("backup tree_root=%x tree_root_gen=%x chunk_root=%x chunk_root_gen=%x extent_root=%x extent_root_gen=%x fs_root=%x fs_root_gen=%x dev_root=%x dev_root_gen=%x csum_root=%x csum_root_gen=%x total_bytes=%x bytes_used=%x num_devices=%x tree_root_level=%x chunk_root_level=%x extent_root_level=%x fs_root_level=%x dev_root_level=%x csum_root_level=%x\n", @b3);
    }

    print "\n";
}

sub format_uuid {
    my ($s) = @_;
    my @b = unpack("VVVV", $s);

    return sprintf("%08x%08x%08x%08x", $b[3], $b[2], $b[1], $b[0]);
}

sub format_time {
    my ($t, $ns) = @_;

    my @tb = gmtime($t);

    return sprintf("%04u-%02u-%02uT%02u:%02u:%02u", $tb[5] + 1900, $tb[4] + 1, $tb[3], $tb[2], $tb[1], $tb[0]);
}

sub inode_flags {
    my ($flags) = @_;
    my @l = ();

    if ($flags & 1) {
        push @l, "nodatasum";
        $flags &= ~1;
    }

    if ($flags & 2) {
        push @l, "nodatacow";
        $flags &= ~2;
    }

    if ($flags & 4) {
        push @l, "readonly";
        $flags &= ~4;
    }

    if ($flags & 8) {
        push @l, "nocompress";
        $flags &= ~8;
    }

    if ($flags & 16) {
        push @l, "prealloc";
        $flags &= ~16;
    }

    if ($flags & 32) {
        push @l, "sync";
        $flags &= ~32;
    }

    if ($flags & 64) {
        push @l, "immutable";
        $flags &= ~64;
    }

    if ($flags & 128) {
        push @l, "append";
        $flags &= ~128;
    }

    if ($flags & 256) {
        push @l, "nodump";
        $flags &= ~256;
    }

    if ($flags & 512) {
        push @l, "noatime";
        $flags &= ~512;
    }

    if ($flags & 1024) {
        push @l, "dirsync";
        $flags &= ~1024;
    }

    if ($flags & 2048) {
        push @l, "compress";
        $flags &= ~2048;
    }

    if ($flags & 0x80000000) {
        push @l, "root_item_init";
        $flags &= ~0x80000000;
    }

    if ($flags & 4294967296) {
        push @l, "ro_verity";
        $flags &= ~4294967296;
    }

    if ($flags != 0) {
        push @l, sprintf("%x", $flags);
    }

    if ($#l > -1) {
        return join(',', @l);
    } else {
        return 0;
    }
}

sub format_balance {
    my ($s) = @_;
    my (@b, $flags, @f, $fl, $t);

    @b = unpack("QVVQQQQQQQVVVV", $s);

    $flags = $b[9];

    $t = sprintf("profiles=%x", $b[0]);

    if ($flags & (1 << 10)) {
        $t .= sprintf(" usage=%x", ($b[2] << 32) | $b[1]);
    } elsif ($flags & (1 << 1)) {
        $t .= sprintf(" usage=%x..%x", $b[1], $b[2]);
    }

    $t .= sprintf(" devid=%x pstart=%x pend=%x vstart=%x vend=%x target=%x", $b[3], $b[4], $b[5], $b[6], $b[7], $b[8]);

    @f = ();
    $fl = $flags;

    if ($fl & (1 << 0)) {
        push @f, "profiles";
        $fl &= ~(1 << 0);
    }

    if ($fl & (1 << 1)) {
        push @f, "usage";
        $fl &= ~(1 << 1);
    }

    if ($fl & (1 << 2)) {
        push @f, "devid";
        $fl &= ~(1 << 2);
    }

    if ($fl & (1 << 3)) {
        push @f, "drange";
        $fl &= ~(1 << 3);
    }

    if ($fl & (1 << 4)) {
        push @f, "vrange";
        $fl &= ~(1 << 4);
    }

    if ($fl & (1 << 5)) {
        push @f, "limit";
        $fl &= ~(1 << 5);
    }

    if ($fl & (1 << 6)) {
        push @f, "limitrange";
        $fl &= ~(1 << 6);
    }

    if ($fl & (1 << 7)) {
        push @f, "stripesrange";
        $fl &= ~(1 << 7);
    }

    if ($fl & (1 << 8)) {
        push @f, "convert";
        $fl &= ~(1 << 8);
    }

    if ($fl & (1 << 9)) {
        push @f, "soft";
        $fl &= ~(1 << 9);
    }

    if ($fl & (1 << 10)) {
        push @f, "usagerange";
        $fl &= ~(1 << 10);
    }

    if ($fl != 0 || $#f == -1) {
        push @f, $fl;
    }

    $t .= sprintf(" flags=%s", join(',', @f));

    if ($flags & (1 << 5)) {
        $t .= sprintf(" limit=%x", ($b[11] << 32) | $b[10]);
    } elsif ($flags & (1 << 6)) {
        $t .= sprintf(" limit=%x..%x", $b[11], $b[10]);
    }

    if ($flags & (1 << 7)) {
        $t .= sprintf(" stripes=%x..%x", $b[12], $b[13]);
    }

    return $t;
}

sub qgroup_status_flags {
    my ($f) = @_;
    my (@l);

    if ($f & 1) {
        push @l, "on";
        $f &= ~1;
    }

    if ($f & 2) {
        push @l, "rescan";
        $f &= ~2;
    }

    if ($f & 4) {
        push @l, "inconsistent";
        $f &= ~4;
    }

    if ($f & 8) {
        push @l, "simple_mode";
        $f &= ~8;
    }

    if ($f != 0) {
        push @l, $f;
    }

    return join(',', @l);
}

sub free_space_bitmap {
    my ($s, $off) = @_;

    my $b = "";
    while (length($s) != 0) {
        $b .= reverse(sprintf("%08b", ord($s)));
        $s = substr($s, 1, length($s) - 1);
    }

    my @runs = ();

    my $run_start = 0;
    for (my $i = 0; $i < length($b); $i++) {
        my $c = substr($b, $i, 1);

        if ($c eq "1" && ($i == 0 || substr($b, $i - 1, 1) eq "0")) {
            $run_start = $i;
        } elsif ($c eq "0" && $i != 0 && substr($b, $i - 1, 1) eq "1") {
            push @runs, sprintf("%x, %x", $off + ($run_start * $blocksize), ($i - $run_start) * $blocksize);
        }
    }

    if (substr($b, length($b) - 1, 1) eq "1") {
        push @runs, sprintf("%x, %x", $off + ($run_start * $blocksize),
                            (length($b) - $run_start) * $blocksize);
    }

    return join('; ', @runs);
}

sub block_group_item_flags {
    my ($f) = @_;
    my (@l);

    if ($f & 1) {
        push @l, "data";
        $f &= ~1;
    }

    if ($f & 2) {
        push @l, "system";
        $f &= ~2;
    }

    if ($f & 4) {
        push @l, "metadata";
        $f &= ~4;
    }

    if ($f & 8) {
        push @l, "raid0";
        $f &= ~8;
    }

    if ($f & 16) {
        push @l, "raid1";
        $f &= ~16;
    }

    if ($f & 32) {
        push @l, "dup";
        $f &= ~32;
    }

    if ($f & 64) {
        push @l, "raid10";
        $f &= ~64;
    }

    if ($f & 128) {
        push @l, "raid5";
        $f &= ~128;
    }

    if ($f & 256) {
        push @l, "raid6";
        $f &= ~256;
    }

    if ($f & 512) {
        push @l, "raid1c3";
        $f &= ~512;
    }

    if ($f & 1024) {
        push @l, "raid1c4";
        $f &= ~1024;
    }

    if ($f != 0) {
        push @l, $f;
    }

    return join(',', @l);
}

sub extent_item_flags {
    my ($f) = @_;
    my (@l);

    if ($f & 1) {
        push @l, "data";
        $f &= ~1;
    }

    if ($f & 2) {
        push @l, "tree_block";
        $f &= ~2;
    }

    if ($f & 256) {
        push @l, "full_backref";
        $f &= ~256;
    }

    if ($f != 0) {
        push @l, $f;
    }

    return join(',', @l);
}

sub extent_data_type {
    my ($d) = @_;

    if ($d == 0) {
        return "inline";
    } elsif ($d == 1) {
        return "reg";
    } elsif ($d == 2) {
        return "prealloc";
    } else {
        return sprintf("%x", $d);
    }
}

sub compression_type {
    my ($d) = @_;

    if ($d == 0) {
        return "none";
    } elsif ($d == 1) {
        return "zlib";
    } elsif ($d == 2) {
        return "lzo";
    } elsif ($d == 3) {
        return "zstd";
    } else {
        return sprintf("%x", $d);
    }
}

sub dir_item_type {
    my ($d) = @_;

    if ($d == 0) {
        return "unknown";
    } elsif ($d == 1) {
        return "reg_file";
    } elsif ($d == 2) {
        return "dir";
    } elsif ($d == 3) {
        return "chrdev";
    } elsif ($d == 4) {
        return "blkdev";
    } elsif ($d == 5) {
        return "fifo";
    } elsif ($d == 6) {
        return "sock";
    } elsif ($d == 7) {
        return "symlink";
    } elsif ($d == 8) {
        return "xattr";
    } else {
        return sprintf("%x", $d);
    }
}

sub free_space_info_flags {
    my ($f) = @_;
    my (@l);

    if ($f & 1) {
        push @l, "using_bitmaps";
        $f &= ~1;
    }

    if ($f != 0 || $#l == -1) {
        push @l, sprintf("%x", $f);
    }

    return join(',', @l);
}

sub qgroup_limit_flags {
    my ($f) = @_;
    my (@l);

    if ($f & 1) {
        push @l, "max_rfer";
        $f &= ~1;
    }

    if ($f & 2) {
        push @l, "max_excl";
        $f &= ~2;
    }

    if ($f & 4) {
        push @l, "rsv_rfer";
        $f &= ~4;
    }

    if ($f & 8) {
        push @l, "rsv_excl";
        $f &= ~8;
    }

    if ($f & 16) {
        push @l, "rfer_cmpr";
        $f &= ~8;
    }

    if ($f & 32) {
        push @l, "excl_cmpr";
        $f &= ~8;
    }

    if ($f != 0 || $#l == -1) {
        push @l, $f;
    }

    return join(',', @l);
}

sub dump_item {
    my ($type, $s, $pref, $id, $off) = @_;
    my (@b);

    my $unrecog = 0;

    print $pref;
    if ($type == 0x1 || $type == 0x84) { # INODE_ITEM or ROOT_ITEM
        if (length($s) < 0xa0) {
            $s .= chr(0) x (0xa0 - length($s));
        }

        @b = unpack("QQQQQVVVVQQQx32QVQVQVQV", $s);
        $s = substr($s, 0xa0);

        if ($type == 0x84) {
            print "root_item";
        } else {
            print "inode_item";
        }

        printf(" generation=%x transid=%x size=%x nbytes=%x block_group=%x nlink=%x uid=%x gid=%x mode=%o rdev=%x flags=%s sequence=%x atime=%s ctime=%s mtime=%s otime=%s", $b[0], $b[1], $b[2], $b[3], $b[4], $b[5], $b[6], $b[7], $b[8], $b[9], inode_flags($b[10]), $b[11], format_time($b[12], $b[13]), format_time($b[14], $b[15]), format_time($b[16], $b[17]), format_time($b[18], $b[19]));

        if ($type != 0x1) {
            @b = unpack("QQQQQQQVQCQCC", $s);
            $s = substr($s, 0x4f);

            #print Dumper(@b)."\n";
            printf("; generation=%x root_dirid=%x bytenr=%x byte_limit=%x bytes_used=%x last_snapshot=%x flags=%x refs=%x drop_progress=%x,%x,%x drop_level=%x level=%x", @b);

            @b = unpack("Qa16a16a16QQQQQVQVQVQV", $s);
            $s = substr($s, 0xc8); # above + 64 blank bytes

            printf(" generation_v2=%x uuid=%s parent_uuid=%s received_uuid=%s ctransid=%x otransid=%x stransid=%x rtransid=%x ctime=%s otime=%s stime=%s rtime=%s", $b[0], format_uuid($b[1]), format_uuid($b[2]), format_uuid($b[3]), $b[4], $b[5], $b[6], $b[7], format_time($b[8], $b[9]), format_time($b[10], $b[11]), format_time($b[12], $b[13]), format_time($b[14], $b[15]));
        }
    } elsif ($type == 0xc) { # INODE_REF
        printf("inode_ref");

        do {
            @b = unpack("Qv", $s);
            $s = substr($s, 0xa);
            my $name = substr($s, 0, $b[1]);
            $s = substr($s, $b[1]);

            printf(" index=%x name_len=%x name=%s", $b[0], $b[1], $name);
        } while (length($s) > 0);
    } elsif ($type == 0xd) { # INODE_EXTREF
        printf("inode_extref");

        do {
            @b = unpack("QQv", $s);
            $s = substr($s, 0x12);
            my $name = substr($s, 0, $b[2]);
            $s = substr($s, $b[2]);

            printf(" parent_objectid=%x index=%x name_len=%x name=%s", $b[0], $b[1], $b[2], $name);
        } while (length($s) > 0);
    } elsif ($type == 0x18 || $type == 0x54 || $type == 0x60) { # XATTR_ITEM, DIR_ITEM or DIR_INDEX
        print $type == 0x54 ? "dir_item" : ($type == 0x18 ? "xattr_item" : "dir_index");

        while (length($s) > 0) {
            @b = unpack("QCQQvvC", $s);
            $s = substr($s, 0x1e);

            my $name = substr($s, 0, $b[5]);
            $s = substr($s, $b[5]);

            my $name2 = substr($s, 0, $b[4]);
            $s = substr($s, $b[4]);

            printf(" location=%x,%x,%x transid=%x data_len=%x name_len=%x type=%s name=%s%s", $b[0], $b[1], $b[2], $b[3], $b[4], $b[5], dir_item_type($b[6]), $name, $name2 eq "" ? "" : (" data=" . $name2));
        }
    } elsif ($type == 0x24) { # VERITY_DESC_ITEM
        printf("verity_desc_item");

        if ($off == 0) {
            @b = unpack("Qx16C", $s);
            $s = substr($s, 25);

            printf(" size=%x encryption=%x", $b[0], $b[1]);
        } else {
            while (length($s) > 0) {
                @b = unpack("C", $s);
                printf(" %02x", $b[0]);
                $s = substr($s, 1);
            }
        }
    } elsif ($type == 0x25) { # VERITY_MERKLE_ITEM
        printf("verity_merkle_item");

        while (length($s) > 0) {
            @b = unpack("NNNNNNNN", $s);
            printf(" %008x%008x%008x%008x%008x%008x%008x%008x", $b[0], $b[1], $b[2], $b[3], $b[4], $b[5], $b[6], $b[7]);
            $s = substr($s, 32);
        }
    } elsif ($type == 0x30) { # ORPHAN_ITEM
        printf("orphan_item");
    } elsif ($type == 0x48) { # DIR_LOG_INDEX
        @b = unpack("Q", $s);
        $s = substr($s, 8);

        printf("dir_log_index end=%x", $b[0]);
    } elsif ($type == 0x6c) { # EXTENT_DATA
        @b = unpack("QQCCvC", $s);
        $s = substr($s, 0x15);

        printf("extent_data generation=%x ram_bytes=%x compression=%s encryption=%x other_encoding=%x type=%s", $b[0], $b[1], compression_type($b[2]), $b[3], $b[4], extent_data_type($b[5]));

        if ($b[5] != 0) {
            @b = unpack("QQQQ", $s);
            $s = substr($s, 0x20);

            printf(" disk_bytenr=%x disk_num_bytes=%x offset=%x num_bytes=%x", @b);
        } else {
            $s = substr($s, $b[1]);
        }
    } elsif ($type == 0x80) { # EXTENT_CSUM
        print "extent_csum";

        if ($csum_type == 1) { # xxhash
            while (length($s) > 0) {
                printf(" %016x", unpack("Q", $s));
                $s = substr($s, 8);
            }
        } elsif ($csum_type == 2 || $csum_type == 3) { # sha256 or blake2
            while (length($s) > 0) {
                printf(" %016x%016x%016x%016x", unpack("QQQQ", $s));
                $s = substr($s, 32);
            }
        } else {
            while (length($s) > 0) {
                printf(" %08x", unpack("V", $s));
                $s = substr($s, 4);
            }
        }
    } elsif ($type == 0x90 || $type == 0x9c) { # ROOT_BACKREF or ROOT_REF
        @b = unpack("QQv", $s);
        $s = substr($s, 18);

        my $name = substr($s, 0, $b[2]);
        $s = substr($s, $b[2]);

        printf("%s dirid=%x sequence=%x name_len=%x name=%s", $type == 0x90 ? "root_backref" : "root_ref", $b[0], $b[1], $b[2], $name);
    } elsif ($type == 0xa8 || $type == 0xa9) { # EXTENT_ITEM_KEY or METADATA_ITEM_KEY
        # FIXME - TREE_BLOCK is out by one byte (why?)
        if (length($s) == 4) {
            @b = unpack("L", $s);
            $s = substr($s, 4);
            printf("extent_item_v0 refcount=%x", $b[0]);
        } else {
            @b = unpack("QQQ", $s);
            printf("%s refs=%x generation=%x flags=%s", $type == 0xa9 ? "metadata_item" : "extent_item",
                   $b[0], $b[1], extent_item_flags($b[2]));

            $s = substr($s, 24);

            my $refcount = $b[0];
            if ($b[2] & 2 && $type != 0xa9) {
                @b = unpack("QCQC", $s);
                printf(" key=%x,%x,%x level=%u", $b[0], $b[1], $b[2], $b[3]);
                $s = substr($s, 18);
            }

            while (length($s) > 0) {
                my $irt = unpack("C", $s);
                $s = substr($s, 1);

                if ($irt == 0xac) {
                    @b = unpack("Q", $s);
                    $s = substr($s, 8);
                    printf(" extent_owner_ref root=%x", $b[0]);
                } elsif ($irt == 0xb0) {
                    @b = unpack("Q", $s);
                    $s = substr($s, 8);
                    printf(" tree_block_ref root=%x", $b[0]);
                } elsif ($irt == 0xb2) {
                    @b = unpack("QQQv", $s);
                    $s = substr($s, 28);
                    printf(" extent_data_ref root=%x objectid=%x offset=%x count=%x", @b);
                    $refcount -= $b[3] - 1;
                } elsif ($irt == 0xb6) {
                    @b = unpack("Q", $s);
                    $s = substr($s, 8);
                    printf(" shared_block_ref offset=%x", $b[0]);
                } elsif ($irt == 0xb8) {
                    @b = unpack("Qv", $s);
                    $s = substr($s, 12);
                    printf(" shared_data_ref offset=%x count=%x", @b);
                    $refcount -= $b[1] - 1;
                } else {
                    printf(" unknown %x (length %u)", $irt, length($s));
                }
            }
        }
    } elsif ($type == 0xb0) { # TREE_BLOCK_REF
        printf("tree_block_ref");
    } elsif ($type == 0xb2) { # EXTENT_DATA_REF
        @b = unpack("QQQv", $s);
        $s = substr($s, 28);
        printf("extent_data_ref root=%x objectid=%x offset=%x count=%x", @b);
    } elsif ($type == 0xb4) { # EXTENT_REF_V0
        @b = unpack("QQQv", $s);
        $s = substr($s, 28);

        printf("extent_ref_v0 root=%x gen=%x objid=%x count=%x", @b);
    } elsif ($type == 0xb6) { # SHARED_BLOCK_REF
        printf("shared_block_ref");
    } elsif ($type == 0xb8) { # SHARED_DATA_REF
        @b = unpack("v", $s);
        $s = substr($s, 4);

        printf("shared_data_ref count=%x", @b);
    } elsif ($type == 0xc0) { # BLOCK_GROUP_ITEM
        @b = unpack("QQQ", $s);
        $s = substr($s, 0x18);
        printf("block_group_item used=%x chunk_objectid=%x flags=%s", $b[0], $b[1], block_group_item_flags($b[2]));
    } elsif ($type == 0xc6) { # FREE_SPACE_INFO
        @b = unpack("VV", $s);
        $s = substr($s, 0x8);
        printf("free_space_info extent_count=%x flags=%s", $b[0], free_space_info_flags($b[1]));
    } elsif ($type == 0xc7) { # FREE_SPACE_EXTENT
        printf("free_space_extent");
    } elsif ($type == 0xc8) { # FREE_SPACE_BITMAP
        printf("free_space_bitmap %s", free_space_bitmap($s, $id));
        $s = "";
    } elsif ($type == 0xcc) { # DEV_EXTENT
        @b = unpack("QQQQa16", $s);
        $s = substr($s, 0x30);
        printf("dev_extent chunk_tree=%x chunk_objectid=%x chunk_offset=%x length=%x chunk_tree_uuid=%s", $b[0], $b[1], $b[2], $b[3], format_uuid($b[4]));
    } elsif ($type == 0xd8) { # DEV_ITEM
        @b = unpack("QQQVVVQQQVCCa16a16", $s);
        printf("dev_item devid=%x total_bytes=%x bytes_used=%x io_align=%x io_width=%x sector_size=%x type=%x generation=%x start_offset=%x dev_group=%x seek_speed=%x bandwidth=%x uuid=%s fsid=%s", $b[0], $b[1],  $b[2], $b[3], $b[4], $b[5], $b[6], $b[7], $b[8], $b[9], $b[10], $b[11], format_uuid($b[12]), format_uuid($b[13]));
        $s = substr($s, 0x62);
    } elsif ($type == 0xe4) { # CHUNK_ITEM
        @b = unpack("QQQQVVVvv", $s);
        printf("chunk_item length=%x owner=%x stripe_len=%x type=%s io_align=%x io_width=%x sector_size=%x num_stripes=%x sub_stripes=%x",
               $b[0], $b[1], $b[2], block_group_item_flags($b[3]), $b[4], $b[5], $b[6], $b[7], $b[8]);
        $s = substr($s, 0x30);

        my $numstripes = $b[7];
        for (my $i = 0; $i < $numstripes; $i++) {
            @b = unpack("QQa16", $s);
            $s = substr($s, 0x20);

            printf(" stripe(%u) devid=%x offset=%x dev_uuid=%s", $i, $b[0], $b[1], format_uuid($b[2]));
        }
    } elsif ($type == 0xf0) { # QGROUP_STATUS
        @b = unpack("QQQQQ", $s);
        printf("qgroup_status version=%x generation=%x flags=%s rescan=%x enable_gen=%x", $b[0], $b[1], qgroup_status_flags($b[2]), $b[3], $b[4]);
        $s = substr($s, 0x28);
    } elsif ($type == 0xf2) { # QGROUP_INFO
        @b = unpack("QQQQQ", $s);
        printf("qgroup_info generation=%x rfer=%x rfer_cmpr=%x excl=%x excl_cmpr=%x", $b[0], $b[1], $b[2], $b[3], $b[4]);
        $s = substr($s, 0x28);
    } elsif ($type == 0xf4) { # QGROUP_LIMIT
        @b = unpack("QQQQQ", $s);
        printf("qgroup_limit flags=%s max_rfer=%x max_excl=%x rsv_rfer=%x rsv_excl=%x", qgroup_limit_flags($b[0]), $b[1], $b[2], $b[3], $b[4]);
        $s = substr($s, 0x28);
    } elsif ($type == 0xf6) { # QGROUP_RELATION
        printf("qgroup_relation");
    } elsif ($type == 0xf8 && $id == 0xfffffffffffffffc) { # balance
        my ($fl, @f);

        @b = unpack("Q", $s);
        $s = substr($s, 8);

        $fl = $b[0];
        @f = ();

        if ($fl & (1 << 0)) {
            push @f, "data";
            $fl &= ~(1 << 0);
        }

        if ($fl & (1 << 1)) {
            push @f, "system";
            $fl &= ~(1 << 1);
        }

        if ($fl & (1 << 2)) {
            push @f, "metadata";
            $fl &= ~(1 << 2);
        }

        if ($fl != 0 || $#f == -1) {
            push @f, $fl;
        }

        printf("balance flags=%s data=(%s) metadata=(%s) sys=(%s)", join(',', @f), format_balance(substr($s, 0, 0x88)), format_balance(substr($s, 0x88, 0x88)), format_balance(substr($s, 0x110, 0x88)));

        $s = substr($s, 0x1b8);
    } elsif ($type == 0xf9) { # DEV_STATS
        print "dev_stats";

        while (length($s) > 0) {
            printf(" %x", unpack("Q", $s));
            $s = substr($s, 8);
        }
    } elsif ($type == 0xfb) { # UUID_SUBVOL
        print "uuid_subvol";

        while (length($s) > 0) {
            printf(" %x", unpack("Q", $s));
            $s = substr($s, 8);
        }
    } elsif ($type == 0xfc) { # UUID_REC_SUBVOL
        print "uuid_rec_subvol";

        while (length($s) > 0) {
            printf(" %x", unpack("Q", $s));
            $s = substr($s, 8);
        }
    } elsif ($type == 0 && $id == 0xfffffffffffffff5) { # free space
        @b = unpack("QCQQQQ", $s);
        $s = substr($s, 0x29);

        printf("free_space location=(%x,%x,%x) generation=%x num_entries=%x num_bitmaps=%x", @b);
    } else {
        printf STDERR("ERROR - unknown type %x (size=%x, tell=%x)\n", $type, length($s), tell($f));
        printf("unknown (size=%x)", length($s));
        $unrecog = 1;
    }

    if ($unrecog == 0 && length($s) > 0) {
        printf(" (left=%x)", length($s));
    }

    print "\n";
}

sub read_data {
    my ($addr, $size, $bs) = @_;
    my (@arr, $f, $data, $stripeoff, $parity, $stripe, $stripe2, $physoff);

    if ($bs == 1) {
        @arr = @l2p_bs;
    } else {
        @arr = @l2p;
    }

    foreach my $obj (@arr) {
        if ($obj->{'offset'} <= $addr && ($addr - $obj->{'offset'}) < $obj->{'size'}) {
            if ($obj->{'type'} & 0x80) { # RAID5
                my $data_stripes = $obj->{'num_stripes'} - 1;
                $stripeoff = ($addr - $obj->{'offset'}) % ($data_stripes * $obj->{'stripe_len'});
                $parity = (int(($addr - $obj->{'offset'}) / ($data_stripes * $obj->{'stripe_len'})) + $obj->{'num_stripes'} - 1) % $obj->{'num_stripes'};
                $stripe2 = int($stripeoff / $obj->{'stripe_len'});
                $stripe = ($parity + $stripe2 + 1) % $obj->{'num_stripes'};

                $f = $devs{$obj->{'stripes'}[$stripe]{'devid'}};
                $physoff = $obj->{'stripes'}[$stripe]{'physoffset'} + (int(($addr - $obj->{'offset'}) / ($data_stripes * $obj->{'stripe_len'})) * $obj->{'stripe_len'}) + ($stripeoff % $obj->{'stripe_len'});
            } elsif ($obj->{'type'} & 0x100) { # RAID6
                my $data_stripes = $obj->{'num_stripes'} - 2;
                $stripeoff = ($addr - $obj->{'offset'}) % ($data_stripes * $obj->{'stripe_len'});
                $parity = (int(($addr - $obj->{'offset'}) / ($data_stripes * $obj->{'stripe_len'})) + $obj->{'num_stripes'} - 1) % $obj->{'num_stripes'};
                $stripe2 = int($stripeoff / $obj->{'stripe_len'});
                $stripe = ($parity + $stripe2 + 1) % $obj->{'num_stripes'};

                $f = $devs{$obj->{'stripes'}[$stripe]{'devid'}};
                $physoff = $obj->{'stripes'}[$stripe]{'physoffset'} + (int(($addr - $obj->{'offset'}) / ($data_stripes * $obj->{'stripe_len'})) * $obj->{'stripe_len'}) + ($stripeoff % $obj->{'stripe_len'});
            } elsif ($obj->{'type'} & 0x40) { # RAID10
                my $stripe_num = ($addr - $obj->{'offset'}) / $obj->{'stripe_len'};
                my $stripe_offset = ($addr - $obj->{'offset'}) % $obj->{'stripe_len'};
                my $stripe = $stripe_num % ($obj->{'num_stripes'} / $obj->{'sub_stripes'}) * $obj->{'sub_stripes'};

                $f = $devs{$obj->{'stripes'}[$stripe]{'devid'}};
                $physoff = $obj->{'stripes'}[$stripe]{'physoffset'} + (($stripe_num / ($obj->{'num_stripes'} / $obj->{'sub_stripes'})) * $obj->{'stripe_len'}) + $stripe_offset;
            } elsif ($obj->{'type'} & 0x8) { # RAID0
                my $stripe_num = ($addr - $obj->{'offset'}) / $obj->{'stripe_len'};
                my $stripe_offset = ($addr - $obj->{'offset'}) % $obj->{'stripe_len'};
                my $stripe = $stripe_num % $obj->{'num_stripes'};

                $f = $devs{$obj->{'stripes'}[$stripe]{'devid'}};
                $physoff = $obj->{'stripes'}[$stripe]{'physoffset'} + (($stripe_num / $obj->{'num_stripes'}) * $obj->{'stripe_len'}) + $stripe_offset;
            } else { # SINGLE, DUP, RAID1, RAID1C3, RAID1C4
                $f = $devs{$obj->{'stripes'}[0]{'devid'}};
                $physoff = $obj->{'stripes'}[0]{'physoffset'} + $addr - $obj->{'offset'};
            }

            seek($f, $physoff, 0);
            read($f, $data, $size);

            return $data;
        }
    }
}

sub header_flags {
    my ($flags) = @_;
    my @l = ();

    if ($flags & 1) {
        push @l, "written";
        $flags &= ~1;
    }

    if ($flags & 2) {
        push @l, "reloc";
        $flags &= ~2;
    }

    if ($flags & 0x100000000000000) {
        push @l, "mixed_backref";
        $flags &= ~0x100000000000000;
    }

    if ($flags != 0) {
        push @l, sprintf("%x", $flags);
    }

    if ($#l > -1) {
        return join(',', @l);
    } else {
        return 0;
    }
}

sub dump_tree {
    my ($addr, $pref, $bs) = @_;
    my ($head, @headbits, $level, $treenum, $tree, $csum);

    $tree = read_data($addr, $nodesize, $bs);

    @headbits = unpack("a32a16QQa16QQVC", $tree);
    if ($headbits[2] != $addr) {
        printf STDERR sprintf("Address mismatch: expected %llx, got %llx\n", $addr, $headbits[2]);
        exit;
    }

    if ($csum_type == 1) {
        $csum = sprintf("%016x", unpack("Q", $headbits[0]));
    } elsif ($csum_type == 2 || $csum_type == 3) {
        $csum = sprintf("%016x%016x%016x%016x", unpack("QQQQ", $headbits[0]));
    } else {
        $csum = sprintf("%08x", unpack("V", $headbits[0]));
    }

    print $pref;
    printf("header csum=%s fsid=%s bytenr=%x flags=%s chunk_tree_uuid=%s generation=%x owner=%x nritems=%x level=%x\n", $csum, format_uuid($headbits[1]), $headbits[2], header_flags($headbits[3]), format_uuid($headbits[4]), $headbits[5], $headbits[6], $headbits[7], $headbits[8]);

    $level = $headbits[8];
    $treenum = $headbits[6];

    my $numitems = $headbits[7];

    if ($level == 0) {
        my $headaddr = tell($f);
        for (my $i = 0; $i < $numitems; $i++) {
            #read($f, my $itemhead, 0x19);
            my $itemhead = substr($tree, 0x65 + ($i * 0x19), 0x19);

            my @ihb = unpack("QCQVV", $itemhead);

            #print Dumper(@ihb)."\n";
            print $pref;
            printf("%x,%x,%x\n", $ihb[0], $ihb[1], $ihb[2]);

            my $item = substr($tree, 0x65 + $ihb[3], $ihb[4]);
            dump_item($ihb[1], $item, $pref, $ihb[0], $ihb[2]);

            if ($treenum == 3 && $ihb[1] == 0xe4) {
                my @b = unpack("QQQQVVVvv", $item);
                my $stripes = substr($item, 48);
                my %obj;

                my $numstripes = $b[7];

                $obj{'offset'} = $ihb[2];
                $obj{'size'} = $b[0];
                $obj{'type'} = $b[3];
                $obj{'num_stripes'} = $b[7];
                $obj{'stripe_len'} = $b[2];
                $obj{'sub_stripes'} = $b[8];

                for (my $i = 0; $i < $numstripes; $i++) {
                    my @cis = unpack("QQa16", $stripes);
                    $stripes = substr($stripes, 32);

                    $obj{'stripes'}[$i]{'physoffset'} = $cis[1];
                    $obj{'stripes'}[$i]{'devid'} = $cis[0];
                }

                push @l2p, \%obj;

                #print Dumper(@l2p);
            }

            if ($ihb[1] == 0x84) {
                if ($treenum == 1) {
                    $roots{$ihb[0]} = unpack("x176Q", $item);
                } elsif ($treenum == 0xfffffffffffffffa && $ihb[0] == 0xfffffffffffffffa) {
                    $logroots{$ihb[2]} = unpack("x176Q", $item);
                }
            }
        }
    } else {
        for (my $i = 0; $i < $numitems; $i++) {
            my $itemhead = substr($tree, 0x65 + ($i * 0x21), 0x21);

            my @ihb = unpack("QCQQQ", $itemhead);

            print $pref;
            printf("%x,%x,%x blockptr=%x generation=%x\n", $ihb[0], $ihb[1], $ihb[2], $ihb[3], $ihb[4]);

            dump_tree($ihb[3], " " . $pref, $bs);
        }
    }
}


================================================
FILE: mingw-amd64.cmake
================================================
#
# To Cross-compile, use:
#  cmake -DCMAKE_TOOLCHAIN_FILE=../mingw.cmake ..
#
# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Windows)

# which compilers to use for C and C++
SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)

# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)

# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

set(CMAKE_PREFIX_PATH /usr/x86_64-w64-mingw32/usr/lib/cmake)

set(CMAKE_SYSTEM_PROCESSOR x86_64)


================================================
FILE: mingw-x86.cmake
================================================
#
# To Cross-compile, use:
#  cmake -DCMAKE_TOOLCHAIN_FILE=../mingw.cmake ..
#
# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Windows)

# which compilers to use for C and C++
SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres)

SET(CMAKE_C_FLAGS "-m32")
SET(CMAKE_CXX_FLAGS "-m32")
SET(CMAKE_RC_FLAGS "-F pe-i386")
SET(CMAKE_ASM_FLAGS "-m32")

# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32)

# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

set(CMAKE_PREFIX_PATH /usr/i686-w64-mingw32/usr/lib/cmake)

set(CMAKE_SYSTEM_PROCESSOR x86)


================================================
FILE: msvc-aarch64.cmake
================================================
set(CMAKE_SYSTEM_NAME Windows)

SET(CMAKE_C_COMPILER /opt/msvc/bin/arm64/cl)
SET(CMAKE_CXX_COMPILER /opt/msvc/bin/arm64/cl)
SET(CMAKE_RC_COMPILER /opt/msvc/bin/arm64/rc)

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /MANIFEST:NO")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO")


================================================
FILE: msvc-amd64.cmake
================================================
set(CMAKE_SYSTEM_NAME Windows)

SET(CMAKE_C_COMPILER /opt/msvc/bin/x64/cl)
SET(CMAKE_CXX_COMPILER /opt/msvc/bin/x64/cl)
SET(CMAKE_RC_COMPILER /opt/msvc/bin/x64/rc)

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /MANIFEST:NO")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO")


================================================
FILE: msvc-armv7.cmake
================================================
set(CMAKE_SYSTEM_NAME Windows)

SET(CMAKE_C_COMPILER /opt/msvc/bin/arm/cl)
SET(CMAKE_CXX_COMPILER /opt/msvc/bin/arm/cl)
SET(CMAKE_RC_COMPILER /opt/msvc/bin/arm/rc)

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /MANIFEST:NO")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO")


================================================
FILE: msvc-x86.cmake
================================================
set(CMAKE_SYSTEM_NAME Windows)

SET(CMAKE_C_COMPILER /opt/msvc/bin/x86/cl)
SET(CMAKE_CXX_COMPILER /opt/msvc/bin/x86/cl)
SET(CMAKE_RC_COMPILER /opt/msvc/bin/x86/rc)

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /MANIFEST:NO")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO")

set(CMAKE_PREFIX_PATH "/home/hellas/wine/vcpkg/installed/x64-windows")


================================================
FILE: send-dump.pl
================================================
#!/usr/bin/perl

# Dumper for btrfs send streams.
# Released under the same terms, or lack thereof, as btrfs-dump.pl.

open($f,$ARGV[0]) or die "Error opening ".$ARGV[0].": ".$!;
binmode($f);

while (!eof($f)) {
    do_stream($f);

    if (!eof($f)) {
        print "---\n";
    }
}

close($f);

sub do_stream {
    my ($f)=@_;

    read($f,$a,0x11);
    ($magic,$ver)=unpack("a13V",$a);

    if ($magic ne "btrfs-stream\0") {
        printf STDERR "Not a send file.\n";
        close($f);
        exit;
    }

    if ($ver != 1 && $ver != 2) {
        printf STDERR "Version $ver not supported.\n";
        close($f);
        exit;
    }

    $type = 0;
    while (!eof($f) && $type != 21) {
        read($f,$a,0xa);
        ($len,$type,$crc)=unpack("VvV",$a);

        if ($type == 1) {
            printf("subvol, %x, %08x\n", $len, $crc);
        } elsif ($type == 2) {
            printf("snapshot, %x, %08x\n", $len, $crc);
        } elsif ($type == 3) {
            printf("mkfile, %x, %08x\n", $len, $crc);
        } elsif ($type == 4) {
            printf("mkdir, %x, %08x\n", $len, $crc);
        } elsif ($type == 5) {
            printf("mknod, %x, %08x\n", $len, $crc);
        } elsif ($type == 6) {
            printf("mkfifo, %x, %08x\n", $len, $crc);
        } elsif ($type == 7) {
            printf("mksock, %x, %08x\n", $len, $crc);
        } elsif ($type == 8) {
            printf("symlink, %x, %08x\n", $len, $crc);
        } elsif ($type == 9) {
            printf("rename, %x, %08x\n", $len, $crc);
        } elsif ($type == 10) {
            printf("link, %x, %08x\n", $len, $crc);
        } elsif ($type == 11) {
            printf("unlink, %x, %08x\n", $len, $crc);
        } elsif ($type == 12) {
            printf("rmdir, %x, %08x\n", $len, $crc);
        } elsif ($type == 13) {
            printf("set_xattr, %x, %08x\n", $len, $crc);
        } elsif ($type == 14) {
            printf("remove_xattr, %x, %08x\n", $len, $crc);
        } elsif ($type == 15) {
            printf("write, %x, %08x\n", $len, $crc);
        } elsif ($type == 16) {
            printf("clone, %x, %08x\n", $len, $crc);
        } elsif ($type == 17) {
            printf("truncate, %x, %08x\n", $len, $crc);
        } elsif ($type == 18) {
            printf("chmod, %x, %08x\n", $len, $crc);
        } elsif ($type == 19) {
            printf("chown, %x, %08x\n", $len, $crc);
        } elsif ($type == 20) {
            printf("utimes, %x, %08x\n", $len, $crc);
        } elsif ($type == 21) {
            printf("end, %x, %08x\n", $len, $crc);
        } elsif ($type == 22) {
            printf("update-extent, %x, %08x\n", $len, $crc);
        } elsif ($type == 23) {
            printf("fallocate, %x, %08x\n", $len, $crc);
        } elsif ($type == 24) {
            printf("fileattr, %x, %08x\n", $len, $crc);
        } elsif ($type == 25) {
            printf("encoded-write, %x, %08x\n", $len, $crc);
        } else {
            printf("unknown(%x), %x, %08x\n", $type, $len, $crc);
        }

        read($f,$b,$len);
        print_tlvs($b);
    }
}

sub btrfstime {
    my ($t)=@_;

    my $ut = unpack("Q",$t);
    my @lt = localtime($ut);

    return sprintf("%04u-%02u-%02u %02u:%02u:%02u",$lt[5]+1900,$lt[4]+1,$lt[3],$lt[2],$lt[1],$lt[0]);
}

sub print_tlvs {
    my ($b)=@_;

    while (length($b)>0) {
        my ($t,$l)=unpack("vv",$b);

        if ($t == 1) {
            printf("  uuid: %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n", unpack("NnnnCCCCCC",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 2) {
            printf("  transid: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 3) {
            printf("  inode: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 4) {
            printf("  size: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 5) {
            printf("  mode: %o\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 6) {
            printf("  uid: %u\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 7) {
            printf("  gid: %u\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 8) {
            printf("  rdev: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 9) {
            printf("  ctime: %s\n", btrfstime(substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 10) {
            printf("  mtime: %s\n", btrfstime(substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 11) {
            printf("  atime: %s\n", btrfstime(substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 12) {
            printf("  otime: %s\n", btrfstime(substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 13) {
            printf("  xattr_name: \"%s\"\n", substr($b,4,$l));
            $b=substr($b,$l+4);
        } elsif ($t == 14) {
            printf("  xattr_data: \"%s\"\n", substr($b,4,$l));
            $b=substr($b,$l+4);
        } elsif ($t == 15) {
            printf("  path: \"%s\"\n", substr($b,4,$l));
            $b=substr($b,$l+4);
        } elsif ($t == 16) {
            printf("  path_to: \"%s\"\n", substr($b,4,$l));
            $b=substr($b,$l+4);
        } elsif ($t == 17) {
            printf("  path_link: \"%s\"\n", substr($b,4,$l));
            $b=substr($b,$l+4);
        } elsif ($t == 18) {
            printf("  offset: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 19) {
            if ($ver == 2) {
                printf("  data: (%x bytes)\n", length($b) - 2); # FIXME
                $b="";
            } else {
                printf("  data: (%x bytes)\n", $l);
                $b=substr($b,$l+4);
            }
        } elsif ($t == 20) {
            printf("  clone_uuid: %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n", unpack("NnnnCCCCCC",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 21) {
            printf("  clone_transid: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 22) {
            printf("  clone_path: \"%s\"\n", substr($b,4,$l));
            $b=substr($b,$l+4);
        } elsif ($t == 23) {
            printf("  clone_offset: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 24) {
            printf("  clone_len: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 25) {
            printf("  fallocate_mode: %x\n", unpack("V",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 26) {
            printf("  fileattr: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 27) {
            printf("  unencoded_file_len: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 28) {
            printf("  unencoded_len: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 29) {
            printf("  unencoded_offset: %x\n", unpack("Q",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 30) {
            printf("  compression: %x\n", unpack("V",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } elsif ($t == 31) {
            printf("  encryption: %x\n", unpack("V",substr($b,4,$l)));
            $b=substr($b,$l+4);
        } else {
            printf("  unknown(%u),%x\n",$t,$l);
            $b=substr($b,$l+4);
        }
    }
}


================================================
FILE: src/balance.c
================================================
/* Copyright (c) Mark Harmstone 2016-17
 *
 * This file is part of WinBtrfs.
 *
 * WinBtrfs is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public Licence as published by
 * the Free Software Foundation, either version 3 of the Licence, or
 * (at your option) any later version.
 *
 * WinBtrfs is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public Licence for more details.
 *
 * You should have received a copy of the GNU Lesser General Public Licence
 * along with WinBtrfs.  If not, see <http://www.gnu.org/licenses/>. */

#include "btrfs_drv.h"
#include "btrfsioctl.h"
#include "crc32c.h"
#include <ntddstor.h>

typedef struct {
    uint64_t address;
    uint64_t new_address;
    tree_header* data;
    EXTENT_ITEM* ei;
    tree* t;
    bool system;
    LIST_ENTRY refs;
    LIST_ENTRY list_entry;
} metadata_reloc;

typedef struct {
    uint8_t type;
    uint64_t hash;

    union {
        TREE_BLOCK_REF tbr;
        SHARED_BLOCK_REF sbr;
    };

    metadata_reloc* parent;
    bool top;
    LIST_ENTRY list_entry;
} metadata_reloc_ref;

typedef struct {
    uint64_t address;
    uint64_t size;
    uint64_t new_address;
    chunk* newchunk;
    EXTENT_ITEM* ei;
    LIST_ENTRY refs;
    LIST_ENTRY list_entry;
} data_reloc;

typedef struct {
    uint8_t type;
    uint64_t hash;

    union {
        EXTENT_DATA_REF edr;
        SHARED_DATA_REF sdr;
    };

    metadata_reloc* parent;
    LIST_ENTRY list_entry;
} data_reloc_ref;

#define BALANCE_UNIT 0x100000 // only read 1 MB at a time

static NTSTATUS add_metadata_reloc(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, LIST_ENTRY* items, traverse_ptr* tp,
                                   bool skinny, metadata_reloc** mr2, chunk* c, LIST_ENTRY* rollback) {
    NTSTATUS Status;
    metadata_reloc* mr;
    EXTENT_ITEM* ei;
    uint16_t len;
    uint64_t inline_rc;
    uint8_t* ptr;

    mr = ExAllocatePoolWithTag(PagedPool, sizeof(metadata_reloc), ALLOC_TAG);
    if (!mr) {
        ERR("out of memory\n");
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    mr->address = tp->item->key.obj_id;
    mr->data = NULL;
    mr->ei = (EXTENT_ITEM*)tp->item->data;
    mr->system = false;
    InitializeListHead(&mr->refs);

    Status = delete_tree_item(Vcb, tp);
    if (!NT_SUCCESS(Status)) {
        ERR("delete_tree_item returned %08lx\n", Status);
        ExFreePool(mr);
        return Status;
    }

    if (!c)
        c = get_chunk_from_address(Vcb, tp->item->key.obj_id);

    if (c) {
        acquire_chunk_lock(c, Vcb);

        c->used -= Vcb->superblock.node_size;

        space_list_add(c, tp->item->key.obj_id, Vcb->superblock.node_size, rollback);

        release_chunk_lock(c, Vcb);
    }

    ei = (EXTENT_ITEM*)tp->item->data;
    inline_rc = 0;

    len = tp->item->size - sizeof(EXTENT_ITEM);
    ptr = (uint8_t*)tp->item->data + sizeof(EXTENT_ITEM);
    if (!skinny) {
        len -= sizeof(EXTENT_ITEM2);
        ptr += sizeof(EXTENT_ITEM2);
    }

    while (len > 0) {
        uint8_t secttype = *ptr;
        uint16_t sectlen = secttype == TYPE_TREE_BLOCK_REF ? sizeof(TREE_BLOCK_REF) : (secttype == TYPE_SHARED_BLOCK_REF ? sizeof(SHARED_BLOCK_REF) : 0);
        metadata_reloc_ref* ref;

        len--;

        if (sectlen > len) {
            ERR("(%I64x,%x,%I64x): %x bytes left, expecting at least %x\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, len, sectlen);
            return STATUS_INTERNAL_ERROR;
        }

        if (sectlen == 0) {
            ERR("(%I64x,%x,%I64x): unrecognized extent type %x\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, secttype);
            return STATUS_INTERNAL_ERROR;
        }

        ref = ExAllocatePoolWithTag(PagedPool, sizeof(metadata_reloc_ref), ALLOC_TAG);
        if (!ref) {
            ERR("out of memory\n");
            return STATUS_INSUFFICIENT_RESOURCES;
        }

        if (secttype == TYPE_TREE_BLOCK_REF) {
            ref->type = TYPE_TREE_BLOCK_REF;
            RtlCopyMemory(&ref->tbr, ptr + sizeof(uint8_t), sizeof(TREE_BLOCK_REF));
            inline_rc++;
        } else if (secttype == TYPE_SHARED_BLOCK_REF) {
            ref->type = TYPE_SHARED_BLOCK_REF;
            RtlCopyMemory(&ref->sbr, ptr + sizeof(uint8_t), sizeof(SHARED_BLOCK_REF));
            inline_rc++;
        } else {
            ERR("unexpected tree type %x\n", secttype);
            ExFreePool(ref);
            return STATUS_INTERNAL_ERROR;
        }

        ref->parent = NULL;
        ref->top = false;
        InsertTailList(&mr->refs, &ref->list_entry);

        len -= sectlen;
        ptr += sizeof(uint8_t) + sectlen;
    }

    if (inline_rc < ei->refcount) { // look for non-inline entries
        traverse_ptr tp2 = *tp, next_tp;

        while (find_next_item(Vcb, &tp2, &next_tp, false, NULL)) {
            tp2 = next_tp;

            if (tp2.item->key.obj_id == tp->item->key.obj_id) {
                if (tp2.item->key.obj_type == TYPE_TREE_BLOCK_REF) {
                    metadata_reloc_ref* ref = ExAllocatePoolWithTag(PagedPool, sizeof(metadata_reloc_ref), ALLOC_TAG);
                    if (!ref) {
                        ERR("out of memory\n");
                        return STATUS_INSUFFICIENT_RESOURCES;
                    }

                    ref->type = TYPE_TREE_BLOCK_REF;
                    ref->tbr.offset = tp2.item->key.offset;
                    ref->parent = NULL;
                    ref->top = false;
                    InsertTailList(&mr->refs, &ref->list_entry);

                    Status = delete_tree_item(Vcb, &tp2);
                    if (!NT_SUCCESS(Status)) {
                        ERR("delete_tree_item returned %08lx\n", Status);
                        return Status;
                    }
                } else if (tp2.item->key.obj_type == TYPE_SHARED_BLOCK_REF) {
                    metadata_reloc_ref* ref = ExAllocatePoolWithTag(PagedPool, sizeof(metadata_reloc_ref), ALLOC_TAG);
                    if (!ref) {
                        ERR("out of memory\n");
                        return STATUS_INSUFFICIENT_RESOURCES;
                    }

                    ref->type = TYPE_SHARED_BLOCK_REF;
                    ref->sbr.offset = tp2.item->key.offset;
                    ref->parent = NULL;
                    ref->top = false;
                    InsertTailList(&mr->refs, &ref->list_entry);

                    Status = delete_tree_item(Vcb, &tp2);
                    if (!NT_SUCCESS(Status)) {
                        ERR("delete_tree_item returned %08lx\n", Status);
                        return Status;
                    }
                }
            } else
                break;
        }
    }

    InsertTailList(items, &mr->list_entry);

    if (mr2)
        *mr2 = mr;

    return STATUS_SUCCESS;
}

static NTSTATUS add_metadata_reloc_parent(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, LIST_ENTRY* items,
                                          uint64_t address, metadata_reloc** mr2, LIST_ENTRY* rollback) {
    LIST_ENTRY* le;
    KEY searchkey;
    traverse_ptr tp;
    bool skinny = false;
    NTSTATUS Status;

    le = items->Flink;
    while (le != items) {
        metadata_reloc* mr = CONTAINING_RECORD(le, metadata_reloc, list_entry);

        if (mr->address == address) {
            *mr2 = mr;
            return STATUS_SUCCESS;
        }

        le = le->Flink;
    }

    searchkey.obj_id = address;
    searchkey.obj_type = TYPE_METADATA_ITEM;
    searchkey.offset = 0xffffffffffffffff;

    Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, false, NULL);
    if (!NT_SUCCESS(Status)) {
        ERR("find_item returned %08lx\n", Status);
        return Status;
    }

    if (tp.item->key.obj_id == address && tp.item->key.obj_type == TYPE_METADATA_ITEM && tp.item->size >= sizeof(EXTENT_ITEM))
        skinny = true;
    else if (tp.item->key.obj_id == address && tp.item->key.obj_type == TYPE_EXTENT_ITEM && tp.item->key.offset == Vcb->superblock.node_size &&
             tp.item->size >= sizeof(EXTENT_ITEM)) {
        EXTENT_ITEM* ei = (EXTENT_ITEM*)tp.item->data;

        if (!(ei->flags & EXTENT_ITEM_TREE_BLOCK)) {
            ERR("EXTENT_ITEM for %I64x found, but tree flag not set\n", address);
            return STATUS_INTERNAL_ERROR;
        }
    } else {
        ERR("could not find valid EXTENT_ITEM for address %I64x\n", address);
        return STATUS_INTERNAL_ERROR;
    }

    Status = add_metadata_reloc(Vcb, items, &tp, skinny, mr2, NULL, rollback);
    if (!NT_SUCCESS(Status)) {
        ERR("add_metadata_reloc returned %08lx\n", Status);
        return Status;
    }

    return STATUS_SUCCESS;
}

static void sort_metadata_reloc_refs(metadata_reloc* mr) {
    LIST_ENTRY newlist, *le;

    if (mr->refs.Flink == mr->refs.Blink) // 0 or 1 items
        return;

    // insertion sort

    InitializeListHead(&newlist);

    while (!IsListEmpty(&mr->refs)) {
        metadata_reloc_ref* ref = CONTAINING_RECORD(RemoveHeadList(&mr->refs), metadata_reloc_ref, list_entry);
        bool inserted = false;

        if (ref->type == TYPE_TREE_BLOCK_REF)
            ref->hash = ref->tbr.offset;
        else if (ref->type == TYPE_SHARED_BLOCK_REF)
            ref->hash = ref->parent->new_address;

        le = newlist.Flink;
        while (le != &newlist) {
            metadata_reloc_ref* ref2 = CONTAINING_RECORD(le, metadata_reloc_ref, list_entry);

            if (ref->type < ref2->type || (ref->type == ref2->type && ref->hash > ref2->hash)) {
                InsertHeadList(le->Blink, &ref->list_entry);
                inserted = true;
                break;
            }

            le = le->Flink;
        }

        if (!inserted)
            InsertTailList(&newlist, &ref->list_entry);
    }

    newlist.Flink->Blink = &mr->refs;
    newlist.Blink->Flink = &mr->refs;
    mr->refs.Flink = newlist.Flink;
    mr->refs.Blink = newlist.Blink;
}

static NTSTATUS add_metadata_reloc_extent_item(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, metadata_reloc* mr) {
    NTSTATUS Status;
    LIST_ENTRY* le;
    uint64_t rc = 0;
    uint16_t inline_len;
    bool all_inline = true;
    metadata_reloc_ref* first_noninline = NULL;
    EXTENT_ITEM* ei;
    uint8_t* ptr;

    inline_len = sizeof(EXTENT_ITEM);
    if (!(Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA))
        inline_len += sizeof(EXTENT_ITEM2);

    sort_metadata_reloc_refs(mr);

    le = mr->refs.Flink;
    while (le != &mr->refs) {
        metadata_reloc_ref* ref = CONTAINING_RECORD(le, metadata_reloc_ref, list_entry);
        uint16_t extlen = 0;

        rc++;

        if (ref->type == TYPE_TREE_BLOCK_REF)
            extlen += sizeof(TREE_BLOCK_REF);
        else if (ref->type == TYPE_SHARED_BLOCK_REF)
            extlen += sizeof(SHARED_BLOCK_REF);

        if (all_inline) {
            if ((ULONG)(inline_len + 1 + extlen) > (Vcb->superblock.node_size >> 2)) {
                all_inline = false;
                first_noninline = ref;
            } else
                inline_len += extlen + 1;
        }

        le = le->Flink;
    }

    ei = ExAllocatePoolWithTag(PagedPool, inline_len, ALLOC_TAG);
    if (!ei) {
        ERR("out of memory\n");
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    ei->refcount = rc;
    ei->generation = mr->ei->generation;
    ei->flags = mr->ei->flags;
    ptr = (uint8_t*)&ei[1];

    if (!(Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA)) {
        EXTENT_ITEM2* ei2 = (EXTENT_ITEM2*)ptr;

        ei2->firstitem = *(KEY*)&mr->data[1];
        ei2->level = mr->data->level;

        ptr += sizeof(EXTENT_ITEM2);
    }

    le = mr->refs.Flink;
    while (le != &mr->refs) {
        metadata_reloc_ref* ref = CONTAINING_RECORD(le, metadata_reloc_ref, list_entry);

        if (ref == first_noninline)
            break;

        *ptr = ref->type;
        ptr++;

        if (ref->type == TYPE_TREE_BLOCK_REF) {
            TREE_BLOCK_REF* tbr = (TREE_BLOCK_REF*)ptr;

            tbr->offset = ref->tbr.offset;

            ptr += sizeof(TREE_BLOCK_REF);
        } else if (ref->type == TYPE_SHARED_BLOCK_REF) {
            SHARED_BLOCK_REF* sbr = (SHARED_BLOCK_REF*)ptr;

            sbr->offset = ref->parent->new_address;

            ptr += sizeof(SHARED_BLOCK_REF);
        }

        le = le->Flink;
    }

    if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA)
        Status = insert_tree_item(Vcb, Vcb->extent_root, mr->new_address, TYPE_METADATA_ITEM, mr->data->level, ei, inline_len, NULL, NULL);
    else
        Status = insert_tree_item(Vcb, Vcb->extent_root, mr->new_address, TYPE_EXTENT_ITEM, Vcb->superblock.node_size, ei, inline_len, NULL, NULL);

    if (!NT_SUCCESS(Status)) {
        ERR("insert_tree_item returned %08lx\n", Status);
        ExFreePool(ei);
        return Status;
    }

    if (!all_inline) {
        le = &first_noninline->list_entry;

        while (le != &mr->refs) {
            metadata_reloc_ref* ref = CONTAINING_RECORD(le, metadata_reloc_ref, list_entry);

            if (ref->type == TYPE_TREE_BLOCK_REF) {
                Status = insert_tree_item(Vcb, Vcb->extent_root, mr->new_address, TYPE_TREE_BLOCK_REF, ref->tbr.offset, NULL, 0, NULL, NULL);
                if (!NT_SUCCESS(Status)) {
                    ERR("insert_tree_item returned %08lx\n", Status);
                    return Status;
                }
            } else if (ref->type == TYPE_SHARED_BLOCK_REF) {
                Status = insert_tree_item(Vcb, Vcb->extent_root, mr->new_address, TYPE_SHARED_BLOCK_REF, ref->parent->new_address, NULL, 0, NULL, NULL);
                if (!NT_SUCCESS(Status)) {
                    ERR("insert_tree_item returned %08lx\n", Status);
                    return Status;
                }
            }

            le = le->Flink;
        }
    }

    if (ei->flags & EXTENT_ITEM_SHARED_BACKREFS || mr->data->flags & HEADER_FLAG_SHARED_BACKREF || !(mr->data->flags & HEADER_FLAG_MIXED_BACKREF)) {
        if (mr->data->level > 0) {
            uint16_t i;
            internal_node* in = (internal_node*)&mr->data[1];

            for (i = 0; i < mr->data->num_items; i++) {
                uint64_t sbrrc = find_extent_shared_tree_refcount(Vcb, in[i].address, mr->address, NULL);

                if (sbrrc > 0) {
                    SHARED_BLOCK_REF sbr;

                    sbr.offset = mr->new_address;

                    Status = increase_extent_refcount(Vcb, in[i].address, Vcb->superblock.node_size, TYPE_SHARED_BLOCK_REF, &sbr, NULL, 0, NULL);
                    if (!NT_SUCCESS(Status)) {
                        ERR("increase_extent_refcount returned %08lx\n", Status);
                        return Status;
                    }

                    sbr.offset = mr->address;

                    Status = decrease_extent_refcount(Vcb, in[i].address, Vcb->superblock.node_size, TYPE_SHARED_BLOCK_REF, &sbr, NULL, 0,
                                                      sbr.offset, false, NULL);
                    if (!NT_SUCCESS(Status)) {
                        ERR("decrease_extent_refcount returned %08lx\n", Status);
                        return Status;
                    }
                }
            }
        } else {
            uint16_t i;
            leaf_node* ln = (leaf_node*)&mr->data[1];

            for (i = 0; i < mr->data->num_items; i++) {
                if (ln[i].key.obj_type == TYPE_EXTENT_DATA && ln[i].size >= sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
                    EXTENT_DATA* ed = (EXTENT_DATA*)((uint8_t*)mr->data + sizeof(tree_header) + ln[i].offset);

                    if (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) {
                        EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;

                        if (ed2->size > 0) { // not sparse
                            uint32_t sdrrc = find_extent_shared_data_refcount(Vcb, ed2->address, mr->address, NULL);

                            if (sdrrc > 0) {
                                SHARED_DATA_REF sdr;
                                chunk* c;

                                sdr.offset = mr->new_address;
                                sdr.count = sdrrc;

                                Status = increase_extent_refcount(Vcb, ed2->address, ed2->size, TYPE_SHARED_DATA_REF, &sdr, NULL, 0, NULL);
                                if (!NT_SUCCESS(Status)) {
                                    ERR("increase_extent_refcount returned %08lx\n", Status);
                                    return Status;
                                }

                                sdr.offset = mr->address;

                                Status = decrease_extent_refcount(Vcb, ed2->address, ed2->size, TYPE_SHARED_DATA_REF, &sdr, NULL, 0,
                                                                  sdr.offset, false, NULL);
                                if (!NT_SUCCESS(Status)) {
                                    ERR("decrease_extent_refcount returned %08lx\n", Status);
                                    return Status;
                                }

                                c = get_chunk_from_address(Vcb, ed2->address);

                                if (c) {
                                    // check changed_extents

                                    ExAcquireResourceExclusiveLite(&c->changed_extents_lock, true);

                                    le = c->changed_extents.Flink;

                                    while (le != &c->changed_extents) {
                                        changed_extent* ce = CONTAINING_RECORD(le, changed_extent, list_entry);

                                        if (ce->address == ed2->address) {
                                            LIST_ENTRY* le2;

                                            le2 = ce->refs.Flink;
                                            while (le2 != &ce->refs) {
                                                changed_extent_ref* cer = CONTAINING_RECORD(le2, changed_extent_ref, list_entry);

                                                if (cer->type == TYPE_SHARED_DATA_REF && cer->sdr.offset == mr->address) {
                                                    cer->sdr.offset = mr->new_address;
                                                    break;
                                                }

                                                le2 = le2->Flink;
                                            }

                                            le2 = ce->old_refs.Flink;
                                            while (le2 != &ce->old_refs) {
                                                changed_extent_ref* cer = CONTAINING_RECORD(le2, changed_extent_ref, list_entry);

                                                if (cer->type == TYPE_SHARED_DATA_REF && cer->sdr.offset == mr->address) {
                                                    cer->sdr.offset = mr->new_address;
                                                    break;
                                                }

                                                le2 = le2->Flink;
                                            }

                                            break;
                                        }

                                        le = le->Flink;
                                    }

                                    ExReleaseResourceLite(&c->changed_extents_lock);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return STATUS_SUCCESS;
}

static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, LIST_ENTRY* items,
                                     LIST_ENTRY* data_items, chunk* c, LIST_ENTRY* rollback) {
    LIST_ENTRY tree_writes, *le;
    NTSTATUS Status;
    traverse_ptr tp;
    uint8_t level, max_level = 0;
    chunk* newchunk = NULL;

    InitializeListHead(&tree_writes);

    le = items->Flink;
    while (le != items) {
        metadata_reloc* mr = CONTAINING_RECORD(le, metadata_reloc, list_entry);
        LIST_ENTRY* le2;
        chunk* pc;

        mr->data = ExAllocatePoolWithTag(PagedPool, Vcb->superblock.node_size, ALLOC_TAG);
        if (!mr->data) {
            ERR("out of memory\n");
            return STATUS_INSUFFICIENT_RESOURCES;
        }

        Status = read_data(Vcb, mr->address, Vcb->superblock.node_size, NULL, true, (uint8_t*)mr->data,
                           c && mr->address >= c->offset && mr->address < c->offset + c->chunk_item->size ? c : NULL, &pc, NULL, 0, false, NormalPagePriority);
        if (!NT_SUCCESS(Status)) {
            ERR("read_data returned %08lx\n", Status);
            return Status;
        }

        if (pc->chunk_item->type & BLOCK_FLAG_SYSTEM)
            mr->system = true;

        if (data_items && mr->data->level == 0) {
            le2 = data_items->Flink;
            while (le2 != data_items) {
                data_reloc* dr = CONTAINING_RECORD(le2, data_reloc, list_entry);
                leaf_node* ln = (leaf_node*)&mr->data[1];
                uint16_t i;

                for (i = 0; i < mr->data->num_items; i++) {
                    if (ln[i].key.obj_type == TYPE_EXTENT_DATA && ln[i].size >= sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
                        EXTENT_DATA* ed = (EXTENT_DATA*)((uint8_t*)mr->data + sizeof(tree_header) + ln[i].offset);

                        if (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) {
                            EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;

                            if (ed2->address == dr->address)
                                ed2->address = dr->new_address;
                        }
                    }
                }

                le2 = le2->Flink;
            }
        }

        if (mr->data->level > max_level)
            max_level = mr->data->level;

        le2 = mr->refs.Flink;
        while (le2 != &mr->refs) {
            metadata_reloc_ref* ref = CONTAINING_RECORD(le2, metadata_reloc_ref, list_entry);

            if (ref->type == TYPE_TREE_BLOCK_REF) {
                KEY* firstitem;
                root* r = NULL;
                LIST_ENTRY* le3;
                tree* t;

                firstitem = (KEY*)&mr->data[1];

                le3 = Vcb->roots.Flink;
                while (le3 != &Vcb->roots) {
                    root* r2 = CONTAINING_RECORD(le3, root, list_entry);

                    if (r2->id == ref->tbr.offset) {
                        r = r2;
                        break;
                    }

                    le3 = le3->Flink;
                }

                if (!r) {
                    ERR("could not find subvol with id %I64x\n", ref->tbr.offset);
                    return STATUS_INTERNAL_ERROR;
                }

                Status = find_item_to_level(Vcb, r, &tp, firstitem, false, mr->data->level + 1, NULL);
                if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) {
                    ERR("find_item_to_level returned %08lx\n", Status);
                    return Status;
                }

                t = tp.tree;
                while (t && t->header.level < mr->data->level + 1) {
                    t = t->parent;
                }

                if (!t)
                    ref->top = true;
                else {
                    metadata_reloc* mr2;

                    Status = add_metadata_reloc_parent(Vcb, items, t->header.address, &mr2, rollback);
                    if (!NT_SUCCESS(Status)) {
                        ERR("add_metadata_reloc_parent returned %08lx\n", Status);
                        return Status;
                    }

                    ref->parent = mr2;
                }
            } else if (ref->type == TYPE_SHARED_BLOCK_REF) {
                metadata_reloc* mr2;

                Status = add_metadata_reloc_parent(Vcb, items, ref->sbr.offset, &mr2, rollback);
                if (!NT_SUCCESS(Status)) {
                    ERR("add_metadata_reloc_parent returned %08lx\n", Status);
                    return Status;
                }

                ref->parent = mr2;
            }

            le2 = le2->Flink;
        }

        le = le->Flink;
    }

    le = items->Flink;
    while (le != items) {
        metadata_reloc* mr = CONTAINING_RECORD(le, metadata_reloc, list_entry);
        LIST_ENTRY* le2;
        uint32_t hash;

        mr->t = NULL;

        hash = calc_crc32c(0xffffffff, (uint8_t*)&mr->address, sizeof(uint64_t));

        le2 = Vcb->trees_ptrs[hash >> 24];

        if (le2) {
            while (le2 != &Vcb->trees_hash) {
                tree* t = CONTAINING_RECORD(le2, tree, list_entry_hash);

                if (t->header.address == mr->address) {
                    mr->t = t;
                    break;
                } else if (t->hash > hash)
                    break;

                le2 = le2->Flink;
            }
        }

        le = le->Flink;
    }

    for (level = 0; level <= max_level; level++) {
        le = items->Flink;
        while (le != items) {
            metadata_reloc* mr = CONTAINING_RECORD(le, metadata_reloc, list_entry);

            if (mr->data->level == level) {
                bool done = false;
                LIST_ENTRY* le2;
                tree_write* tw;
                uint64_t flags;
                tree* t3;

                if (mr->system)
                    flags = Vcb->system_flags;
                else if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS)
                    flags = Vcb->data_flags;
                else
                    flags = Vcb->metadata_flags;

                if (newchunk) {
                    acquire_chunk_lock(newchunk, Vcb);

                    if (newchunk->chunk_item->type == flags && find_metadata_address_in_chunk(Vcb, newchunk, &mr->new_address)) {
                        newchunk->used += Vcb->superblock.node_size;
                        space_list_subtract(newchunk, mr->new_address, Vcb->superblock.node_size, rollback);
                        done = true;
                    }

                    release_chunk_lock(newchunk, Vcb);
                }

                if (!done) {
                    ExAcquireResourceExclusiveLite(&Vcb->chunk_lock, true);

                    le2 = Vcb->chunks.Flink;
                    while (le2 != &Vcb->chunks) {
                        chunk* c2 = CONTAINING_RECORD(le2, chunk, list_entry);

                        if (!c2->readonly && !c2->reloc && c2 != newchunk && c2->chunk_item->type == flags) {
                            acquire_chunk_lock(c2, Vcb);

                            if ((c2->chunk_item->size - c2->used) >= Vcb->superblock.node_size) {
                                if (find_metadata_address_in_chunk(Vcb, c2, &mr->new_address)) {
                                    c2->used += Vcb->superblock.node_size;
                                    space_list_subtract(c2, mr->new_address, Vcb->superblock.node_size, rollback);
                                    release_chunk_lock(c2, Vcb);
                                    newchunk = c2;
                                    done = true;
                                    break;
                                }
                            }

                            release_chunk_lock(c2, Vcb);
                        }

                        le2 = le2->Flink;
                    }

                    // allocate new chunk if necessary
                    if (!done) {
                        Status = alloc_chunk(Vcb, flags, &newchunk, false);

                        if (!NT_SUCCESS(Status)) {
                            ERR("alloc_chunk returned %08lx\n", Status);
                            ExReleaseResourceLite(&Vcb->chunk_lock);
                            goto end;
                        }

                        acquire_chunk_lock(newchunk, Vcb);

                        newchunk->balance_num = Vcb->balance.balance_num;

                        if (!find_metadata_address_in_chunk(Vcb, newchunk, &mr->new_address)) {
                            release_chunk_lock(newchunk, Vcb);
                            ExReleaseResourceLite(&Vcb->chunk_lock);
                            ERR("could not find address in new chunk\n");
                            Status = STATUS_DISK_FULL;
                            goto end;
                        } else {
                            newchunk->used += Vcb->superblock.node_size;
                            space_list_subtract(newchunk, mr->new_address, Vcb->superblock.node_size, rollback);
                        }

                        release_chunk_lock(newchunk, Vcb);
                    }

                    ExReleaseResourceLite(&Vcb->chunk_lock);
                }

                // update parents
                le2 = mr->refs.Flink;
                while (le2 != &mr->refs) {
                    metadata_reloc_ref* ref = CONTAINING_RECORD(le2, metadata_reloc_ref, list_entry);

                    if (ref->parent) {
                        uint16_t i;
                        internal_node* in = (internal_node*)&ref->parent->data[1];

                        for (i = 0; i < ref->parent->data->num_items; i++) {
                            if (in[i].address == mr->address) {
                                in[i].address = mr->new_address;
                                break;
                            }
                        }

                        if (ref->parent->t) {
                            LIST_ENTRY* le3;

                            le3 = ref->parent->t->itemlist.Flink;
                            while (le3 != &ref->parent->t->itemlist) {
                                tree_data* td = CONTAINING_RECORD(le3, tree_data, list_entry);

                                if (!td->inserted && td->treeholder.address == mr->address)
                                    td->treeholder.address = mr->new_address;

                                le3 = le3->Flink;
                            }
                        }
                    } else if (ref->top && ref->type == TYPE_TREE_BLOCK_REF) {
                        LIST_ENTRY* le3;
                        root* r = NULL;

                        // alter ROOT_ITEM

                        le3 = Vcb->roots.Flink;
                        while (le3 != &Vcb->roots) {
                            root* r2 = CONTAINING_RECORD(le3, root, list_entry);

                            if (r2->id == ref->tbr.offset) {
                                r = r2;
                                break;
                            }

                            le3 = le3->Flink;
                        }

                        if (r) {
                            r->treeholder.address = mr->new_address;

                            if (r == Vcb->root_root)
                                Vcb->superblock.root_tree_addr = mr->new_address;
                            else if (r == Vcb->chunk_root)
                                Vcb->superblock.chunk_tree_addr = mr->new_address;
                            else if (r->root_item.block_number == mr->address) {
                                KEY searchkey;
                                ROOT_ITEM* ri;

                                r->root_item.block_number = mr->new_address;

                                searchkey.obj_id = r->id;
                                searchkey.obj_type = TYPE_ROOT_ITEM;
                                searchkey.offset = 0xffffffffffffffff;

                                Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, NULL);
                                if (!NT_SUCCESS(Status)) {
                                    ERR("find_item returned %08lx\n", Status);
                                    goto end;
                                }

                                if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
                                    ERR("could not find ROOT_ITEM for tree %I64x\n", searchkey.obj_id);
                                    Status = STATUS_INTERNAL_ERROR;
                                    goto end;
                                }

                                ri = ExAllocatePoolWithTag(PagedPool, sizeof(ROOT_ITEM), ALLOC_TAG);
                                if (!ri) {
                                    ERR("out of memory\n");
                                    Status = STATUS_INSUFFICIENT_RESOURCES;
                                    goto end;
                                }

                                RtlCopyMemory(ri, &r->root_item, sizeof(ROOT_ITEM));

                                Status = delete_tree_item(Vcb, &tp);
                                if (!NT_SUCCESS(Status)) {
                                    ERR("delete_tree_item returned %08lx\n", Status);
                                    goto end;
                                }

                                Status = insert_tree_item(Vcb, Vcb->root_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, ri, sizeof(ROOT_ITEM), NULL, NULL);
                                if (!NT_SUCCESS(Status)) {
                                    ERR("insert_tree_item returned %08lx\n", Status);
                                    goto end;
                                }
                            }
                        }
                    }

                    le2 = le2->Flink;
                }

                mr->data->address = mr->new_address;

                t3 = mr->t;

                while (t3) {
                    uint8_t h;
                    bool inserted;
                    tree* t4 = NULL;

                    // check if tree loaded more than once
                    if (t3->list_entry.Flink != &Vcb->trees_hash) {
                        tree* nt = CONTAINING_RECORD(t3->list_entry_hash.Flink, tree, list_entry_hash);

                        if (nt->header.address == t3->header.address)
                            t4 = nt;
                    }

                    t3->header.address = mr->new_address;

                    h = t3->hash >> 24;

                    if (Vcb->trees_ptrs[h] == &t3->list_entry_hash) {
                        if (t3->list_entry_hash.Flink == &Vcb->trees_hash)
                            Vcb->trees_ptrs[h] = NULL;
                        else {
                            tree* t2 = CONTAINING_RECORD(t3->list_entry_hash.Flink, tree, list_entry_hash);

                            if (t2->hash >> 24 == h)
                                Vcb->trees_ptrs[h] = &t2->list_entry_hash;
                            else
                                Vcb->trees_ptrs[h] = NULL;
                        }
                    }

                    RemoveEntryList(&t3->list_entry_hash);

                    t3->hash = calc_crc32c(0xffffffff, (uint8_t*)&t3->header.address, sizeof(uint64_t));
                    h = t3->hash >> 24;

                    if (!Vcb->trees_ptrs[h]) {
                        uint8_t h2 = h;

                        le2 = Vcb->trees_hash.Flink;

                        if (h2 > 0) {
                            h2--;
                            do {
                                if (Vcb->trees_ptrs[h2]) {
                                    le2 = Vcb->trees_ptrs[h2];
                                    break;
                                }

                                h2--;
                            } while (h2 > 0);
                        }
                    } else
                        le2 = Vcb->trees_ptrs[h];

                    inserted = false;
                    while (le2 != &Vcb->trees_hash) {
                        tree* t2 = CONTAINING_RECORD(le2, tree, list_entry_hash);

                        if (t2->hash >= t3->hash) {
                            InsertHeadList(le2->Blink, &t3->list_entry_hash);
                            inserted = true;
                            break;
                        }

                        le2 = le2->Flink;
                    }

                    if (!inserted)
                        InsertTailList(&Vcb->trees_hash, &t3->list_entry_hash);

                    if (!Vcb->trees_ptrs[h] || t3->list_entry_hash.Flink == Vcb->trees_ptrs[h])
                        Vcb->trees_ptrs[h] = &t3->list_entry_hash;

                    if (data_items && level == 0) {
                        le2 = data_items->Flink;

                        while (le2 != data_items) {
                            data_reloc* dr = CONTAINING_RECORD(le2, data_reloc, list_entry);
                            LIST_ENTRY* le3 = t3->itemlist.Flink;

                            while (le3 != &t3->itemlist) {
                                tree_data* td = CONTAINING_RECORD(le3, tree_data, list_entry);

                                if (!td->inserted && td->key.obj_type == TYPE_EXTENT_DATA && td->size >= sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
                                    EXTENT_DATA* ed = (EXTENT_DATA*)td->data;

                                    if (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) {
                                        EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;

                                        if (ed2->address == dr->address)
                                            ed2->address = dr->new_address;
                                    }
                                }

                                le3 = le3->Flink;
                            }

                            le2 = le2->Flink;
                        }
                    }

                    t3 = t4;
                }

                calc_tree_checksum(Vcb, mr->data);

                tw = ExAllocatePoolWithTag(PagedPool, sizeof(tree_write), ALLOC_TAG);
                if (!tw) {
                    ERR("out of memory\n");
                    Status = STATUS_INSUFFICIENT_RESOURCES;
                    goto end;
                }

                tw->address = mr->new_address;
                tw->length = Vcb->superblock.node_size;
                tw->data = (uint8_t*)mr->data;
                tw->allocated = false;

                if (IsListEmpty(&tree_writes))
                    InsertTailList(&tree_writes, &tw->list_entry);
                else {
                    bool inserted = false;

                    le2 = tree_writes.Flink;
                    while (le2 != &tree_writes) {
                        tree_write* tw2 = CONTAINING_RECORD(le2, tree_write, list_entry);

                        if (tw2->address > tw->address) {
                            InsertHeadList(le2->Blink, &tw->list_entry);
                            inserted = true;
                            break;
                        }

                        le2 = le2->Flink;
                    }

                    if (!inserted)
                        InsertTailList(&tree_writes, &tw->list_entry);
                }
            }

            le = le->Flink;
        }
    }

    Status = do_tree_writes(Vcb, &tree_writes, true);
    if (!NT_SUCCESS(Status)) {
        ERR("do_tree_writes returned %08lx\n", Status);
        goto end;
    }

    le = items->Flink;
    while (le != items) {
        metadata_reloc* mr = CONTAINING_RECORD(le, metadata_reloc, list_entry);

        Status = add_metadata_reloc_extent_item(Vcb, mr);
        if (!NT_SUCCESS(Status)) {
            ERR("add_metadata_reloc_extent_item returned %08lx\n", Status);
            goto end;
        }

        le = le->Flink;
    }

    Status = STATUS_SUCCESS;

end:
    while (!IsListEmpty(&tree_writes)) {
        tree_write* tw = CONTAINING_RECORD(RemoveHeadList(&tree_writes), tree_write, list_entry);

        if (tw->allocated)
            ExFreePool(tw->data);

        ExFreePool(tw);
    }

    return Status;
}

static NTSTATUS balance_metadata_chunk(device_extension* Vcb, chunk* c, bool* changed) {
    KEY searchkey;
    traverse_ptr tp;
    NTSTATUS Status;
    bool b;
    LIST_ENTRY items, rollback;
    uint32_t loaded = 0;

    TRACE("chunk %I64x\n", c->offset);

    InitializeListHead(&rollback);
    InitializeListHead(&items);

    ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);

    searchkey.obj_id = c->offset;
    searchkey.obj_type = TYPE_METADATA_ITEM;
    searchkey.offset = 0xffffffffffffffff;

    Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, false, NULL);
    if (!NT_SUCCESS(Status)) {
        ERR("find_item returned %08lx\n", Status);
        goto end;
    }

    do {
        traverse_ptr next_tp;

        if (tp.item->key.obj_id >= c->offset + c->chunk_item->size)
            break;

        if (tp.item->key.obj_id >= c->offset && (tp.item->key.obj_type == TYPE_EXTENT_ITEM || tp.item->key.obj_type == TYPE_METADATA_ITEM)) {
            bool tree = false, skinny = false;

            if (tp.item->key.obj_type == TYPE_METADATA_ITEM && tp.item->size >= sizeof(EXTENT_ITEM)) {
                tree = true;
                skinny = true;
            } else if (tp.item->key.obj_type == TYPE_EXTENT_ITEM && tp.item->key.offset == Vcb->superblock.node_size &&
                       tp.item->size >= sizeof(EXTENT_ITEM)) {
                EXTENT_ITEM* ei = (EXTENT_ITEM*)tp.item->data;

                if (ei->flags & EXTENT_ITEM_TREE_BLOCK)
                    tree = true;
            }

            if (tree) {
                Status = add_metadata_reloc(Vcb, &items, &tp, skinny, NULL, c, &rollback);

                if (!NT_SUCCESS(Status)) {
                    ERR("add_metadata_reloc returned %08lx\n", Status);
                    goto end;
                }

                loaded++;

                if (loaded >= 64) // only do 64 at a time
                    break;
            }
        }

        b = find_next_item(Vcb, &tp, &next_tp, false, NULL);

        if (b)
            tp = next_tp;
    } while (b);

    if (IsListEmpty(&items)) {
        *changed = false;
        Status = STATUS_SUCCESS;
        goto end;
    } else
        *changed = true;

    Status = write_metadata_items(Vcb, &items, NULL, c, &rollback);
    if (!NT_SUCCESS(Status)) {
        ERR("write_metadata_items returned %08lx\n", Status);
        goto end;
    }

    Status = STATUS_SUCCESS;

    Vcb->need_write = true;

end:
    if (NT_SUCCESS(Status)) {
        Status = do_write(Vcb, NULL);
        if (!NT_SUCCESS(Status))
            ERR("do_write returned %08lx\n", Status);
    }

    if (NT_SUCCESS(Status))
        clear_rollback(&rollback);
    else
        do_rollback(Vcb, &rollback);

    free_trees(Vcb);

    ExReleaseResourceLite(&Vcb->tree_lock);

    while (!IsListEmpty(&items)) {
        metadata_reloc* mr = CONTAINING_RECORD(RemoveHeadList(&items), metadata_reloc, list_entry);

        while (!IsListEmpty(&mr->refs)) {
            metadata_reloc_ref* ref = CONTAINING_RECORD(RemoveHeadList(&mr->refs), metadata_reloc_ref, list_entry);

            ExFreePool(ref);
        }

        if (mr->data)
            ExFreePool(mr->data);

        ExFreePool(mr);
    }

    return Status;
}

static NTSTATUS data_reloc_add_tree_edr(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, LIST_ENTRY* metadata_items,
                                        data_reloc* dr, EXTENT_DATA_REF* edr, LIST_ENTRY* rollback) {
    NTSTATUS Status;
    LIST_ENTRY* le;
    KEY searchkey;
    traverse_ptr tp;
    root* r = NULL;
    metadata_reloc* mr;
    uint64_t last_tree = 0;
    data_reloc_ref* ref;

    le = Vcb->roots.Flink;
    while (le != &Vcb->roots) {
        root* r2 = CONTAINING_RECORD(le, root, list_entry);

        if (r2->id == edr->root) {
            r = r2;
            break;
        }

        le = le->Flink;
    }

    if (!r) {
        ERR("could not find subvol %I64x\n", edr->root);
        return STATUS_INTERNAL_ERROR;
    }

    searchkey.obj_id = edr->objid;
    searchkey.obj_type = TYPE_EXTENT_DATA;
    searchkey.offset = 0;

    Status = find_item(Vcb, r, &tp, &searchkey, false, NULL);
    if (!NT_SUCCESS(Status)) {
        ERR("find_item returned %08lx\n", Status);
        return Status;
    }

    if (tp.item->key.obj_id < searchkey.obj_id || (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type < searchkey.obj_type)) {
        traverse_ptr tp2;

        if (find_next_item(Vcb, &tp, &tp2, false, NULL))
            tp = tp2;
        else {
            ERR("could not find EXTENT_DATA for inode %I64x in root %I64x\n", searchkey.obj_id, r->id);
            return STATUS_INTERNAL_ERROR;
        }
    }

    ref = NULL;

    while (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
        traverse_ptr tp2;

        if (tp.item->size >= sizeof(EXTENT_DATA)) {
            EXTENT_DATA* ed = (EXTENT_DATA*)tp.item->data;

            if ((ed->type == EXTENT_TYPE_PREALLOC || ed->type == EXTENT_TYPE_REGULAR) && tp.item->size >= offsetof(EXTENT_DATA, data[0]) + sizeof(EXTENT_DATA2)) {
                EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;

                if (ed2->address == dr->address && ed2->size == dr->size && tp.item->key.offset - ed2->offset == edr->offset) {
                    if (ref && last_tree == tp.tree->header.address)
                        ref->edr.count++;
                    else {
                        ref = ExAllocatePoolWithTag(PagedPool, sizeof(data_reloc_ref), ALLOC_TAG);
                        if (!ref) {
                            ERR("out of memory\n");
                            return STATUS_INSUFFICIENT_RESOURCES;
                        }

                        ref->type = TYPE_EXTENT_DATA_REF;
                        RtlCopyMemory(&ref->edr, edr, sizeof(EXTENT_DATA_REF));
                        ref->edr.count = 1;

                        Status = add_metadata_reloc_parent(Vcb, metadata_items, tp.tree->header.address, &mr, rollback);
                        if (!NT_SUCCESS(Status)) {
                            ERR("add_metadata_reloc_parent returned %08lx\n", Status);
                            ExFreePool(ref);
                            return Status;
                        }

                        last_tree = tp.tree->header.address;
                        ref->parent = mr;

                        InsertTailList(&dr->refs, &ref->list_entry);
                    }
                }
            }
        }

        if (find_next_item(Vcb, &tp, &tp2, false, NULL))
            tp = tp2;
        else
            break;
    }

    return STATUS_SUCCESS;
}

static NTSTATUS add_data_reloc(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, LIST_ENTRY* items, LIST_ENTRY* metadata_items,
                               traverse_ptr* tp, chunk* c, LIST_ENTRY* rollback) {
    NTSTATUS Status;
    data_reloc* dr;
    EXTENT_ITEM* ei;
    uint16_t len;
    uint64_t inline_rc;
    uint8_t* ptr;

    dr = ExAllocatePoolWithTag(PagedPool, sizeof(data_reloc), ALLOC_TAG);
    if (!dr) {
        ERR("out of memory\n");
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    dr->address = tp->item->key.obj_id;
    dr->size = tp->item->key.offset;
    dr->ei = (EXTENT_ITEM*)tp->item->data;
    InitializeListHead(&dr->refs);

    Status = delete_tree_item(Vcb, tp);
    if (!NT_SUCCESS(Status)) {
        ERR("delete_tree_item returned %08lx\n", Status);
        return Status;
    }

    if (!c)
        c = get_chunk_from_address(Vcb, tp->item->key.obj_id);

    if (c) {
        acquire_chunk_lock(c, Vcb);

        c->used -= tp->item->key.offset;

        space_list_add(c, tp->item->key.obj_id, tp->item->key.offset, rollback);

        release_chunk_lock(c, Vcb);
    }

    ei = (EXTENT_ITEM*)tp->item->data;
    inline_rc = 0;

    len = tp->item->size - sizeof(EXTENT_ITEM);
    ptr = (uint8_t*)tp->item->data + sizeof(EXTENT_ITEM);

    while (len > 0) {
        uint8_t secttype = *ptr;
        uint16_t sectlen = secttype == TYPE_EXTENT_DATA_REF ? sizeof(EXTENT_DATA_REF) : (secttype == TYPE_SHARED_DATA_REF ? sizeof(SHARED_DATA_REF) : 0);

        len--;

        if (sectlen > len) {
            ERR("(%I64x,%x,%I64x): %x bytes left, expecting at least %x\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, len, sectlen);
            return STATUS_INTERNAL_ERROR;
        }

        if (sectlen == 0) {
            ERR("(%I64x,%x,%I64x): unrecognized extent type %x\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, secttype);
            return STATUS_INTERNAL_ERROR;
        }

        if (secttype == TYPE_EXTENT_DATA_REF) {
            EXTENT_DATA_REF* edr = (EXTENT_DATA_REF*)(ptr + sizeof(uint8_t));

            inline_rc += edr->count;

            Status = data_reloc_add_tree_edr(Vcb, metadata_items, dr, edr, rollback);
            if (!NT_SUCCESS(Status)) {
                ERR("data_reloc_add_tree_edr returned %08lx\n", Status);
                return Status;
            }
        } else if (secttype == TYPE_SHARED_DATA_REF) {
            metadata_reloc* mr;
            data_reloc_ref* ref;

            ref = ExAllocatePoolWithTag(PagedPool, sizeof(data_reloc_ref), ALLOC_TAG);
            if (!ref) {
                ERR("out of memory\n");
                return STATUS_INSUFFICIENT_RESOURCES;
            }

            ref->type = TYPE_SHARED_DATA_REF;
            RtlCopyMemory(&ref->sdr, ptr + sizeof(uint8_t), sizeof(SHARED_DATA_REF));
            inline_rc += ref->sdr.count;

            Status = add_metadata_reloc_parent(Vcb, metadata_items, ref->sdr.offset, &mr, rollback);
            if (!NT_SUCCESS(Status)) {
                ERR("add_metadata_reloc_parent returned %08lx\n", Status);
                ExFreePool(ref);
                return Status;
            }

            ref->parent = mr;

            InsertTailList(&dr->refs, &ref->list_entry);
        } else {
            ERR("unexpected tree type %x\n", secttype);
            return STATUS_INTERNAL_ERROR;
        }


        len -= sectlen;
        ptr += sizeof(uint8_t) + sectlen;
    }

    if (inline_rc < ei->refcount) { // look for non-inline entries
        traverse_ptr tp2 = *tp, next_tp;

        while (find_next_item(Vcb, &tp2, &next_tp, false, NULL)) {
            tp2 = next_tp;

            if (tp2.item->key.obj_id == tp->item->key.obj_id) {
                if (tp2.item->key.obj_type == TYPE_EXTENT_DATA_REF && tp2.item->size >= sizeof(EXTENT_DATA_REF)) {
                    Status = data_reloc_add_tree_edr(Vcb, metadata_items, dr, (EXTENT_DATA_REF*)tp2.item->data, rollback);
                    if (!NT_SUCCESS(Status)) {
                        ERR("data_reloc_add_tree_edr returned %08lx\n", Status);
                        return Status;
                    }

                    Status = delete_tree_item(Vcb, &tp2);
                    if (!NT_SUCCESS(Status)) {
                        ERR("delete_tree_item returned %08lx\n", Status);
                        return Status;
                    }
                } else if (tp2.item->key.obj_type == TYPE_SHARED_DATA_REF && tp2.item->size >= sizeof(uint32_t)) {
                    metadata_reloc* mr;
                    data_reloc_ref* ref;

                    ref = ExAllocatePoolWithTag(PagedPool, sizeof(data_reloc_ref), ALLOC_TAG);
                    if (!ref) {
                        ERR("out of memory\n");
                        return STATUS_INSUFFICIENT_RESOURCES;
                    }

                    ref->type = TYPE_SHARED_DATA_REF;
                    ref->sdr.offset = tp2.item->key.offset;
                    ref->sdr.count = *((uint32_t*)tp2.item->data);

                    Status = add_metadata_reloc_parent(Vcb, metadata_items, ref->sdr.offset, &mr, rollback);
                    if (!NT_SUCCESS(Status)) {
                        ERR("add_metadata_reloc_parent returned %08lx\n", Status);
                        ExFreePool(ref);
                        return Status;
                    }

                    ref->parent = mr;
                    InsertTailList(&dr->refs, &ref->list_entry);

                    Status = delete_tree_item(Vcb, &tp2);
                    if (!NT_SUCCESS(Status)) {
                        ERR("delete_tree_item returned %08lx\n", Status);
                        return Status;
                    }
                }
            } else
                break;
        }
    }

    InsertTailList(items, &dr->list_entry);

    return STATUS_SUCCESS;
}

static void sort_data_reloc_refs(data_reloc* dr) {
    LIST_ENTRY newlist, *le;

    if (IsListEmpty(&dr->refs))
        return;

    // insertion sort

    InitializeListHead(&newlist);

    while (!IsListEmpty(&dr->refs)) {
        data_reloc_ref* ref = CONTAINING_RECORD(RemoveHeadList(&dr->refs), data_reloc_ref, list_entry);
        bool inserted = false;

        if (ref->type == TYPE_EXTENT_DATA_REF)
            ref->hash = get_extent_data_ref_hash2(ref->edr.root, ref->edr.objid, ref->edr.offset);
        else if (ref->type == TYPE_SHARED_DATA_REF)
            ref->hash = ref->parent->new_address;

        le = newlist.Flink;
        while (le != &newlist) {
            data_reloc_ref* ref2 = CONTAINING_RECORD(le, data_reloc_ref, list_entry);

            if (ref->type < ref2->type || (ref->type == ref2->type && ref->hash > ref2->hash)) {
                InsertHeadList(le->Blink, &ref->list_entry);
                inserted = true;
                break;
            }

            le = le->Flink;
        }

        if (!inserted)
            InsertTailList(&newlist, &ref->list_entry);
    }

    le = newlist.Flink;
    while (le != &newlist) {
        data_reloc_ref* ref = CONTAINING_RECORD(le, data_reloc_ref, list_entry);

        if (le->Flink != &newlist) {
            data_reloc_ref* ref2 = CONTAINING_RECORD(le->Flink, data_reloc_ref, list_entry);

            if (ref->type == TYPE_EXTENT_DATA_REF && ref2->type == TYPE_EXTENT_DATA_REF && ref->edr.root == ref2->edr.root &&
                ref->edr.objid == ref2->edr.objid && ref->edr.offset == ref2->edr.offset) {
                RemoveEntryList(&ref2->list_entry);
                ref->edr.count += ref2->edr.count;
                ExFreePool(ref2);
                continue;
            }
        }

        le = le->Flink;
    }

    newlist.Flink->Blink = &dr->refs;
    newlist.Blink->Flink = &dr->refs;
    dr->refs.Flink = newlist.Flink;
    dr->refs.Blink = newlist.Blink;
}

static NTSTATUS add_data_reloc_extent_item(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, data_reloc* dr) {
    NTSTATUS Status;
    LIST_ENTRY* le;
    uint64_t rc = 0;
    uint16_t inline_len;
    bool all_inline = true;
    data_reloc_ref* first_noninline = NULL;
    EXTENT_ITEM* ei;
    uint8_t* ptr;

    inline_len = sizeof(EXTENT_ITEM);

    sort_data_reloc_refs(dr);

    le = dr->refs.Flink;
    while (le != &dr->refs) {
        data_reloc_ref* ref = CONTAINING_RECORD(le, data_reloc_ref, list_entry);
        uint16_t extlen = 0;

        if (ref->type == TYPE_EXTENT_DATA_REF) {
            extlen += sizeof(EXTENT_DATA_REF);
            rc += ref->edr.count;
        } else if (ref->type == TYPE_SHARED_DATA_REF) {
            extlen += sizeof(SHARED_DATA_REF);
            rc++;
        }

        if (all_inline) {
            if ((ULONG)(inline_len + 1 + extlen) > (Vcb->superblock.node_size >> 2)) {
                all_inline = false;
                first_noninline = ref;
            } else
                inline_len += extlen + 1;
        }

        le = le->Flink;
    }

    ei = ExAllocatePoolWithTag(PagedPool, inline_len, ALLOC_TAG);
    if (!ei) {
        ERR("out of memory\n");
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    ei->refcount = rc;
    ei->generation = dr->ei->generation;
    ei->flags = dr->ei->flags;
    ptr = (uint8_t*)&ei[1];

    le = dr->refs.Flink;
    while (le != &dr->refs) {
        data_reloc_ref* ref = CONTAINING_RECORD(le, data_reloc_ref, list_entry);

        if (ref == first_noninline)
            break;

        *ptr = ref->type;
        ptr++;

        if (ref->type == TYPE_EXTENT_DATA_REF) {
            EXTENT_DATA_REF* edr = (EXTENT_DATA_REF*)ptr;

            RtlCopyMemory(edr, &ref->edr, sizeof(EXTENT_DATA_REF));

            ptr += sizeof(EXTENT_DATA_REF);
        } else if (ref->type == TYPE_SHARED_DATA_REF) {
            SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)ptr;

            sdr->offset = ref->parent->new_address;
            sdr->count = ref->sdr.count;

            ptr += sizeof(SHARED_DATA_REF);
        }

        le = le->Flink;
    }

    Status = insert_tree_item(Vcb, Vcb->extent_root, dr->new_address, TYPE_EXTENT_ITEM, dr->size, ei, inline_len, NULL, NULL);
    if (!NT_SUCCESS(Status)) {
        ERR("insert_tree_item returned %08lx\n", Status);
        return Status;
    }

    if (!all_inline) {
        le = &first_noninline->list_entry;

        while (le != &dr->refs) {
            data_reloc_ref* ref = CONTAINING_RECORD(le, data_reloc_ref, list_entry);

            if (ref->type == TYPE_EXTENT_DATA_REF) {
                EXTENT_DATA_REF* edr;

                edr = ExAllocatePoolWithTag(PagedPool, sizeof(EXTENT_DATA_REF), ALLOC_TAG);
                if (!edr) {
                    ERR("out of memory\n");
                    return STATUS_INSUFFICIENT_RESOURCES;
                }

                RtlCopyMemory(edr, &ref->edr, sizeof(EXTENT_DATA_REF));

                Status = insert_tree_item(Vcb, Vcb->extent_root, dr->new_address, TYPE_EXTENT_DATA_REF, ref->hash, edr, sizeof(EXTENT_DATA_REF), NULL, NULL);
                if (!NT_SUCCESS(Status)) {
                    ERR("insert_tree_item returned %08lx\n", Status);
                    return Status;
                }
            } else if (ref->type == TYPE_SHARED_DATA_REF) {
                uint32_t* sdr;

                sdr = ExAllocatePoolWithTag(PagedPool, sizeof(uint32_t), ALLOC_TAG);
                if (!sdr) {
                    ERR("out of memory\n");
                    return STATUS_INSUFFICIENT_RESOURCES;
                }

                *sdr = ref->sdr.count;

                Status = insert_tree_item(Vcb, Vcb->extent_root, dr->new_address, TYPE_SHARED_DATA_REF, ref->parent->new_address, sdr, sizeof(uint32_t), NULL, NULL);
                if (!NT_SUCCESS(Status)) {
                    ERR("insert_tree_item returned %08lx\n", Status);
                    return Status;
                }
            }

            le = le->Flink;
        }
    }

    return STATUS_SUCCESS;
}

static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* changed) {
    KEY searchkey;
    traverse_ptr tp;
    NTSTATUS Status;
    bool b;
    LIST_ENTRY items, metadata_items, rollback, *le;
    uint64_t loaded = 0, num_loaded = 0;
    chunk* newchunk = NULL;
    uint8_t* data = NULL;

    TRACE("chunk %I64x\n", c->offset);

    InitializeListHead(&rollback);
    InitializeListHead(&items);
    InitializeListHead(&metadata_items);

    ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);

    searchkey.obj_id = c->offset;
    searchkey.obj_type = TYPE_EXTENT_ITEM;
    searchkey.offset = 0xffffffffffffffff;

    Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, false, NULL);
    if (!NT_SUCCESS(Status)) {
        ERR("find_item returned %08lx\n", Status);
        goto end;
    }

    do {
        traverse_ptr next_tp;

        if (tp.item->key.obj_id >= c->offset + c->chunk_item->size)
            break;

        if (tp.item->key.obj_id >= c->offset && tp.item->key.obj_type == TYPE_EXTENT_ITEM) {
            bool tree = false;

            if (tp.item->key.obj_type == TYPE_EXTENT_ITEM && tp.item->size >= sizeof(EXTENT_ITEM)) {
                EXTENT_ITEM* ei = (EXTENT_ITEM*)tp.item->data;

                if (ei->flags & EXTENT_ITEM_TREE_BLOCK)
                    tree = true;
            }

            if (!tree) {
                Status = add_data_reloc(Vcb, &items, &metadata_items, &tp, c, &rollback);

                if (!NT_SUCCESS(Status)) {
                    ERR("add_data_reloc returned %08lx\n", Status);
                    goto end;
                }

                loaded += tp.item->key.offset;
                num_loaded++;

                if (loaded >= 0x1000000 || num_loaded >= 100) // only do so much at a time, so we don't block too obnoxiously
                    break;
            }
        }

        b = find_next_item(Vcb, &tp, &next_tp, false, NULL);

        if (b)
            tp = next_tp;
    } while (b);

    if (IsListEmpty(&items)) {
        *changed = false;
        Status = STATUS_SUCCESS;
        goto end;
    } else
        *changed = true;

    data = ExAllocatePoolWithTag(PagedPool, BALANCE_UNIT, ALLOC_TAG);
    if (!data) {
        ERR("out of memory\n");
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto end;
    }

    le = items.Flink;
    while (le != &items) {
        data_reloc* dr = CONTAINING_RECORD(le, data_reloc, list_entry);
        bool done = false;
        LIST_ENTRY* le2;
        void* csum;
        RTL_BITMAP bmp;
        ULONG* bmparr;
        ULONG bmplen, runlength, index, lastoff;

        if (newchunk) {
            acquire_chunk_lock(newchunk, Vcb);

            if (find_data_address_in_chunk(Vcb, newchunk, dr->size, &dr->new_address)) {
                newchunk->used += dr->size;
                space_list_subtract(newchunk, dr->new_address, dr->size, &rollback);
                done = true;
            }

            release_chunk_lock(newchunk, Vcb);
        }

        if (!done) {
            ExAcquireResourceExclusiveLite(&Vcb->chunk_lock, true);

            le2 = Vcb->chunks.Flink;
            while (le2 != &Vcb->chunks) {
                chunk* c2 = CONTAINING_RECORD(le2, chunk, list_entry);

                if (!c2->readonly && !c2->reloc && c2 != newchunk && c2->chunk_item->type == Vcb->data_flags) {
                    acquire_chunk_lock(c2, Vcb);

                    if ((c2->chunk_item->size - c2->used) >= dr->size) {
                        if (find_data_address_in_chunk(Vcb, c2, dr->size, &dr->new_address)) {
                            c2->used += dr->size;
                            space_list_subtract(c2, dr->new_address, dr->size, &rollback);
                            release_chunk_lock(c2, Vcb);
                            newchunk = c2;
                            done = true;
                            break;
                        }
                    }

                    release_chunk_lock(c2, Vcb);
                }

                le2 = le2->Flink;
            }

            // allocate new chunk if necessary
            if (!done) {
                Status = alloc_chunk(Vcb, Vcb->data_flags, &newchunk, false);

                if (!NT_SUCCESS(Status)) {
                    ERR("alloc_chunk returned %08lx\n", Status);
                    ExReleaseResourceLite(&Vcb->chunk_lock);
                    goto end;
                }

                acquire_chunk_lock(newchunk, Vcb);

                newchunk->balance_num = Vcb->balance.balance_num;

                if (!find_data_address_in_chunk(Vcb, newchunk, dr->size, &dr->new_address)) {
                    release_chunk_lock(newchunk, Vcb);
                    ExReleaseResourceLite(&Vcb->chunk_lock);
                    ERR("could not find address in new chunk\n");
                    Status = STATUS_DISK_FULL;
                    goto end;
                } else {
                    newchunk->used += dr->size;
                    space_list_subtract(newchunk, dr->new_address, dr->size, &rollback);
                }

                release_chunk_lock(newchunk, Vcb);
            }

            ExReleaseResourceLite(&Vcb->chunk_lock);
        }

        dr->newchunk = newchunk;

        bmplen = (ULONG)(dr->size >> Vcb->sector_shift);

        bmparr = ExAllocatePoolWithTag(PagedPool, (ULONG)sector_align(bmplen + 1, sizeof(ULONG)), ALLOC_TAG);
        if (!bmparr) {
            ERR("out of memory\n");
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto end;
        }

        csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((dr->size * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
        if (!csum) {
            ERR("out of memory\n");
            ExFreePool(bmparr);
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto end;
        }

        RtlInitializeBitMap(&bmp, bmparr, bmplen);
        RtlSetAllBits(&bmp); // 1 = no csum, 0 = csum

        searchkey.obj_id = EXTENT_CSUM_ID;
        searchkey.obj_type = TYPE_EXTENT_CSUM;
        searchkey.offset = dr->address;

        Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, false, NULL);
        if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) {
            ERR("find_item returned %08lx\n", Status);
            ExFreePool(csum);
            ExFreePool(bmparr);
            goto end;
        }

        if (Status != STATUS_NOT_FOUND) {
            do {
                traverse_ptr next_tp;

                if (tp.item->key.obj_type == TYPE_EXTENT_CSUM) {
                    if (tp.item->key.offset >= dr->address + dr->size)
                        break;
                    else if (tp.item->size >= Vcb->csum_size && tp.item->key.offset + (((unsigned int)tp.item->size << Vcb->sector_shift) / Vcb->csum_size) >= dr->address) {
                        uint64_t cs = max(dr->address, tp.item->key.offset);
                        uint64_t ce = min(dr->address + dr->size, tp.item->key.offset + (((unsigned int)tp.item->size << Vcb->sector_shift) / Vcb->csum_size));

                        RtlCopyMemory((uint8_t*)csum + (((cs - dr->address) * Vcb->csum_size) >> Vcb->sector_shift),
                                      tp.item->data + (((cs - tp.item->key.offset) * Vcb->csum_size) >> Vcb->sector_shift),
                                      (ULONG)(((ce - cs) * Vcb->csum_size) >> Vcb->sector_shift));

                        RtlClearBits(&bmp, (ULONG)((cs - dr->address) >> Vcb->sector_shift), (ULONG)((ce - cs) >> Vcb->sector_shift));

                        if (ce == dr->address + dr->size)
                            break;
                    }
                }

                if (find_next_item(Vcb, &tp, &next_tp, false, NULL))
                    tp = next_tp;
                else
                    break;
            } while (true);
        }

        lastoff = 0;
        runlength = RtlFindFirstRunClear(&bmp, &index);

        while (runlength != 0) {
            if (index >= bmplen)
                break;

            if (index + runlength >= bmplen) {
                runlength = bmplen - index;

                if (runlength == 0)
                    break;
            }

            if (index > lastoff) {
                ULONG off = lastoff;
                ULONG size = index - lastoff;

                // handle no csum run
                do {
                    ULONG rl;

                    if (size << Vcb->sector_shift > BALANCE_UNIT)
                        rl = BALANCE_UNIT >> Vcb->sector_shift;
                    else
                        rl = size;

                    Status = read_data(Vcb, dr->address + (off << Vcb->sector_shift), rl << Vcb->sector_shift, NULL, false, data,
                                       c, NULL, NULL, 0, false, NormalPagePriority);
                    if (!NT_SUCCESS(Status)) {
                        ERR("read_data returned %08lx\n", Status);
                        ExFreePool(csum);
                        ExFreePool(bmparr);
                        goto end;
                    }

                    Status = write_data_complete(Vcb, dr->new_address + (off << Vcb->sector_shift), data, rl << Vcb->sector_shift,
                                                 NULL, newchunk, false, 0, NormalPagePriority);
                    if (!NT_SUCCESS(Status)) {
                        ERR("write_data_complete returned %08lx\n", Status);
                        ExFreePool(csum);
                        ExFreePool(bmparr);
                        goto end;
                    }

                    size -= rl;
                    off += rl;
                } while (size > 0);
            }

            add_checksum_entry(Vcb, dr->new_address + (index << Vcb->sector_shift), runlength, (uint8_t*)csum + (index * Vcb->csum_size), NULL);
            add_checksum_entry(Vcb, dr->address + (index << Vcb->sector_shift), runlength, NULL, NULL);

            // handle csum run
            do {
                ULONG rl;

                if (runlength << Vcb->sector_shift > BALANCE_UNIT)
                    rl = BALANCE_UNIT >> Vcb->sector_shift;
                else
                    rl = runlength;

                Status = read_data(Vcb, dr->address + (index << Vcb->sector_shift), rl << Vcb->sector_shift,
                                   (uint8_t*)csum + (index * Vcb->csum_size), false, data, c, NULL, NULL, 0, false, NormalPagePriority);
                if (!NT_SUCCESS(Status)) {
                    ERR("read_data returned %08lx\n", Status);
                    ExFreePool(csum);
                    ExFreePool(bmparr);
                    goto end;
                }

                Status = write_data_complete(Vcb, dr->new_address + (index << Vcb->sector_shift), data, rl << Vcb->sector_shift,
                                             NULL, newchunk, false, 0, NormalPagePriority);
                if (!NT_SUCCESS(Status)) {
                    ERR("write_data_complete returned %08lx\n", Status);
                    ExFreePool(csum);
                    ExFreePool(bmparr);
                    goto end;
                }

                runlength -= rl;
                index += rl;
            } while (runlength > 0);

            lastoff = index;
            runlength = RtlFindNextForwardRunClear(&bmp, index, &index);
        }

        ExFreePool(csum);
        ExFreePool(bmparr);

        // handle final nocsum run
        if (lastoff < dr->size >> Vcb->sector_shift) {
            ULONG off = lastoff;
            ULONG size = (ULONG)((dr->size >> Vcb->sector_shift) - lastoff);

            do {
                ULONG rl;

                if (size << Vcb->sector_shift > BALANCE_UNIT)
                    rl = BALANCE_UNIT >> Vcb->sector_shift;
                else
                    rl = size;

                Status = read_data(Vcb, dr->address + (off << Vcb->sector_shift), rl << Vcb->sector_shift, NULL, false, data,
                                   c, NULL, NULL, 0, false, NormalPagePriority);
                if (!NT_SUCCESS(Status)) {
                    ERR("read_data returned %08lx\n", Status);
                    goto end;
                }

                Status = write_data_complete(Vcb, dr->new_address + (off << Vcb->sector_shift), data, rl << Vcb->sector_shift,
                                             NULL, newchunk, false, 0, NormalPagePriority);
                if (!NT_SUCCESS(Status)) {
                    ERR("write_data_complete returned %08lx\n", Status);
                    goto end;
                }

                size -= rl;
                off += rl;
            } while (size > 0);
        }

        le = le->Flink;
    }

    ExFreePool(data);
    data = NULL;

    Status = write_metadata_items(Vcb, &metadata_items, &items, NULL, &rollback);
    if (!NT_SUCCESS(Status)) {
        ERR("write_metadata_items returned %08lx\n", Status);
        goto end;
    }

    le = items.Flink;
    while (le != &items) {
        data_reloc* dr = CONTAINING_RECORD(le, data_reloc, list_entry);

        Status = add_data_reloc_extent_item(Vcb, dr);
        if (!NT_SUCCESS(Status)) {
            ERR("add_data_reloc_extent_item returned %08lx\n", Status);
            goto end;
        }

        le = le->Flink;
    }

    le = c->changed_extents.Flink;
    while (le != &c->changed_extents) {
        LIST_ENTRY *le2, *le3;
        changed_extent* ce = CONTAINING_RECORD(le, changed_extent, list_entry);

        le3 = le->Flink;

        le2 = items.Flink;
        while (le2 != &items) {
            data_reloc* dr = CONTAINING_RECORD(le2, data_reloc, list_entry);

            if (ce->address == dr->address) {
                ce->address = dr->new_address;
                RemoveEntryList(&ce->list_entry);
                InsertTailList(&dr->newchunk->changed_extents, &ce->list_entry);
                break;
            }

            le2 = le2->Flink;
        }

        le = le3;
    }

    Status = STATUS_SUCCESS;

    Vcb->need_write = true;

end:
    if (NT_SUCCESS(Status)) {
        // update extents in cache inodes before we flush
        le = Vcb->chunks.Flink;
        while (le != &Vcb->chunks) {
            chunk* c2 = CONTAINING_RECORD(le, chunk, list_entry);

            if (c2->cache) {
                LIST_ENTRY* le2;

                ExAcquireResourceExclusiveLite(c2->cache->Header.Resource, true);

                le2 = c2->cache->extents.Flink;
                while (le2 != &c2->cache->extents) {
                    extent* ext = CONTAINING_RECORD(le2, extent, list_entry);

                    if (!ext->ignore) {
                        if (ext->extent_data.type == EXTENT_TYPE_REGULAR || ext->extent_data.type == EXTENT_TYPE_PREALLOC) {
                            EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;

                            if (ed2->size > 0 && ed2->address >= c->offset && ed2->address < c->offset + c->chunk_item->size) {
                                LIST_ENTRY* le3 = items.Flink;
                                while (le3 != &items) {
                                    data_reloc* dr = CONTAINING_RECORD(le3, data_reloc, list_entry);

                                    if (ed2->address == dr->address) {
                                        ed2->address = dr->new_address;
                                        break;
                                    }

                                    le3 = le3->Flink;
                                }
                            }
                        }
                    }

                    le2 = le2->Flink;
                }

                ExReleaseResourceLite(c2->cache->Header.Resource);
            }

            le = le->Flink;
        }

        Status = do_write(Vcb, NULL);
        if (!NT_SUCCESS(Status))
            ERR("do_write returned %08lx\n", Status);
    }

    if (NT_SUCCESS(Status)) {
        clear_rollback(&rollback);

        // update open FCBs
        // FIXME - speed this up(?)

        le = Vcb->all_fcbs.Flink;
        while (le != &Vcb->all_fcbs) {
            struct _fcb* fcb = CONTAINING_RECORD(le, struct _fcb, list_entry_all);
            LIST_ENTRY* le2;

            ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);

            le2 = fcb->extents.Flink;
            while (le2 != &fcb->extents) {
                extent* ext = CONTAINING_RECORD(le2, extent, list_entry);

                if (!ext->ignore) {
                    if (ext->extent_data.type == EXTENT_TYPE_REGULAR || ext->extent_data.type == EXTENT_TYPE_PREALLOC) {
                        EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;

                        if (ed2->size > 0 && ed2->address >= c->offset && ed2->address < c->offset + c->chunk_item->size) {
                            LIST_ENTRY* le3 = items.Flink;
                            while (le3 != &items) {
                                data_reloc* dr = CONTAINING_RECORD(le3, data_reloc, list_entry);

                                if (ed2->address == dr->address) {
                                    ed2->address = dr->new_address;
                                    break;
                                }

                                le3 = le3->Flink;
                            }
                        }
                    }
                }

                le2 = le2->Flink;
            }

            ExReleaseResourceLite(fcb->Header.Resource);

            le = le->Flink;
        }
    } else
        do_rollback(Vcb, &rollback);

    free_trees(Vcb);

    ExReleaseResourceLite(&Vcb->tree_lock);

    if (data)
        ExFreePool(data);

    while (!IsListEmpty(&items)) {
        data_reloc* dr = CONTAINING_RECORD(RemoveHeadList(&items), data_reloc, list_entry);

        while (!IsListEmpty(&dr->refs)) {
            data_reloc_ref* ref = CONTAINING_RECORD(RemoveHeadList(&dr->refs), data_reloc_ref, list_entry);

            ExFreePool(ref);
        }

        ExFreePool(dr);
    }

    while (!IsListEmpty(&metadata_items)) {
        metadata_reloc* mr = CONTAINING_RECORD(RemoveHeadList(&metadata_items), metadata_reloc, list_entry);

        while (!IsListEmpty(&mr->refs)) {
            metadata_reloc_ref* ref = CONTAINING_RECORD(RemoveHeadList(&mr->refs), metadata_reloc_ref, list_entry);

            ExFreePool(ref);
        }

        if (mr->data)
            ExFreePool(mr->data);

        ExFreePool(mr);
    }

    return Status;
}

static __inline uint64_t get_chunk_dup_type(chunk* c) {
    if (c->chunk_item->type & BLOCK_FLAG_RAID0)
        return BLOCK_FLAG_RAID0;
    else if (c->chunk_item->type & BLOCK_FLAG_RAID1)
        return BLOCK_FLAG_RAID1;
    else if (c->chunk_item->type & BLOCK_FLAG_DUPLICATE)
        return BLOCK_FLAG_DUPLICATE;
    else if (c->chunk_item->type & BLOCK_FLAG_RAID10)
        return BLOCK_FLAG_RAID10;
    else if (c->chunk_item->type & BLOCK_FLAG_RAID5)
        return BLOCK_FLAG_RAID5;
    else if (c->chunk_item->type & BLOCK_FLAG_RAID6)
        return BLOCK_FLAG_RAID6;
    else if (c->chunk_item->type & BLOCK_FLAG_RAID1C3)
        return BLOCK_FLAG_RAID1C3;
    else if (c->chunk_item->type & BLOCK_FLAG_RAID1C4)
        return BLOCK_FLAG_RAID1C4;
    else
        return BLOCK_FLAG_SINGLE;
}

static bool should_balance_chunk(device_extension* Vcb, uint8_t sort, chunk* c) {
    btrfs_balance_opts* opts;

    opts = &Vcb->balance.opts[sort];

    if (!(opts->flags & BTRFS_BALANCE_OPTS_ENABLED))
        return false;

    if (opts->flags & BTRFS_BALANCE_OPTS_PROFILES) {
        uint64_t type = get_chunk_dup_type(c);

        if (!(type & opts->profiles))
            return false;
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_DEVID) {
        uint16_t i;
        CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
        bool b = false;

        for (i = 0; i < c->chunk_item->num_stripes; i++) {
            if (cis[i].dev_id == opts->devid) {
                b = true;
                break;
            }
        }

        if (!b)
            return false;
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_DRANGE) {
        uint16_t i, factor;
        uint64_t physsize;
        CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
        bool b = false;

        if (c->chunk_item->type & BLOCK_FLAG_RAID0)
            factor = c->chunk_item->num_stripes;
        else if (c->chunk_item->type & BLOCK_FLAG_RAID10)
            factor = c->chunk_item->num_stripes / c->chunk_item->sub_stripes;
        else if (c->chunk_item->type & BLOCK_FLAG_RAID5)
            factor = c->chunk_item->num_stripes - 1;
        else if (c->chunk_item->type & BLOCK_FLAG_RAID6)
            factor = c->chunk_item->num_stripes - 2;
        else // SINGLE, DUPLICATE, RAID1, RAID1C3, RAID1C4
            factor = 1;

        physsize = c->chunk_item->size / factor;

        for (i = 0; i < c->chunk_item->num_stripes; i++) {
            if (cis[i].offset < opts->drange_end && cis[i].offset + physsize >= opts->drange_start &&
                (!(opts->flags & BTRFS_BALANCE_OPTS_DEVID) || cis[i].dev_id == opts->devid)) {
                b = true;
                break;
            }
        }

        if (!b)
            return false;
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_VRANGE) {
        if (c->offset + c->chunk_item->size <= opts->vrange_start || c->offset > opts->vrange_end)
            return false;
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_STRIPES) {
        if (c->chunk_item->num_stripes < opts->stripes_start || c->chunk_item->num_stripes < opts->stripes_end)
            return false;
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_USAGE) {
        uint64_t usage = c->used * 100 / c->chunk_item->size;

        // usage == 0 should mean completely empty, not just that usage rounds to 0%
        if (c->used > 0 && usage == 0)
            usage = 1;

        if (usage < opts->usage_start || usage > opts->usage_end)
            return false;
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_CONVERT && opts->flags & BTRFS_BALANCE_OPTS_SOFT) {
        uint64_t type = get_chunk_dup_type(c);

        if (type == opts->convert)
            return false;
    }

    return true;
}

static void copy_balance_args(btrfs_balance_opts* opts, BALANCE_ARGS* args) {
    if (opts->flags & BTRFS_BALANCE_OPTS_PROFILES) {
        args->profiles = opts->profiles;
        args->flags |= BALANCE_ARGS_FLAGS_PROFILES;
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_USAGE) {
        if (args->usage_start == 0) {
            args->flags |= BALANCE_ARGS_FLAGS_USAGE_RANGE;
            args->usage_start = opts->usage_start;
            args->usage_end = opts->usage_end;
        } else {
            args->flags |= BALANCE_ARGS_FLAGS_USAGE;
            args->usage = opts->usage_end;
        }
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_DEVID) {
        args->devid = opts->devid;
        args->flags |= BALANCE_ARGS_FLAGS_DEVID;
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_DRANGE) {
        args->drange_start = opts->drange_start;
        args->drange_end = opts->drange_end;
        args->flags |= BALANCE_ARGS_FLAGS_DRANGE;
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_VRANGE) {
        args->vrange_start = opts->vrange_start;
        args->vrange_end = opts->vrange_end;
        args->flags |= BALANCE_ARGS_FLAGS_VRANGE;
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_CONVERT) {
        args->convert = opts->convert;
        args->flags |= BALANCE_ARGS_FLAGS_CONVERT;

        if (opts->flags & BTRFS_BALANCE_OPTS_SOFT)
            args->flags |= BALANCE_ARGS_FLAGS_SOFT;
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_LIMIT) {
        if (args->limit_start == 0) {
            args->flags |= BALANCE_ARGS_FLAGS_LIMIT_RANGE;
            args->limit_start = (uint32_t)opts->limit_start;
            args->limit_end = (uint32_t)opts->limit_end;
        } else {
            args->flags |= BALANCE_ARGS_FLAGS_LIMIT;
            args->limit = opts->limit_end;
        }
    }

    if (opts->flags & BTRFS_BALANCE_OPTS_STRIPES) {
        args->stripes_start = opts->stripes_start;
        args->stripes_end = opts->stripes_end;
        args->flags |= BALANCE_ARGS_FLAGS_STRIPES_RANGE;
    }
}

static NTSTATUS add_balance_item(device_extension* Vcb) {
    KEY searchkey;
    traverse_ptr tp;
    NTSTATUS Status;
    BALANCE_ITEM* bi;

    searchkey.obj_id = BALANCE_ITEM_ID;
    searchkey.obj_type = TYPE_TEMP_ITEM;
    searchkey.offset = 0;

    ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);

    Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, NULL);
    if (!NT_SUCCESS(Status)) {
        ERR("find_item returned %08lx\n", Status);
        goto end;
    }

    if (!keycmp(tp.item->key, searchkey)) {
        Status = delete_tree_item(Vcb, &tp);
        if (!NT_SUCCESS(Status)) {
            ERR("delete_tree_item returned %08lx\n", Status);
            goto end;
        }
    }

    bi = ExAllocatePoolWithTag(PagedPool, sizeof(BALANCE_ITEM), ALLOC_TAG);
    if (!bi) {
        ERR("out of memory\n");
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto end;
    }

    RtlZeroMemory(bi, sizeof(BALANCE_ITEM));

    if (Vcb->balance.opts[BALANCE_OPTS_DATA].flags & BTRFS_BALANCE_OPTS_ENABLED) {
        bi->flags |= BALANCE_FLAGS_DATA;
        copy_balance_args(&Vcb->balance.opts[BALANCE_OPTS_DATA], &bi->data);
    }

    if (Vcb->balance.opts[BALANCE_OPTS_METADATA].flags & BTRFS_BALANCE_OPTS_ENABLED) {
        bi->flags |= BALANCE_FLAGS_METADATA;
        copy_balance_args(&Vcb->balance.opts[BALANCE_OPTS_METADATA], &bi->metadata);
    }

    if (Vcb->balance.opts[BALANCE_OPTS_SYSTEM].flags & BTRFS_BALANCE_OPTS_ENABLED) {
        bi->flags |= BALANCE_FLAGS_SYSTEM;
        copy_balance_args(&Vcb->balance.opts[BALANCE_OPTS_SYSTEM], &bi->system);
    }

    Status = insert_tree_item(Vcb, Vcb->root_root, BALANCE_ITEM_ID, TYPE_TEMP_ITEM, 0, bi, sizeof(BALANCE_ITEM), NULL, NULL);
    if (!NT_SUCCESS(Status)) {
        ERR("insert_tree_item returned %08lx\n", Status);
        ExFreePool(bi);
        goto end;
    }

    Status = STATUS_SUCCESS;

end:
    if (NT_SUCCESS(Status)) {
        Status = do_write(Vcb, NULL);
        if (!NT_SUCCESS(Status))
            ERR("do_write returned %08lx\n", Status);
    }

    free_trees(Vcb);

    ExReleaseResourceLite(&Vcb->tree_lock);

    return Status;
}

static NTSTATUS remove_balance_item(device_extension* Vcb) {
    KEY searchkey;
    traverse_ptr tp;
    NTSTATUS Status;

    searchkey.obj_id = BALANCE_ITEM_ID;
    searchkey.obj_type = TYPE_TEMP_ITEM;
    searchkey.offset = 0;

    ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);

    Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, NULL);
    if (!NT_SUCCESS(Status)) {
        ERR("find_item returned %08lx\n", Status);
        goto end;
    }

    if (!keycmp(tp.item->key, searchkey)) {
        Status = delete_tree_item(Vcb, &tp);
        if (!NT_SUCCESS(Status)) {
            ERR("delete_tree_item returned %08lx\n", Status);
            goto end;
        }

        Status = do_write(Vcb, NULL);
        if (!NT_SUCCESS(Status)) {
            ERR("do_write returned %08lx\n", Status);
            goto end;
        }

        free_trees(Vcb);
    }

    Status = STATUS_SUCCESS;

end:
    ExReleaseResourceLite(&Vcb->tree_lock);

    return Status;
}

static void load_balance_args(btrfs_balance_opts* opts, BALANCE_ARGS* args) {
    opts->flags = BTRFS_BALANCE_OPTS_ENABLED;

    if (args->flags & BALANCE_ARGS_FLAGS_PROFILES) {
        opts->flags |= BTRFS_BALANCE_OPTS_PROFILES;
        opts->profiles = args->profiles;
    }

    if (args->flags & BALANCE_ARGS_FLAGS_USAGE) {
        opts->flags |= BTRFS_BALANCE_OPTS_USAGE;

        opts->usage_start = 0;
        opts->usage_end = (uint8_t)args->usage;
    } else if (args->flags & BALANCE_ARGS_FLAGS_USAGE_RANGE) {
        opts->flags |= BTRFS_BALANCE_OPTS_USAGE;

        opts->usage_start = (uint8_t)args->usage_start;
        opts->usage_end = (uint8_t)args->usage_end;
    }

    if (args->flags & BALANCE_ARGS_FLAGS_DEVID) {
        opts->flags |= BTRFS_BALANCE_OPTS_DEVID;
        opts->devid = args->devid;
    }

    if (args->flags & BALANCE_ARGS_FLAGS_DRANGE) {
        opts->flags |= BTRFS_BALANCE_OPTS_DRANGE;
        opts->drange_start = args->drange_start;
        opts->drange_end = args->drange_end;
    }

    if (args->flags & BALANCE_ARGS_FLAGS_VRANGE) {
        opts->flags |= BTRFS_BALANCE_OPTS_VRANGE;
        opts->vrange_start = args->vrange_start;
        opts->vrange_end = args->vrange_end;
    }

    if (args->flags & BALANCE_ARGS_FLAGS_LIMIT) {
        opts->flags |= BTRFS_BALANCE_OPTS_LIMIT;

        opts->limit_start = 0;
        opts->limit_end = args->limit;
    } else if (args->flags & BALANCE_ARGS_FLAGS_LIMIT_RANGE) {
        opts->flags |= BTRFS_BALANCE_OPTS_LIMIT;

        opts->limit_start = args->limit_start;
        opts->limit_end = args->limit_end;
    }

    if (args->flags & BALANCE_ARGS_FLAGS_STRIPES_RANGE) {
        opts->flags |= BTRFS_BALANCE_OPTS_STRIPES;

        opts->stripes_start = (uint16_t)args->stripes_start;
        opts->stripes_end = (uint16_t)args->stripes_end;
    }

    if (args->flags & BALANCE_ARGS_FLAGS_CONVERT) {
        opts->flags |= BTRFS_BALANCE_OPTS_CONVERT;
        opts->convert = args->convert;

        if (args->flags & BALANCE_ARGS_FLAGS_SOFT)
            opts->flags |= BTRFS_BALANCE_OPTS_SOFT;
    }
}

static NTSTATUS remove_superblocks(device* dev) {
    NTSTATUS Status;
    superblock* sb;
    int i = 0;

    sb = ExAllocatePoolWithTag(PagedPool, sizeof(superblock), ALLOC_TAG);
    if (!sb) {
        ERR("out of memory\n");
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    RtlZeroMemory(sb, sizeof(superblock));

    while (superblock_addrs[i] > 0 && dev->devitem.num_bytes >= superblock_addrs[i] + sizeof(superblock)) {
        Status = write_data_phys(dev->devobj, dev->fileobj, superblock_addrs[i], sb, sizeof(superblock));

        if (!NT_SUCCESS(Status)) {
            ExFreePool(sb);
            return Status;
        }

        i++;
    }

    ExFreePool(sb);

    return STATUS_SUCCESS;
}

static NTSTATUS finish_removing_device(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, device* dev) {
    KEY searchkey;
    traverse_ptr tp;
    NTSTATUS Status;
    LIST_ENTRY* le;
    volume_device_extension* vde;

    if (Vcb->need_write) {
        Status = do_write(Vcb, NULL);

        if (!NT_SUCCESS(Status))
            ERR("do_write returned %08lx\n", Status);
    } else
        Status = STATUS_SUCCESS;

    free_trees(Vcb);

    if (!NT_SUCCESS(Status))
        return Status;

    // remove entry in chunk tree

    searchkey.obj_id = 1;
    searchkey.obj_type = TYPE_DEV_ITEM;
    searchkey.offset = dev->devitem.dev_id;

    Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, false, NULL);
    if (!NT_SUCCESS(Status)) {
        ERR("find_item returned %08lx\n", Status);
        return Status;
    }

    if (!keycmp(searchkey, tp.item->key)) {
        Status = delete_tree_item(Vcb, &tp);

        if (!NT_SUCCESS(Status)) {
            ERR("delete_tree_item returned %08lx\n", Status);
            return Status;
        }
    }

    // remove stats entry in device tree

    searchkey.obj_id = 0;
    searchkey.obj_type = TYPE_DEV_STATS;
    searchkey.offset = dev->devitem.dev_id;

    Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, false, NULL);
    if (!NT_SUCCESS(Status)) {
        ERR("find_item returned %08lx\n", Status);
        return Status;
    }

    if (!keycmp(searchkey, tp.item->key)) {
        Status = delete_tree_item(Vcb, &tp);

        if (!NT_SUCCESS(Status)) {
            ERR("delete_tree_item returned %08lx\n", Status);
            return Status;
        }
    }

    // update superblock

    Vcb->superblock.num_devices--;
    Vcb->superblock.total_bytes -= dev->devitem.num_bytes;
    Vcb->devices_loaded--;

    RemoveEntryList(&dev->list_entry);

    // flush

    Status = do_write(Vcb, NULL);
    if (!NT_SUCCESS(Status))
        ERR("do_write returned %08lx\n", Status);

    free_trees(Vcb);

    if (!NT_SUCCESS(Status))
        return Status;

    if (!dev->readonly && dev->devobj) {
        Status = remove_superblocks(dev);
        if (!NT_SUCCESS(Status))
            WARN("remove_superblocks returned %08lx\n", Status);
    }

    // remove entry in volume list

    vde = Vcb->vde;

    if (dev->devobj) {
        pdo_device_extension* pdode = vde->pdode;

        ExAcquireResourceExclusiveLite(&pdode->child_lock, true);

        le = pdode->children.Flink;
        while (le != &pdode->children) {
            volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);

            if (RtlCompareMemory(&dev->devitem.device_uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
                PFILE_OBJECT FileObject;
                PDEVICE_OBJECT mountmgr;
                UNICODE_STRING mmdevpath;

                pdode->children_loaded--;

                if (vc->had_drive_letter) { // re-add entry to mountmgr
                    RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
                    Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject, &mountmgr);
                    if (!NT_SUCCESS(Status))
                        ERR("IoGetDeviceObjectPointer returned %08lx
Download .txt
gitextract_g2azv67f/

├── .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
    │   ├── 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
Download .txt
SYMBOL INDEX (1292 symbols across 80 files)

FILE: src/balance.c
  type metadata_reloc (line 23) | typedef struct {
  type metadata_reloc_ref (line 34) | typedef struct {
  type data_reloc (line 48) | typedef struct {
  type data_reloc_ref (line 58) | typedef struct {
  function NTSTATUS (line 73) | static NTSTATUS add_metadata_reloc(_Requires_exclusive_lock_held_(_Curr_...
  function NTSTATUS (line 226) | static NTSTATUS add_metadata_reloc_parent(_Requires_exclusive_lock_held_...
  function sort_metadata_reloc_refs (line 280) | static void sort_metadata_reloc_refs(metadata_reloc* mr) {
  function NTSTATUS (line 322) | static NTSTATUS add_metadata_reloc_extent_item(_Requires_exclusive_lock_...
  function NTSTATUS (line 566) | static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Cur...
  function NTSTATUS (line 1100) | static NTSTATUS balance_metadata_chunk(device_extension* Vcb, chunk* c, ...
  function NTSTATUS (line 1217) | static NTSTATUS data_reloc_add_tree_edr(_Requires_lock_held_(_Curr_->tre...
  function NTSTATUS (line 1316) | static NTSTATUS add_data_reloc(_Requires_exclusive_lock_held_(_Curr_->tr...
  function sort_data_reloc_refs (line 1480) | static void sort_data_reloc_refs(data_reloc* dr) {
  function NTSTATUS (line 1541) | static NTSTATUS add_data_reloc_extent_item(_Requires_exclusive_lock_held...
  function NTSTATUS (line 1671) | static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool...
  function get_chunk_dup_type (line 2204) | static __inline uint64_t get_chunk_dup_type(chunk* c) {
  function should_balance_chunk (line 2225) | static bool should_balance_chunk(device_extension* Vcb, uint8_t sort, ch...
  function copy_balance_args (line 2318) | static void copy_balance_args(btrfs_balance_opts* opts, BALANCE_ARGS* ar...
  function NTSTATUS (line 2378) | static NTSTATUS add_balance_item(device_extension* Vcb) {
  function NTSTATUS (line 2451) | static NTSTATUS remove_balance_item(device_extension* Vcb) {
  function load_balance_args (line 2492) | static void load_balance_args(btrfs_balance_opts* opts, BALANCE_ARGS* ar...
  function NTSTATUS (line 2557) | static NTSTATUS remove_superblocks(device* dev) {
  function NTSTATUS (line 2586) | static NTSTATUS finish_removing_device(_Requires_exclusive_lock_held_(_C...
  function trim_unalloc_space (line 2802) | static void trim_unalloc_space(_Requires_lock_held_(_Curr_->tree_lock) d...
  function NTSTATUS (line 2902) | static NTSTATUS try_consolidation(device_extension* Vcb, uint64_t flags,...
  function NTSTATUS (line 2997) | static NTSTATUS regenerate_space_list(device_extension* Vcb, device* dev) {
  function balance_thread (line 3047) | _Function_class_(KSTART_ROUTINE)
  function NTSTATUS (line 3511) | NTSTATUS start_balance(device_extension* Vcb, void* data, ULONG length, ...
  function NTSTATUS (line 3628) | NTSTATUS look_for_balance_item(_Requires_lock_held_(_Curr_->tree_lock) d...
  function NTSTATUS (line 3711) | NTSTATUS query_balance(device_extension* Vcb, void* data, ULONG length) {
  function NTSTATUS (line 3749) | NTSTATUS pause_balance(device_extension* Vcb, KPROCESSOR_MODE processor_...
  function NTSTATUS (line 3765) | NTSTATUS resume_balance(device_extension* Vcb, KPROCESSOR_MODE processor...
  function NTSTATUS (line 3784) | NTSTATUS stop_balance(device_extension* Vcb, KPROCESSOR_MODE processor_m...
  function NTSTATUS (line 3799) | NTSTATUS remove_device(device_extension* Vcb, void* data, ULONG length, ...

FILE: src/blake2-impl.h
  function BLAKE2_INLINE (line 34) | static BLAKE2_INLINE uint32_t load32( const void *src )
  function BLAKE2_INLINE (line 49) | static BLAKE2_INLINE uint64_t load64( const void *src )
  function BLAKE2_INLINE (line 68) | static BLAKE2_INLINE uint16_t load16( const void *src )
  function BLAKE2_INLINE (line 81) | static BLAKE2_INLINE void store16( void *dst, uint16_t w )
  function BLAKE2_INLINE (line 92) | static BLAKE2_INLINE void store32( void *dst, uint32_t w )
  function BLAKE2_INLINE (line 105) | static BLAKE2_INLINE void store64( void *dst, uint64_t w )
  function BLAKE2_INLINE (line 122) | static BLAKE2_INLINE uint64_t load48( const void *src )
  function BLAKE2_INLINE (line 133) | static BLAKE2_INLINE void store48( void *dst, uint64_t w )
  function BLAKE2_INLINE (line 144) | static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c )
  function BLAKE2_INLINE (line 149) | static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c )
  type blake2b_constant (line 160) | enum blake2b_constant
  type blake2b_state (line 169) | typedef struct blake2b_state__
  type blake2b_param__ (line 180) | struct blake2b_param__
  type blake2b_param (line 196) | typedef struct blake2b_param__ blake2b_param;

FILE: src/blake2b-ref.c
  function blake2b_set_lastnode (line 48) | static void blake2b_set_lastnode( blake2b_state *S )
  function blake2b_is_lastblock (line 54) | static int blake2b_is_lastblock( const blake2b_state *S )
  function blake2b_set_lastblock (line 59) | static void blake2b_set_lastblock( blake2b_state *S )
  function blake2b_increment_counter (line 66) | static void blake2b_increment_counter( blake2b_state *S, const uint64_t ...
  function blake2b_init0 (line 72) | static void blake2b_init0( blake2b_state *S )
  function blake2b_init_param (line 81) | static void blake2b_init_param( blake2b_state *S, const blake2b_param *P )
  function blake2b_init (line 97) | static void blake2b_init( blake2b_state *S, size_t outlen )
  function blake2b_compress (line 141) | static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAK...
  function blake2b_update (line 185) | static int blake2b_update( blake2b_state *S, const void *pin, size_t inl...
  function blake2b_final (line 212) | static int blake2b_final( blake2b_state *S, void *out, size_t outlen )
  function blake2b (line 237) | void blake2b( void *out, size_t outlen, const void *in, size_t inlen )

FILE: src/boot.c
  type DEVOBJ_EXTENSION2 (line 36) | typedef struct {
  function get_system_root (line 45) | static bool get_system_root() {
  function mountmgr_notification (line 176) | static void mountmgr_notification(BTRFS_UUID* uuid) {
  function check_boot_options (line 228) | static void check_boot_options() {
  function boot_add_device (line 314) | void boot_add_device(DEVICE_OBJECT* pdo) {
  function check_system_root (line 332) | void check_system_root() {

FILE: src/btrfs.c
  type read_context (line 130) | typedef struct {
  function dbg_completion (line 139) | _Function_class_(IO_COMPLETION_ROUTINE)
  function _debug_message (line 154) | void _debug_message(_In_ const char* func, _In_ const char* file, _In_ u...
  function else (line 522) | else if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
  function calculate_total_space (line 620) | static void calculate_total_space(_In_ device_extension* Vcb, _Out_ uint...
  function compare_strings (line 650) | static bool compare_strings(const UNICODE_STRING* us1, const UNICODE_STR...
  function lie_about_fs_type (line 687) | static bool lie_about_fs_type() {
  function NTSTATUS (line 810) | NTSTATUS utf8_to_utf16(WCHAR* dest, ULONG dest_max, ULONG* dest_len, cha...
  function NTSTATUS (line 893) | NTSTATUS utf16_to_utf8(char* dest, ULONG dest_max, ULONG* dest_len, WCHA...
  function read_completion (line 1249) | _Function_class_(IO_COMPLETION_ROUTINE)
  function NTSTATUS (line 1261) | NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lo...
  function NTSTATUS (line 1382) | static NTSTATUS set_label(_In_ device_extension* Vcb, _In_ FILE_FS_LABEL...
  function send_notification_fileref (line 1507) | void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter...
  function send_notification_fcb (line 1547) | static void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG fil...
  type notification_fcb (line 1630) | typedef struct {
  function notification_work_item (line 1638) | _Function_class_(IO_WORKITEM_ROUTINE)
  function queue_notification_fcb (line 1657) | void queue_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_ma...
  function mark_fcb_dirty (line 1685) | void mark_fcb_dirty(_In_ fcb* fcb) {
  function mark_fileref_dirty (line 1707) | void mark_fileref_dirty(_In_ file_ref* fileref) {
  function _free_fcb (line 1721) | void _free_fcb(_Inout_ fcb* fcb, _In_ const char* func) {
  function get_file_attributes_from_xattr (line 2627) | _Success_(return)
  function ULONG (line 2654) | ULONG get_file_attributes(_In_ _Requires_lock_held_(_Curr_->tree_lock) d...
  function NTSTATUS (line 2722) | NTSTATUS sync_read_phys(_In_ PDEVICE_OBJECT DeviceObject, _In_ PFILE_OBJ...
  function check_superblock_checksum (line 2813) | bool check_superblock_checksum(superblock* sb) {
  function NTSTATUS (line 2870) | static NTSTATUS read_superblock(_In_ device_extension* Vcb, _In_ PDEVICE...
  function NTSTATUS (line 2942) | NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlC...
  function NTSTATUS (line 2983) | static NTSTATUS add_root(_Inout_ device_extension* Vcb, _In_ uint64_t id...
  function NTSTATUS (line 3076) | static NTSTATUS look_for_roots(_Requires_exclusive_lock_held_(_Curr_->tr...
  function NTSTATUS (line 3200) | static NTSTATUS find_disk_holes(_In_ _Requires_lock_held_(_Curr_->tree_l...
  function add_device_to_list (line 3272) | static void add_device_to_list(_In_ device_extension* Vcb, _In_ device* ...
  function _Ret_maybenull_ (line 3291) | _Ret_maybenull_
  function is_device_removable (line 3375) | static bool is_device_removable(_In_ PDEVICE_OBJECT devobj) {
  function ULONG (line 3389) | static ULONG get_device_change_count(_In_ PDEVICE_OBJECT devobj) {
  function init_device (line 3409) | void init_device(_In_ device_extension* Vcb, _Inout_ device* dev, _In_ b...
  function NTSTATUS (line 3506) | static NTSTATUS load_chunk_root(_In_ _Requires_lock_held_(_Curr_->tree_l...
  function protect_superblocks (line 3770) | void protect_superblocks(_Inout_ chunk* c) {
  function NTSTATUS (line 3869) | NTSTATUS find_chunk_usage(_In_ _Requires_lock_held_(_Curr_->tree_lock) d...
  function NTSTATUS (line 3927) | static NTSTATUS load_sys_chunks(_In_ device_extension* Vcb) {
  function _Ret_maybenull_ (line 3984) | _Ret_maybenull_
  function init_file_cache (line 4073) | void init_file_cache(_In_ PFILE_OBJECT FileObject, _In_ CC_FILE_SIZES* c...
  function get_num_of_processors (line 4084) | uint32_t get_num_of_processors() {
  function NTSTATUS (line 4098) | static NTSTATUS create_calc_threads(_In_ PDEVICE_OBJECT DeviceObject) {
  function is_btrfs_volume (line 4145) | static bool is_btrfs_volume(_In_ PDEVICE_OBJECT DeviceObject) {
  function NTSTATUS (line 4182) | static NTSTATUS get_device_pnp_name_guid(_In_ PDEVICE_OBJECT DeviceObjec...
  function NTSTATUS (line 4237) | NTSTATUS get_device_pnp_name(_In_ PDEVICE_OBJECT DeviceObject, _Out_ PUN...
  function NTSTATUS (line 4262) | static NTSTATUS check_mount_device(_In_ PDEVICE_OBJECT DeviceObject, _Ou...
  function still_has_superblock (line 4316) | static bool still_has_superblock(_In_ PDEVICE_OBJECT device, _In_ PFILE_...
  function calculate_sector_shift (line 4367) | static void calculate_sector_shift(device_extension* Vcb) {
  function NTSTATUS (line 4378) | static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Ir...
  function NTSTATUS (line 5110) | static NTSTATUS verify_device(_In_ device_extension* Vcb, _Inout_ device...
  function NTSTATUS (line 5202) | static NTSTATUS verify_volume(_In_ PDEVICE_OBJECT devobj) {
  function do_shutdown (line 5391) | void do_shutdown(PIRP Irp) {
  function device_still_valid (line 5545) | static bool device_still_valid(device* dev, uint64_t expected_generation) {
  function check_after_wakeup (line 5587) | _Function_class_(IO_WORKITEM_ROUTINE)
  function _Function_class_ (line 5653) | _Dispatch_type_(IRP_MJ_POWER)
  function else (line 5715) | else if (Vcb && Vcb->type == VCB_TYPE_FS) {
  function else (line 5721) | else if (Vcb && Vcb->type == VCB_TYPE_BUS) {
  function NTSTATUS (line 5796) | NTSTATUS check_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix,...
  function chunk_lock_range (line 5843) | void chunk_lock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ ui...
  function chunk_unlock_range (line 5890) | void chunk_unlock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ ...
  function log_device_error (line 5913) | void log_device_error(_In_ device_extension* Vcb, _Inout_ device* dev, _...
  function serial_thread (line 5920) | _Function_class_(KSTART_ROUTINE)
  function init_serial (line 5951) | static void init_serial(bool first_time) {
  function check_cpu (line 5974) | static void check_cpu() {
  function check_cpu (line 6024) | static void check_cpu() {
  function init_logging (line 6033) | static void init_logging() {
  function degraded_wait_thread (line 6116) | _Function_class_(KSTART_ROUTINE)
  function AddDevice (line 6139) | _Function_class_(DRIVER_ADD_DEVICE)
  function DriverEntry (line 6282) | _Function_class_(DRIVER_INITIALIZE)

FILE: src/btrfs.h
  type BTRFS_UUID (line 144) | typedef struct {
  type KEY (line 148) | typedef struct {
  type tree_header (line 158) | typedef struct {
  type leaf_node (line 170) | typedef struct {
  type internal_node (line 176) | typedef struct {
  type DEV_ITEM (line 182) | typedef struct {
  type superblock_backup (line 202) | typedef struct {
  type superblock (line 228) | typedef struct {
  type DIR_ITEM (line 277) | typedef struct {
  type BTRFS_TIME (line 286) | typedef struct {
  type INODE_ITEM (line 291) | typedef struct {
  type ROOT_ITEM (line 314) | typedef struct {
  type CHUNK_ITEM (line 342) | typedef struct {
  type CHUNK_ITEM_STRIPE (line 354) | typedef struct {
  type EXTENT_DATA (line 360) | typedef struct {
  type EXTENT_DATA2 (line 370) | typedef struct {
  type INODE_REF (line 377) | typedef struct {
  type INODE_EXTREF (line 383) | typedef struct {
  type EXTENT_ITEM (line 394) | typedef struct {
  type EXTENT_ITEM2 (line 400) | typedef struct {
  type EXTENT_ITEM_V0 (line 405) | typedef struct {
  type EXTENT_ITEM_TREE (line 409) | typedef struct {
  type TREE_BLOCK_REF (line 415) | typedef struct {
  type EXTENT_DATA_REF (line 419) | typedef struct {
  type BLOCK_GROUP_ITEM (line 426) | typedef struct {
  type EXTENT_REF_V0 (line 432) | typedef struct {
  type SHARED_BLOCK_REF (line 439) | typedef struct {
  type SHARED_DATA_REF (line 443) | typedef struct {
  type FREE_SPACE_ENTRY (line 451) | typedef struct {
  type FREE_SPACE_ITEM (line 457) | typedef struct {
  type ROOT_REF (line 464) | typedef struct {
  type DEV_EXTENT (line 471) | typedef struct {
  type BALANCE_ARGS (line 495) | typedef struct {
  type BALANCE_ITEM (line 527) | typedef struct {
  type FREE_SPACE_INFO (line 537) | typedef struct {
  type btrfs_send_header (line 598) | typedef struct {
  type btrfs_send_command (line 603) | typedef struct {
  type btrfs_send_tlv (line 609) | typedef struct {

FILE: src/btrfs_drv.h
  type FILE_ID_128 (line 144) | typedef struct _FILE_ID_128 {
  type DUPLICATE_EXTENTS_DATA (line 151) | typedef struct _DUPLICATE_EXTENTS_DATA {
  type FSCTL_GET_INTEGRITY_INFORMATION_BUFFER (line 160) | typedef struct _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER {
  type FSCTL_SET_INTEGRITY_INFORMATION_BUFFER (line 168) | typedef struct _FSCTL_SET_INTEGRITY_INFORMATION_BUFFER {
  type _device_extension (line 189) | struct _device_extension
  type fcb_nonpaged (line 191) | typedef struct _fcb_nonpaged {
  type _root (line 199) | struct _root
  type extent (line 201) | typedef struct {
  type hardlink (line 214) | typedef struct {
  type _file_ref (line 222) | struct _file_ref
  type dir_child (line 224) | typedef struct {
  type prop_compression_type (line 241) | enum prop_compression_type {
  type xattr (line 248) | typedef struct {
  type fcb (line 256) | typedef struct _fcb {
  type file_ref (line 315) | typedef struct _file_ref {
  type send_info (line 335) | typedef struct {
  type ccb (line 344) | typedef struct _ccb {
  type _device_extension (line 370) | struct _device_extension
  type tree_holder (line 372) | typedef struct {
  type tree_data (line 378) | typedef struct _tree_data {
  type tree_nonpaged (line 394) | typedef struct {
  type tree (line 398) | typedef struct _tree {
  type root_nonpaged (line 420) | typedef struct {
  type root (line 424) | typedef struct _root {
  type batch_operation (line 444) | enum batch_operation {
  type batch_item (line 460) | typedef struct {
  type batch_item_ind (line 468) | typedef struct {
  type batch_root (line 475) | typedef struct {
  type traverse_ptr (line 481) | typedef struct {
  type root_cache (line 486) | typedef struct _root_cache {
  type space (line 491) | typedef struct {
  type device (line 498) | typedef struct {
  type range_lock (line 519) | typedef struct {
  type partial_stripe (line 526) | typedef struct {
  type chunk (line 535) | typedef struct {
  type changed_extent (line 570) | typedef struct {
  type changed_extent_ref (line 583) | typedef struct {
  type sys_chunk (line 594) | typedef struct {
  type calc_thread_type (line 601) | enum calc_thread_type {
  type calc_job (line 614) | typedef struct {
  type drv_calc_thread (line 625) | typedef struct {
  type drv_calc_threads (line 633) | typedef struct {
  type mount_options (line 641) | typedef struct {
  type balance_info (line 671) | typedef struct {
  type scrub_error (line 687) | typedef struct {
  type scrub_info (line 711) | typedef struct {
  type _volume_device_extension (line 730) | struct _volume_device_extension
  type device_extension (line 732) | typedef struct _device_extension {
  type control_device_extension (line 817) | typedef struct {
  type bus_device_extension (line 821) | typedef struct {
  type volume_child (line 828) | typedef struct {
  type pdo_device_extension (line 845) | struct pdo_device_extension
  type volume_device_extension (line 847) | typedef struct _volume_device_extension {
  type pdo_device_extension (line 861) | typedef struct pdo_device_extension {
  type uid_map (line 877) | typedef struct {
  type gid_map (line 883) | typedef struct {
  type write_data_status (line 889) | enum write_data_status {
  type _write_data_context (line 898) | struct _write_data_context
  type write_data_stripe (line 900) | typedef struct {
  type write_data_context (line 911) | typedef struct _write_data_context {
  type tree_write (line 920) | typedef struct {
  type name_bit (line 929) | typedef struct {
  function acquire_fcb_lock_shared (line 936) | static __inline void acquire_fcb_lock_shared(device_extension* Vcb) {
  function acquire_fcb_lock_exclusive (line 942) | static __inline void acquire_fcb_lock_exclusive(device_extension* Vcb) {
  function release_fcb_lock (line 948) | static __inline void release_fcb_lock(device_extension* Vcb) {
  function unix_time_to_win (line 960) | static __inline uint64_t unix_time_to_win(BTRFS_TIME* t) {
  function win_time_to_unix (line 964) | static __inline void win_time_to_unix(LARGE_INTEGER t, BTRFS_TIME* out) {
  function get_raid0_offset (line 972) | static __inline void get_raid0_offset(_In_ uint64_t off, _In_ uint64_t s...
  function make_file_id (line 987) | static __inline uint64_t make_file_id(root* r, uint64_t inode) {
  function sector_align (line 1001) | __inline static uint64_t sector_align(_In_ uint64_t n, _In_ uint64_t a) {
  function is_subvol_readonly (line 1008) | __inline static bool is_subvol_readonly(root* r, PIRP Irp) {
  function get_extent_data_len (line 1018) | __inline static uint16_t get_extent_data_len(uint8_t type) {
  function get_extent_data_refcount (line 1040) | __inline static uint32_t get_extent_data_refcount(uint8_t type, void* da...
  type rollback_space (line 1229) | typedef struct {
  type rollback_extent (line 1237) | typedef struct {
  type rollback_type (line 1242) | enum rollback_type {
  type rollback_item (line 1249) | typedef struct {
  type ea_item (line 1255) | typedef struct {
  function _Function_class_ (line 1333) | _Dispatch_type_(IRP_MJ_WRITE)
  function POPLOCK (line 1635) | static __inline POPLOCK fcb_oplock(fcb* fcb) {
  function FAST_IO_POSSIBLE (line 1642) | static __inline FAST_IO_POSSIBLE fast_io_possible(fcb* fcb) {
  function print_open_trees (line 1652) | static __inline void print_open_trees(device_extension* Vcb) {
  function write_fcb_compressed (line 1664) | static __inline bool write_fcb_compressed(fcb* fcb) {
  function fcb_alloc_size (line 1777) | static __inline uint64_t fcb_alloc_size(fcb* fcb) {
  type BOOLEAN (line 1786) | typedef BOOLEAN (__stdcall *tPsIsDiskCountersEnabled)();
  type VOID (line 1788) | typedef VOID (__stdcall *tPsUpdateDiskCounters)(PEPROCESS Process, ULONG...
  type BOOLEAN (line 1791) | typedef BOOLEAN (__stdcall *tCcCopyWriteEx)(PFILE_OBJECT FileObject, PLA...
  type BOOLEAN (line 1794) | typedef BOOLEAN (__stdcall *tCcCopyReadEx)(PFILE_OBJECT FileObject, PLAR...
  type VOID (line 1801) | typedef VOID (__stdcall *tCcSetAdditionalCacheAttributesEx)(PFILE_OBJECT...
  type VOID (line 1803) | typedef VOID (__stdcall *tFsRtlUpdateDiskCounters)(ULONG64 BytesRead, UL...
  type NTSTATUS (line 1805) | typedef NTSTATUS (__stdcall *tIoUnregisterPlugPlayNotificationEx)(PVOID ...
  type NTSTATUS (line 1807) | typedef NTSTATUS (__stdcall *tFsRtlGetEcpListFromIrp)(PIRP Irp, PECP_LIS...
  type NTSTATUS (line 1809) | typedef NTSTATUS (__stdcall *tFsRtlGetNextExtraCreateParameter)(PECP_LIS...
  type NTSTATUS (line 1812) | typedef NTSTATUS (__stdcall *tFsRtlValidateReparsePointBuffer)(ULONG Buf...
  type BOOLEAN (line 1814) | typedef BOOLEAN (__stdcall *tFsRtlCheckLockForOplockRequest)(PFILE_LOCK ...
  type BOOLEAN (line 1816) | typedef BOOLEAN (__stdcall *tFsRtlAreThereCurrentOrInProgressFileLocks)(...
  type LDR_DATA_TABLE_ENTRY (line 1823) | typedef struct _LDR_DATA_TABLE_ENTRY {
  type PEB_LDR_DATA (line 1839) | typedef struct _PEB_LDR_DATA {
  type RTL_USER_PROCESS_PARAMETERS (line 1845) | typedef struct _RTL_USER_PROCESS_PARAMETERS {
  type PEB (line 1854) | typedef struct _PEB {

FILE: src/btrfsioctl.h
  type btrfs_get_file_ids (line 42) | typedef struct {
  type btrfs_create_snapshot (line 48) | typedef struct {
  type btrfs_create_snapshot32 (line 56) | typedef struct {
  type btrfs_inode_info (line 69) | typedef struct {
  type btrfs_set_inode_info (line 89) | typedef struct {
  type btrfs_device (line 102) | typedef struct {
  type btrfs_usage_device (line 116) | typedef struct {
  type btrfs_usage (line 121) | typedef struct {
  type btrfs_balance_opts (line 143) | typedef struct {
  type btrfs_query_balance (line 167) | typedef struct {
  type btrfs_start_balance (line 177) | typedef struct {
  type btrfs_filesystem_device (line 181) | typedef struct {
  type btrfs_filesystem (line 188) | typedef struct {
  type btrfs_scrub_error (line 199) | typedef struct {
  type btrfs_query_scrub (line 223) | typedef struct {
  type btrfs_mknod (line 236) | typedef struct {
  type btrfs_received_subvol (line 244) | typedef struct {
  type btrfs_set_xattr (line 249) | typedef struct {
  type btrfs_create_subvol (line 255) | typedef struct {
  type btrfs_find_subvol (line 262) | typedef struct {
  type btrfs_send_subvol (line 267) | typedef struct {
  type btrfs_send_subvol32 (line 273) | typedef struct {
  type btrfs_resize (line 279) | typedef struct {
  type btrfs_csum_info (line 284) | typedef struct {

FILE: src/cache.c
  function BOOLEAN (line 22) | static BOOLEAN __stdcall acquire_for_lazy_write(PVOID Context, BOOLEAN W...
  function release_from_lazy_write (line 43) | static void __stdcall release_from_lazy_write(PVOID Context) {
  function BOOLEAN (line 59) | static BOOLEAN __stdcall acquire_for_read_ahead(PVOID Context, BOOLEAN W...
  function release_from_read_ahead (line 73) | static void __stdcall release_from_read_ahead(PVOID Context) {
  function init_cache (line 85) | void init_cache() {

FILE: src/calcthread.c
  function calc_thread_main (line 22) | void calc_thread_main(device_extension* Vcb, calc_job* cj) {
  function do_calc_job (line 141) | void do_calc_job(device_extension* Vcb, uint8_t* data, uint32_t sectors,...
  function NTSTATUS (line 183) | NTSTATUS add_calc_job_decomp(device_extension* Vcb, uint8_t compression,...
  function NTSTATUS (line 237) | NTSTATUS add_calc_job_comp(device_extension* Vcb, uint8_t compression, v...
  function calc_thread (line 290) | _Function_class_(KSTART_ROUTINE)

FILE: src/compress.c
  type lzo_stream (line 38) | typedef struct {
  function lzo_nextbyte (line 89) | static uint8_t lzo_nextbyte(lzo_stream* stream) {
  function lzo_len (line 103) | static int lzo_len(lzo_stream* stream, int byte, int mask) {
  function lzo_copy (line 119) | static void lzo_copy(lzo_stream* stream, int len) {
  function lzo_copyback (line 138) | static void lzo_copyback(lzo_stream* stream, uint32_t back, int len) {
  function NTSTATUS (line 156) | static NTSTATUS do_lzo_decompress(lzo_stream* stream) {
  function NTSTATUS (line 264) | NTSTATUS lzo_decompress(uint8_t* inbuf, uint32_t inlen, uint8_t* outbuf,...
  function zlib_free (line 316) | static void zlib_free(void* opaque, void* ptr) {
  function NTSTATUS (line 322) | NTSTATUS zlib_compress(uint8_t* inbuf, uint32_t inlen, uint8_t* outbuf, ...
  function NTSTATUS (line 363) | NTSTATUS zlib_decompress(uint8_t* inbuf, uint32_t inlen, uint8_t* outbuf...
  function NTSTATUS (line 409) | static NTSTATUS lzo_do_compress(const uint8_t* in, uint32_t in_len, uint...
  function NTSTATUS (line 617) | static NTSTATUS lzo1x_1_compress(lzo_stream* stream) {
  function lzo_max_outlen (line 646) | static __inline uint32_t lzo_max_outlen(uint32_t inlen) {
  function zstd_free (line 656) | static void zstd_free(void* opaque, void* address) {
  function NTSTATUS (line 662) | NTSTATUS zstd_decompress(uint8_t* inbuf, uint32_t inlen, uint8_t* outbuf...
  function NTSTATUS (line 713) | NTSTATUS lzo_compress(uint8_t* inbuf, uint32_t inlen, uint8_t* outbuf, u...
  function NTSTATUS (line 791) | NTSTATUS zstd_compress(uint8_t* inbuf, uint32_t inlen, uint8_t* outbuf, ...
  type comp_part (line 853) | typedef struct {
  function NTSTATUS (line 861) | NTSTATUS write_compressed(fcb* fcb, uint64_t start_data, uint64_t end_da...

FILE: src/crc32c.c
  function calc_crc32c_sw (line 62) | uint32_t __stdcall calc_crc32c_sw(_In_ uint32_t seed, _In_reads_bytes_(m...

FILE: src/create.c
  type FILE_TIMESTAMPS (line 48) | typedef struct _FILE_TIMESTAMPS {
  type ATOMIC_CREATE_ECP_CONTEXT (line 55) | typedef struct _ATOMIC_CREATE_ECP_CONTEXT {
  type oplock_context (line 81) | typedef struct {
  function fcb (line 89) | fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) {
  function file_ref (line 158) | file_ref* create_fileref(device_extension* Vcb) {
  function NTSTATUS (line 180) | NTSTATUS find_file_in_dir(PUNICODE_STRING filename, fcb* fcb, root** sub...
  function NTSTATUS (line 319) | static NTSTATUS split_path(device_extension* Vcb, PUNICODE_STRING path, ...
  function NTSTATUS (line 451) | NTSTATUS load_csum(_Requires_lock_held_(_Curr_->tree_lock) device_extens...
  function NTSTATUS (line 508) | NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock) devic...
  function NTSTATUS (line 704) | NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_excl...
  function NTSTATUS (line 1364) | static NTSTATUS open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) ...
  function NTSTATUS (line 1457) | NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Req...
  function NTSTATUS (line 1688) | NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_...
  function NTSTATUS (line 1869) | NTSTATUS add_dir_child(fcb* fcb, uint64_t inode, bool subvol, PANSI_STRI...
  function inherit_mode (line 1946) | uint32_t inherit_mode(fcb* parfcb, bool is_dir) {
  function NTSTATUS (line 1962) | static NTSTATUS file_create_parse_ea(fcb* fcb, FILE_FULL_EA_INFORMATION*...
  function NTSTATUS (line 2180) | static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_hel...
  function NTSTATUS (line 2638) | static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _R...
  function called_from_lxss (line 2987) | static __inline bool called_from_lxss() {
  function NTSTATUS (line 3005) | static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_...
  function debug_create_options (line 3298) | static __inline void debug_create_options(ULONG RequestedOptions) {
  function NTSTATUS (line 3423) | static NTSTATUS get_reparse_block(fcb* fcb, uint8_t** data) {
  function fcb_load_csums (line 3545) | static void fcb_load_csums(_Requires_lock_held_(_Curr_->tree_lock) devic...
  function NTSTATUS (line 3586) | static NTSTATUS open_file3(device_extension* Vcb, PIRP Irp, ACCESS_MASK ...
  function oplock_complete (line 3861) | static void __stdcall oplock_complete(PVOID Context, PIRP Irp) {
  function NTSTATUS (line 3934) | static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposi...
  function NTSTATUS (line 4131) | NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fc...
  function NTSTATUS (line 4461) | static NTSTATUS open_file(PDEVICE_OBJECT DeviceObject, _Requires_lock_he...
  function NTSTATUS (line 4748) | static NTSTATUS verify_vcb(device_extension* Vcb, PIRP Irp) {
  function has_manage_volume_privilege (line 4810) | static bool has_manage_volume_privilege(ACCESS_STATE* access_state, KPRO...

FILE: src/devctrl.c
  function NTSTATUS (line 27) | static NTSTATUS mountdev_query_stable_guid(device_extension* Vcb, PIRP I...
  function NTSTATUS (line 43) | static NTSTATUS is_writable(device_extension* Vcb) {
  function NTSTATUS (line 49) | static NTSTATUS query_filesystems(void* data, ULONG length) {
  function NTSTATUS (line 162) | static NTSTATUS probe_volume(void* data, ULONG length, KPROCESSOR_MODE p...
  function NTSTATUS (line 215) | static NTSTATUS ioctl_unload(PIRP Irp) {
  function NTSTATUS (line 226) | static NTSTATUS control_ioctl(PIRP Irp) {
  function _Function_class_ (line 252) | _Dispatch_type_(IRP_MJ_DEVICE_CONTROL)

FILE: src/dirctrl.c
  type FILE_ID_EXTD_DIR_INFORMATION (line 26) | typedef struct _FILE_ID_EXTD_DIR_INFORMATION {
  type FILE_ID_EXTD_BOTH_DIR_INFORMATION (line 43) | typedef struct _FILE_ID_EXTD_BOTH_DIR_INFORMATION {
  type DirEntryType (line 64) | enum DirEntryType {
  type dir_entry (line 70) | typedef struct {
  function ULONG (line 78) | ULONG get_reparse_tag_fcb(fcb* fcb) {
  function ULONG (line 102) | ULONG get_reparse_tag(device_extension* Vcb, root* subvol, uint64_t inod...
  function ULONG (line 143) | static ULONG get_ea_len(device_extension* Vcb, root* subvol, uint64_t in...
  function NTSTATUS (line 180) | static NTSTATUS query_dir_item(fcb* fcb, ccb* ccb, void* buf, LONG* len,...
  function NTSTATUS (line 644) | static NTSTATUS next_dir_entry(file_ref* fileref, uint64_t* offset, dir_...
  function NTSTATUS (line 730) | static NTSTATUS query_directory(PIRP Irp) {
  function NTSTATUS (line 1073) | static NTSTATUS notify_change_directory(device_extension* Vcb, PIRP Irp) {

FILE: src/extent-tree.c
  type extent_ref (line 21) | typedef struct {
  function get_extent_data_ref_hash2 (line 35) | uint64_t get_extent_data_ref_hash2(uint64_t root, uint64_t objid, uint64...
  function get_extent_data_ref_hash (line 45) | static __inline uint64_t get_extent_data_ref_hash(EXTENT_DATA_REF* edr) {
  function get_extent_hash (line 49) | static uint64_t get_extent_hash(uint8_t type, void* data) {
  function free_extent_refs (line 67) | static void free_extent_refs(LIST_ENTRY* extent_refs) {
  function NTSTATUS (line 76) | static NTSTATUS add_shared_data_extent_ref(LIST_ENTRY* extent_refs, uint...
  function NTSTATUS (line 110) | static NTSTATUS add_shared_block_extent_ref(LIST_ENTRY* extent_refs, uin...
  function NTSTATUS (line 141) | static NTSTATUS add_tree_block_extent_ref(LIST_ENTRY* extent_refs, uint6...
  function sort_extent_refs (line 172) | static void sort_extent_refs(LIST_ENTRY* extent_refs) {
  function NTSTATUS (line 210) | static NTSTATUS construct_extent_item(device_extension* Vcb, uint64_t ad...
  function NTSTATUS (line 372) | static NTSTATUS convert_old_extent(device_extension* Vcb, uint64_t addre...
  function NTSTATUS (line 454) | NTSTATUS increase_extent_refcount(device_extension* Vcb, uint64_t addres...
  function NTSTATUS (line 892) | NTSTATUS increase_extent_refcount_data(device_extension* Vcb, uint64_t a...
  function NTSTATUS (line 903) | NTSTATUS decrease_extent_refcount(device_extension* Vcb, uint64_t addres...
  function NTSTATUS (line 1548) | NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, uint64_t a...
  function NTSTATUS (line 1560) | NTSTATUS decrease_extent_refcount_tree(device_extension* Vcb, uint64_t a...
  function find_extent_data_refcount (line 1569) | static uint32_t find_extent_data_refcount(device_extension* Vcb, uint64_...
  function get_extent_refcount (line 1651) | uint64_t get_extent_refcount(device_extension* Vcb, uint64_t address, ui...
  function is_extent_unique (line 1697) | bool is_extent_unique(device_extension* Vcb, uint64_t address, uint64_t ...
  function get_extent_flags (line 1835) | uint64_t get_extent_flags(device_extension* Vcb, uint64_t address, PIRP ...
  function update_extent_flags (line 1876) | void update_extent_flags(device_extension* Vcb, uint64_t address, uint64...
  function changed_extent (line 1916) | static changed_extent* get_changed_extent_item(chunk* c, uint64_t addres...
  function NTSTATUS (line 1951) | NTSTATUS update_changed_extent_ref(device_extension* Vcb, chunk* c, uint...
  function add_changed_extent_ref (line 2076) | void add_changed_extent_ref(chunk* c, uint64_t address, uint64_t size, u...
  function find_extent_shared_tree_refcount (line 2119) | uint64_t find_extent_shared_tree_refcount(device_extension* Vcb, uint64_...
  function find_extent_shared_data_refcount (line 2220) | uint32_t find_extent_shared_data_refcount(device_extension* Vcb, uint64_...

FILE: src/fastio.c
  function fast_query_basic_info (line 22) | _Function_class_(FAST_IO_QUERY_BASIC_INFO)
  function fast_query_standard_info (line 96) | _Function_class_(FAST_IO_QUERY_STANDARD_INFO)
  function fast_io_check_if_possible (line 174) | _Function_class_(FAST_IO_CHECK_IF_POSSIBLE)
  function fast_io_query_network_open_info (line 198) | _Function_class_(FAST_IO_QUERY_NETWORK_OPEN_INFO)
  function fast_io_acquire_for_mod_write (line 270) | _Function_class_(FAST_IO_ACQUIRE_FOR_MOD_WRITE)
  function fast_io_release_for_mod_write (line 306) | _Function_class_(FAST_IO_RELEASE_FOR_MOD_WRITE)
  function fast_io_acquire_for_ccflush (line 324) | _Function_class_(FAST_IO_ACQUIRE_FOR_CCFLUSH)
  function fast_io_release_for_ccflush (line 334) | _Function_class_(FAST_IO_RELEASE_FOR_CCFLUSH)
  function fast_io_write (line 345) | _Function_class_(FAST_IO_WRITE)
  function fast_io_lock (line 369) | _Function_class_(FAST_IO_LOCK)
  function fast_io_unlock_single (line 403) | _Function_class_(FAST_IO_UNLOCK_SINGLE)
  function fast_io_unlock_all (line 432) | _Function_class_(FAST_IO_UNLOCK_ALL)
  function fast_io_unlock_all_by_key (line 463) | _Function_class_(FAST_IO_UNLOCK_ALL_BY_KEY)
  function fast_io_acquire_for_create_section (line 495) | static void __stdcall fast_io_acquire_for_create_section(_In_ PFILE_OBJE...
  function fast_io_release_for_create_section (line 512) | static void __stdcall fast_io_release_for_create_section(_In_ PFILE_OBJE...
  function init_fast_io_dispatch (line 529) | void init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {

FILE: src/fileinfo.c
  type FILE_ID_INFORMATION (line 33) | typedef struct _FILE_ID_INFORMATION {
  type FILE_STAT_INFORMATION (line 38) | typedef struct _FILE_STAT_INFORMATION {
  type FILE_STAT_LX_INFORMATION (line 52) | typedef struct _FILE_STAT_LX_INFORMATION {
  type FILE_RENAME_INFORMATION_EX (line 78) | typedef struct _FILE_RENAME_INFORMATION_EX {
  type FILE_DISPOSITION_INFORMATION_EX (line 88) | typedef struct _FILE_DISPOSITION_INFORMATION_EX {
  type FILE_LINK_INFORMATION_EX (line 92) | typedef struct _FILE_LINK_INFORMATION_EX {
  type FILE_CASE_SENSITIVE_INFORMATION (line 102) | typedef struct _FILE_CASE_SENSITIVE_INFORMATION {
  type FILE_LINK_ENTRY_FULL_ID_INFORMATION (line 106) | typedef struct _FILE_LINK_ENTRY_FULL_ID_INFORMATION {
  type FILE_LINKS_FULL_ID_INFORMATION (line 113) | typedef struct _FILE_LINKS_FULL_ID_INFORMATION {
  function NTSTATUS (line 150) | static NTSTATUS set_basic_information(device_extension* Vcb, PIRP Irp, P...
  function NTSTATUS (line 317) | static NTSTATUS set_disposition_information(device_extension* Vcb, PIRP ...
  function has_open_children (line 402) | bool has_open_children(file_ref* fileref) {
  function NTSTATUS (line 423) | static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
  type move_entry (line 653) | typedef struct _move_entry {
  function NTSTATUS (line 661) | static NTSTATUS add_children_to_move_list(device_extension* Vcb, move_en...
  function remove_dir_child_from_hash_lists (line 704) | void remove_dir_child_from_hash_lists(fcb* fcb, dir_child* dc) {
  function NTSTATUS (line 742) | static NTSTATUS create_directory_fcb(device_extension* Vcb, root* r, fcb...
  function add_fcb_to_subvol (line 848) | void add_fcb_to_subvol(_In_ _Requires_exclusive_lock_held_(_Curr_->Vcb->...
  function remove_fcb_from_subvol (line 897) | void remove_fcb_from_subvol(_In_ _Requires_exclusive_lock_held_(_Curr_->...
  function NTSTATUS (line 910) | static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb, file_re...
  function insert_dir_child_into_hash_lists (line 1430) | void insert_dir_child_into_hash_lists(fcb* fcb, dir_child* dc) {
  function NTSTATUS (line 1518) | static NTSTATUS rename_stream_to_file(device_extension* Vcb, file_ref* f...
  function NTSTATUS (line 1816) | static NTSTATUS rename_stream(device_extension* Vcb, file_ref* fileref, ...
  function NTSTATUS (line 2060) | static NTSTATUS rename_file_to_stream(device_extension* Vcb, file_ref* f...
  function NTSTATUS (line 2487) | static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, ...
  function NTSTATUS (line 3130) | NTSTATUS stream_set_end_of_file_information(device_extension* Vcb, uint1...
  function NTSTATUS (line 3200) | static NTSTATUS set_end_of_file_information(device_extension* Vcb, PIRP ...
  function NTSTATUS (line 3354) | static NTSTATUS set_allocation_information(device_extension* Vcb, PIRP I...
  function NTSTATUS (line 3498) | static NTSTATUS set_position_information(PFILE_OBJECT FileObject, PIRP I...
  function NTSTATUS (line 3510) | static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PF...
  function NTSTATUS (line 3864) | static NTSTATUS set_valid_data_length_information(device_extension* Vcb,...
  function NTSTATUS (line 3959) | static NTSTATUS set_case_sensitive_information(PIRP Irp) {
  function _Function_class_ (line 3991) | _Dispatch_type_(IRP_MJ_SET_INFORMATION)
  function NTSTATUS (line 4207) | static NTSTATUS fill_in_file_basic_information(FILE_BASIC_INFORMATION* f...
  function NTSTATUS (line 4236) | static NTSTATUS fill_in_file_network_open_information(FILE_NETWORK_OPEN_...
  function NTSTATUS (line 4282) | static NTSTATUS fill_in_file_standard_information(FILE_STANDARD_INFORMAT...
  function NTSTATUS (line 4310) | static NTSTATUS fill_in_file_internal_information(FILE_INTERNAL_INFORMAT...
  function NTSTATUS (line 4318) | static NTSTATUS fill_in_file_ea_information(FILE_EA_INFORMATION* eai, fc...
  function NTSTATUS (line 4331) | static NTSTATUS fill_in_file_position_information(FILE_POSITION_INFORMAT...
  function NTSTATUS (line 4341) | NTSTATUS fileref_get_filename(file_ref* fileref, PUNICODE_STRING fn, USH...
  function NTSTATUS (line 4428) | static NTSTATUS fill_in_file_name_information(FILE_NAME_INFORMATION* fni...
  function NTSTATUS (line 4485) | static NTSTATUS fill_in_file_attribute_information(FILE_ATTRIBUTE_TAG_IN...
  function NTSTATUS (line 4506) | static NTSTATUS fill_in_file_stream_information(FILE_STREAM_INFORMATION*...
  function NTSTATUS (line 4615) | static NTSTATUS fill_in_file_standard_link_information(FILE_STANDARD_LIN...
  function NTSTATUS (line 4630) | static NTSTATUS fill_in_hard_link_information(FILE_LINKS_INFORMATION* fl...
  function NTSTATUS (line 4799) | static NTSTATUS fill_in_hard_link_full_id_information(FILE_LINKS_FULL_ID...
  function NTSTATUS (line 4970) | static NTSTATUS fill_in_file_id_information(FILE_ID_INFORMATION* fii, fc...
  function NTSTATUS (line 4980) | static NTSTATUS fill_in_file_stat_information(FILE_STAT_INFORMATION* fsi...
  function NTSTATUS (line 5039) | static NTSTATUS fill_in_file_stat_lx_information(FILE_STAT_LX_INFORMATIO...
  function NTSTATUS (line 5114) | static NTSTATUS fill_in_file_case_sensitive_information(FILE_CASE_SENSIT...
  function NTSTATUS (line 5122) | static NTSTATUS fill_in_file_compression_information(FILE_COMPRESSION_IN...
  function NTSTATUS (line 5135) | static NTSTATUS query_info(device_extension* Vcb, PFILE_OBJECT FileObjec...
  function _Function_class_ (line 5509) | _Dispatch_type_(IRP_MJ_QUERY_INFORMATION)

FILE: src/flushthread.c
  type write_context (line 34) | typedef struct {
  type EXTENT_ITEM_TREE2 (line 39) | typedef struct {
  type EXTENT_ITEM_SKINNY_METADATA (line 45) | typedef struct {
  type batch_operation (line 56) | enum batch_operation
  function write_completion (line 58) | _Function_class_(IO_COMPLETION_ROUTINE)
  function NTSTATUS (line 70) | NTSTATUS write_data_phys(_In_ PDEVICE_OBJECT device, _In_ PFILE_OBJECT f...
  function add_trim_entry (line 157) | static void add_trim_entry(device* dev, uint64_t address, uint64_t size) {
  function clean_space_cache_chunk (line 171) | static void clean_space_cache_chunk(device_extension* Vcb, chunk* c) {
  type ioctl_context_stripe (line 282) | typedef struct {
  type ioctl_context (line 293) | typedef struct {
  function ioctl_completion (line 299) | _Function_class_(IO_COMPLETION_ROUTINE)
  function trim_emulation (line 314) | static void trim_emulation(device* dev) {
  function clean_space_cache (line 403) | static void clean_space_cache(device_extension* Vcb) {
  function trees_consistent (line 578) | static bool trees_consistent(device_extension* Vcb) {
  function NTSTATUS (line 615) | static NTSTATUS add_parents(device_extension* Vcb, PIRP Irp) {
  function add_parents_to_cache (line 702) | static void add_parents_to_cache(tree* t) {
  function insert_tree_extent_skinny (line 709) | static bool insert_tree_extent_skinny(device_extension* Vcb, uint8_t lev...
  function find_metadata_address_in_chunk (line 744) | bool find_metadata_address_in_chunk(device_extension* Vcb, chunk* c, uin...
  function insert_tree_extent (line 825) | static bool insert_tree_extent(device_extension* Vcb, uint8_t level, uin...
  function NTSTATUS (line 878) | NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP Irp, ...
  function NTSTATUS (line 956) | static NTSTATUS reduce_tree_extent(device_extension* Vcb, uint64_t addre...
  function NTSTATUS (line 1007) | static NTSTATUS add_changed_extent_ref_edr(changed_extent* ce, EXTENT_DA...
  function NTSTATUS (line 1044) | static NTSTATUS add_changed_extent_ref_sdr(changed_extent* ce, SHARED_DA...
  function shared_tree_is_unique (line 1081) | static bool shared_tree_is_unique(device_extension* Vcb, tree* t, PIRP I...
  function NTSTATUS (line 1110) | static NTSTATUS update_tree_extents(device_extension* Vcb, tree* t, PIRP...
  function NTSTATUS (line 1465) | static NTSTATUS allocate_tree_extents(device_extension* Vcb, PIRP Irp, L...
  function NTSTATUS (line 1557) | static NTSTATUS update_root_root(device_extension* Vcb, bool no_cache, P...
  function NTSTATUS (line 1620) | NTSTATUS do_tree_writes(device_extension* Vcb, LIST_ENTRY* tree_writes, ...
  function calc_tree_checksum (line 1806) | void calc_tree_checksum(device_extension* Vcb, tree_header* th) {
  function NTSTATUS (line 1826) | static NTSTATUS write_trees(device_extension* Vcb, PIRP Irp) {
  function update_backup_superblock (line 2111) | static void update_backup_superblock(device_extension* Vcb, superblock_b...
  type write_superblocks_stripe (line 2180) | typedef struct {
  type write_superblocks_context (line 2190) | typedef struct _write_superblocks_context {
  function write_superblock_completion (line 2196) | _Function_class_(IO_COMPLETION_ROUTINE)
  function calc_superblock_checksum (line 2211) | static void calc_superblock_checksum(superblock* sb) {
  function NTSTATUS (line 2231) | static NTSTATUS write_superblock(device_extension* Vcb, device* device, ...
  function NTSTATUS (line 2326) | static NTSTATUS write_superblocks(device_extension* Vcb, PIRP Irp) {
  function NTSTATUS (line 2433) | static NTSTATUS flush_changed_extent(device_extension* Vcb, chunk* c, ch...
  function add_checksum_entry (line 2602) | void add_checksum_entry(device_extension* Vcb, uint64_t address, ULONG l...
  function NTSTATUS (line 2810) | static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST...
  function get_first_item (line 2974) | static void get_first_item(tree* t, KEY* key) {
  function NTSTATUS (line 2986) | static NTSTATUS split_tree_at(device_extension* Vcb, tree* t, tree_data*...
  function NTSTATUS (line 3205) | static NTSTATUS split_tree(device_extension* Vcb, tree* t) {
  function is_tree_unique (line 3245) | bool is_tree_unique(device_extension* Vcb, tree* t, PIRP Irp) {
  function NTSTATUS (line 3308) | static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, bool...
  function NTSTATUS (line 3538) | static NTSTATUS update_extent_level(device_extension* Vcb, uint64_t addr...
  function NTSTATUS (line 3638) | static NTSTATUS update_tree_extents_recursive(device_extension* Vcb, tre...
  function NTSTATUS (line 3656) | static NTSTATUS do_splits(device_extension* Vcb, PIRP Irp, LIST_ENTRY* r...
  function NTSTATUS (line 3876) | static NTSTATUS remove_root_extents(device_extension* Vcb, root* r, tree...
  function NTSTATUS (line 3947) | static NTSTATUS drop_root(device_extension* Vcb, root* r, PIRP Irp, LIST...
  function NTSTATUS (line 4074) | static NTSTATUS drop_roots(device_extension* Vcb, PIRP Irp, LIST_ENTRY* ...
  function NTSTATUS (line 4095) | NTSTATUS update_dev_item(device_extension* Vcb, device* device, PIRP Irp) {
  function regen_bootstrap (line 4140) | static void regen_bootstrap(device_extension* Vcb) {
  function NTSTATUS (line 4162) | static NTSTATUS add_to_bootstrap(device_extension* Vcb, uint64_t obj_id,...
  function NTSTATUS (line 4208) | static NTSTATUS create_chunk(device_extension* Vcb, chunk* c, PIRP Irp) {
  function remove_from_bootstrap (line 4311) | static void remove_from_bootstrap(device_extension* Vcb, uint64_t obj_id...
  function NTSTATUS (line 4334) | static NTSTATUS set_xattr(device_extension* Vcb, LIST_ENTRY* batchlist, ...
  function NTSTATUS (line 4370) | static NTSTATUS delete_xattr(device_extension* Vcb, LIST_ENTRY* batchlis...
  function NTSTATUS (line 4405) | static NTSTATUS insert_sparse_extent(fcb* fcb, LIST_ENTRY* batchlist, ui...
  function NTSTATUS (line 4441) | static NTSTATUS split_batch_item_list(batch_item_ind* bii) {
  function NTSTATUS (line 4520) | static NTSTATUS insert_tree_item_batch(LIST_ENTRY* batchlist, device_ext...
  type extent_range (line 4621) | typedef struct {
  function rationalize_extents (line 4632) | static void rationalize_extents(fcb* fcb, PIRP Irp) {
  function NTSTATUS (line 4927) | NTSTATUS flush_fcb(fcb* fcb, bool cache, LIST_ENTRY* batchlist, PIRP Irp) {
  function add_trim_entry_avoid_sb (line 5510) | void add_trim_entry_avoid_sb(device_extension* Vcb, device* dev, uint64_...
  function NTSTATUS (line 5534) | static NTSTATUS drop_chunk(device_extension* Vcb, chunk* c, LIST_ENTRY* ...
  function NTSTATUS (line 5837) | static NTSTATUS partial_stripe_read(device_extension* Vcb, chunk* c, par...
  function NTSTATUS (line 5962) | NTSTATUS flush_partial_stripe(device_extension* Vcb, chunk* c, partial_s...
  function NTSTATUS (line 6137) | static NTSTATUS update_chunks(device_extension* Vcb, LIST_ENTRY* batchli...
  function NTSTATUS (line 6250) | static NTSTATUS delete_root_ref(device_extension* Vcb, uint64_t subvolid...
  function NTSTATUS (line 6347) | static NTSTATUS add_root_ref(_In_ device_extension* Vcb, _In_ uint64_t s...
  function NTSTATUS (line 6406) | static NTSTATUS update_root_backref(device_extension* Vcb, uint64_t subv...
  function NTSTATUS (line 6476) | static NTSTATUS add_root_item_to_cache(device_extension* Vcb, uint64_t r...
  function NTSTATUS (line 6528) | static NTSTATUS flush_fileref(file_ref* fileref, LIST_ENTRY* batchlist, ...
  function flush_disk_caches (line 6915) | static void flush_disk_caches(device_extension* Vcb) {
  function NTSTATUS (line 7004) | static NTSTATUS flush_changed_dev_stats(device_extension* Vcb, device* d...
  function NTSTATUS (line 7048) | static NTSTATUS flush_subvol(device_extension* Vcb, root* r, PIRP Irp) {
  function NTSTATUS (line 7175) | static NTSTATUS test_not_full(device_extension* Vcb) {
  function NTSTATUS (line 7379) | static NTSTATUS check_for_orphans_root(device_extension* Vcb, root* r, P...
  function NTSTATUS (line 7454) | static NTSTATUS check_for_orphans(device_extension* Vcb, PIRP Irp) {
  function NTSTATUS (line 7481) | static NTSTATUS do_write2(device_extension* Vcb, PIRP Irp, LIST_ENTRY* r...
  function NTSTATUS (line 7881) | NTSTATUS do_write(device_extension* Vcb, PIRP Irp) {
  function do_flush (line 7900) | static void do_flush(device_extension* Vcb) {
  function flush_thread (line 7918) | _Function_class_(KSTART_ROUTINE)

FILE: src/free-space.c
  function NTSTATUS (line 25) | static NTSTATUS remove_free_space_inode(device_extension* Vcb, uint64_t ...
  function NTSTATUS (line 59) | NTSTATUS clear_free_space_cache(device_extension* Vcb, LIST_ENTRY* batch...
  function NTSTATUS (line 190) | NTSTATUS add_space_entry(LIST_ENTRY* list, LIST_ENTRY* list_size, uint64...
  function load_free_space_bitmap (line 258) | static void load_free_space_bitmap(device_extension* Vcb, chunk* c, uint...
  function order_space_entry (line 299) | static void order_space_entry(space* s, LIST_ENTRY* list_size) {
  type superblock_stripe (line 323) | typedef struct {
  function NTSTATUS (line 328) | static NTSTATUS add_superblock_stripe(LIST_ENTRY* stripes, uint64_t off,...
  function NTSTATUS (line 364) | static NTSTATUS get_superblock_size(chunk* c, uint64_t* size) {
  function NTSTATUS (line 466) | NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, b...
  function NTSTATUS (line 729) | static NTSTATUS load_stored_free_space_tree(device_extension* Vcb, chunk...
  function NTSTATUS (line 886) | static NTSTATUS load_free_space_cache(device_extension* Vcb, chunk* c, P...
  function NTSTATUS (line 980) | NTSTATUS load_cache_chunk(device_extension* Vcb, chunk* c, PIRP Irp) {
  function NTSTATUS (line 999) | static NTSTATUS insert_cache_extent(fcb* fcb, uint64_t start, uint64_t l...
  function NTSTATUS (line 1043) | static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, bo...
  function NTSTATUS (line 1382) | NTSTATUS allocate_cache(device_extension* Vcb, bool* changed, PIRP Irp, ...
  function add_rollback_space (line 1428) | static void add_rollback_space(LIST_ENTRY* rollback, bool add, LIST_ENTR...
  function space_list_add2 (line 1446) | void space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, uint64_t a...
  function space_list_merge (line 1657) | void space_list_merge(LIST_ENTRY* spacelist, LIST_ENTRY* spacelist_size,...
  function NTSTATUS (line 1669) | static NTSTATUS copy_space_list(LIST_ENTRY* old_list, LIST_ENTRY* new_li...
  function NTSTATUS (line 1694) | static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRF...
  function NTSTATUS (line 1837) | static NTSTATUS update_chunk_cache_tree(device_extension* Vcb, chunk* c,...
  function NTSTATUS (line 2043) | NTSTATUS update_chunk_caches(device_extension* Vcb, PIRP Irp, LIST_ENTRY...
  function NTSTATUS (line 2113) | NTSTATUS update_chunk_caches_tree(device_extension* Vcb, PIRP Irp) {
  function space_list_add (line 2146) | void space_list_add(chunk* c, uint64_t address, uint64_t length, LIST_EN...
  function space_list_subtract2 (line 2155) | void space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, uint6...
  function space_list_subtract (line 2234) | void space_list_subtract(chunk* c, uint64_t address, uint64_t length, LI...

FILE: src/fsctl.c
  function NTSTATUS (line 47) | static NTSTATUS get_file_ids(PFILE_OBJECT FileObject, void* data, ULONG ...
  function get_uuid (line 71) | static void get_uuid(BTRFS_UUID* uuid) {
  function NTSTATUS (line 85) | static NTSTATUS snapshot_tree_copy(device_extension* Vcb, uint64_t addr,...
  function flush_subvol_fcbs (line 241) | void flush_subvol_fcbs(root* subvol) {
  function NTSTATUS (line 258) | static NTSTATUS do_create_snapshot(device_extension* Vcb, PFILE_OBJECT p...
  type _fcb (line 699) | struct _fcb
  function NTSTATUS (line 744) | static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileOb...
  function NTSTATUS (line 1160) | static NTSTATUS get_inode_info(PFILE_OBJECT FileObject, void* data, ULON...
  function NTSTATUS (line 1321) | static NTSTATUS set_inode_info(PFILE_OBJECT FileObject, void* data, ULON...
  function NTSTATUS (line 1442) | static NTSTATUS get_devices(device_extension* Vcb, void* data, ULONG len...
  function NTSTATUS (line 1510) | static NTSTATUS get_usage(device_extension* Vcb, void* data, ULONG lengt...
  function NTSTATUS (line 1660) | static NTSTATUS is_volume_mounted(device_extension* Vcb, PIRP Irp) {
  function NTSTATUS (line 1703) | static NTSTATUS fs_get_statistics(void* buffer, DWORD buflen, ULONG_PTR*...
  function NTSTATUS (line 1725) | static NTSTATUS set_sparse(device_extension* Vcb, PFILE_OBJECT FileObjec...
  function NTSTATUS (line 1809) | static NTSTATUS zero_data(device_extension* Vcb, fcb* fcb, uint64_t star...
  function NTSTATUS (line 1909) | static NTSTATUS set_zero_data(device_extension* Vcb, PFILE_OBJECT FileOb...
  function NTSTATUS (line 2087) | static NTSTATUS query_ranges(PFILE_OBJECT FileObject, FILE_ALLOCATED_RAN...
  function NTSTATUS (line 2186) | static NTSTATUS get_object_id(PFILE_OBJECT FileObject, FILE_OBJECTID_BUF...
  function flush_fcb_caches (line 2220) | static void flush_fcb_caches(device_extension* Vcb) {
  function NTSTATUS (line 2235) | static NTSTATUS lock_volume(device_extension* Vcb, PIRP Irp) {
  function do_unlock_volume (line 2324) | void do_unlock_volume(device_extension* Vcb) {
  function NTSTATUS (line 2339) | static NTSTATUS unlock_volume(device_extension* Vcb, PIRP Irp) {
  function NTSTATUS (line 2489) | static NTSTATUS is_volume_dirty(device_extension* Vcb, PIRP Irp) {
  function NTSTATUS (line 2516) | static NTSTATUS get_compression(PIRP Irp) {
  function NTSTATUS (line 2542) | static NTSTATUS set_compression(PIRP Irp) {
  function update_volumes (line 2559) | static void update_volumes(device_extension* Vcb) {
  function NTSTATUS (line 2582) | NTSTATUS dismount_volume(device_extension* Vcb, bool shutdown, PIRP Irp) {
  function NTSTATUS (line 2635) | static NTSTATUS is_device_part_of_mounted_btrfs_raid(PDEVICE_OBJECT devo...
  function trim_whole_device (line 2714) | void trim_whole_device(device* dev) {
  function NTSTATUS (line 3129) | static NTSTATUS allow_extended_dasd_io(device_extension* Vcb, PFILE_OBJE...
  function NTSTATUS (line 3155) | static NTSTATUS query_uuid(device_extension* Vcb, void* data, ULONG leng...
  function NTSTATUS (line 3164) | static NTSTATUS reset_stats(device_extension* Vcb, void* data, ULONG len...
  function NTSTATUS (line 3208) | static NTSTATUS get_integrity_information(device_extension* Vcb, PFILE_O...
  function NTSTATUS (line 3230) | static NTSTATUS set_integrity_information(PFILE_OBJECT FileObject, void*...
  function fcb_is_inline (line 3244) | bool fcb_is_inline(fcb* fcb) {
  function NTSTATUS (line 3260) | static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT Fi...
  function NTSTATUS (line 3699) | static NTSTATUS check_inode_used(_In_ _Requires_exclusive_lock_held_(_Cu...
  function NTSTATUS (line 3737) | static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, vo...
  function mark_subvol_dirty (line 4106) | static void mark_subvol_dirty(device_extension* Vcb, root* r) {
  function NTSTATUS (line 4118) | static NTSTATUS recvd_subvol(device_extension* Vcb, PFILE_OBJECT FileObj...
  function NTSTATUS (line 4168) | static NTSTATUS fsctl_get_xattrs(device_extension* Vcb, PFILE_OBJECT Fil...
  function NTSTATUS (line 4233) | static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT File...
  function NTSTATUS (line 4504) | static NTSTATUS reserve_subvol(device_extension* Vcb, PFILE_OBJECT FileO...
  function NTSTATUS (line 4533) | static NTSTATUS get_subvol_path(device_extension* Vcb, uint64_t id, WCHA...
  function NTSTATUS (line 4584) | static NTSTATUS find_subvol(device_extension* Vcb, void* in, ULONG inlen...
  function NTSTATUS (line 4708) | static NTSTATUS resize_device(device_extension* Vcb, void* data, ULONG l...
  function NTSTATUS (line 4893) | static NTSTATUS fsctl_oplock(device_extension* Vcb, PIRP* Pirp) {
  function NTSTATUS (line 4985) | static NTSTATUS get_retrieval_pointers(device_extension* Vcb, PFILE_OBJE...
  function NTSTATUS (line 5125) | static NTSTATUS add_csum_sparse_extents(device_extension* Vcb, uint64_t ...
  function NTSTATUS (line 5186) | static NTSTATUS get_csum_info(device_extension* Vcb, PFILE_OBJECT FileOb...
  function NTSTATUS (line 5322) | NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, uint32_t...

FILE: src/fsrtl.c
  function FORCEINLINE (line 12) | FORCEINLINE
  function FORCEINLINE (line 25) | FORCEINLINE
  function NTSTATUS (line 32) | NTSTATUS __stdcall compat_FsRtlValidateReparsePointBuffer(IN ULONG Buffe...

FILE: src/galois.c
  function galois_divpower (line 55) | void galois_divpower(uint8_t* data, uint8_t div, uint32_t len) {
  function gpow2 (line 69) | uint8_t gpow2(uint8_t e) {
  function gmul (line 73) | uint8_t gmul(uint8_t a, uint8_t b) {
  function gdiv (line 80) | uint8_t gdiv(uint8_t a, uint8_t b) {
  function galois_double_mask64 (line 98) | __inline static uint64_t galois_double_mask64(uint64_t v) {
  function galois_double_mask32 (line 103) | __inline static uint32_t galois_double_mask32(uint32_t v) {
  function galois_double (line 109) | void galois_double(uint8_t* data, uint32_t len) {

FILE: src/mkbtrfs/mkbtrfs.c
  type DSTRING (line 34) | typedef struct {
  type STREAM_MESSAGE (line 40) | typedef struct {
  type options (line 51) | typedef struct {
  type BOOL (line 58) | typedef BOOL (__stdcall* pFormatEx)(DSTRING* root, STREAM_MESSAGE* messa...
  function print_string (line 64) | static void print_string(FILE* f, int resid, ...) {
  function main (line 81) | int main(int argc, char** argv) {

FILE: src/pnp.c
  function NTSTATUS (line 23) | NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
  function NTSTATUS (line 53) | static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject) {
  function NTSTATUS (line 77) | NTSTATUS pnp_surprise_removal(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
  function NTSTATUS (line 101) | static NTSTATUS bus_query_capabilities(PIRP Irp) {
  function NTSTATUS (line 111) | static NTSTATUS bus_query_device_relations(PIRP Irp) {
  function NTSTATUS (line 167) | static NTSTATUS bus_query_hardware_ids(PIRP Irp) {
  function NTSTATUS (line 185) | static NTSTATUS bus_pnp(bus_device_extension* bde, PIRP Irp) {
  function NTSTATUS (line 239) | static NTSTATUS pdo_query_device_id(pdo_device_extension* pdode, PIRP Ir...
  function NTSTATUS (line 272) | static NTSTATUS pdo_query_hardware_ids(PIRP Irp) {
  function NTSTATUS (line 290) | static NTSTATUS pdo_query_id(pdo_device_extension* pdode, PIRP Irp) {
  type device_usage_context (line 309) | typedef struct {
  function device_usage_completion (line 315) | _Function_class_(IO_COMPLETION_ROUTINE)
  function NTSTATUS (line 328) | static NTSTATUS pdo_device_usage_notification(pdo_device_extension* pdod...
  function NTSTATUS (line 387) | static NTSTATUS pdo_query_device_relations(PDEVICE_OBJECT pdo, PIRP Irp) {
  function NTSTATUS (line 410) | static NTSTATUS pdo_pnp(PDEVICE_OBJECT pdo, PIRP Irp) {
  function NTSTATUS (line 437) | static NTSTATUS pnp_device_usage_notification(PDEVICE_OBJECT DeviceObjec...

FILE: src/read.c
  type read_data_status (line 22) | enum read_data_status {
  type read_data_context (line 30) | struct read_data_context
  type read_data_stripe (line 32) | typedef struct {
  type read_data_context (line 44) | typedef struct {
  function read_data_completion (line 67) | _Function_class_(IO_COMPLETION_ROUTINE)
  function NTSTATUS (line 87) | NTSTATUS check_csum(device_extension* Vcb, uint8_t* data, uint32_t secto...
  function get_tree_checksum (line 108) | void get_tree_checksum(device_extension* Vcb, tree_header* th, void* csu...
  function check_tree_checksum (line 128) | bool check_tree_checksum(device_extension* Vcb, tree_header* th) {
  function get_sector_csum (line 182) | void get_sector_csum(device_extension* Vcb, void* buf, void* csum) {
  function check_sector_csum (line 202) | bool check_sector_csum(device_extension* Vcb, void* buf, void* csum) {
  function NTSTATUS (line 236) | static NTSTATUS read_data_dup(device_extension* Vcb, uint8_t* buf, uint6...
  function NTSTATUS (line 397) | static NTSTATUS read_data_raid0(device_extension* Vcb, uint8_t* buf, uin...
  function NTSTATUS (line 467) | static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, ui...
  function NTSTATUS (line 651) | static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uin...
  function raid6_recover2 (line 918) | void raid6_recover2(uint8_t* sectors, uint16_t num_stripes, ULONG sector...
  function NTSTATUS (line 996) | static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uin...
  function NTSTATUS (line 1478) | NTSTATUS read_data(_In_ device_extension* Vcb, _In_ uint64_t addr, _In_ ...
  function else (line 1731) | else if (type == BLOCK_FLAG_RAID10) {
  function except (line 1786) | except (EXCEPTION_EXECUTE_HANDLER) {
  function except (line 1980) | except (EXCEPTION_EXECUTE_HANDLER) {
  function except (line 2022) | except (EXCEPTION_EXECUTE_HANDLER) {
  function except (line 2281) | except (EXCEPTION_EXECUTE_HANDLER) {
  type read_data_context (line 2541) | struct read_data_context
  function NTSTATUS (line 2730) | __attribute__((nonnull(1, 2)))
  type read_part_extent (line 2761) | typedef struct {
  type read_part (line 2768) | typedef struct {
  type comp_calc_job (line 2786) | typedef struct {
  function NTSTATUS (line 2795) | __attribute__((nonnull(1, 2)))
  function NTSTATUS (line 3328) | NTSTATUS do_read(PIRP Irp, bool wait, ULONG* bytes_read) {

FILE: src/registry.c
  function NTSTATUS (line 36) | NTSTATUS registry_load_volume_options(device_extension* Vcb) {
  function NTSTATUS (line 242) | NTSTATUS registry_mark_volume_mounted(BTRFS_UUID* uuid) {
  function NTSTATUS (line 306) | static NTSTATUS registry_mark_volume_unmounted_path(PUNICODE_STRING path) {
  function NTSTATUS (line 385) | NTSTATUS registry_mark_volume_unmounted(BTRFS_UUID* uuid) {
  function is_uuid (line 432) | static bool is_uuid(ULONG namelen, WCHAR* name) {
  type key_name (line 449) | typedef struct {
  function reset_subkeys (line 454) | static void reset_subkeys(HANDLE h, PUNICODE_STRING reg_path) {
  function read_mappings (line 544) | static void read_mappings(PUNICODE_STRING regpath) {
  function read_group_mappings (line 622) | static void read_group_mappings(PUNICODE_STRING regpath) {
  function get_registry_value (line 726) | static void get_registry_value(HANDLE h, WCHAR* string, ULONG type, void...
  function read_registry (line 777) | void read_registry(PUNICODE_STRING regpath, bool refresh) {
  function registry_work_item (line 1021) | _Function_class_(WORKER_THREAD_ROUTINE)
  function watch_registry (line 1036) | void watch_registry(HANDLE regh) {

FILE: src/reparse.c
  type REPARSE_DATA_BUFFER_LX_SYMLINK (line 22) | typedef struct {
  function NTSTATUS (line 27) | NTSTATUS get_reparse_point(PFILE_OBJECT FileObject, void* buffer, DWORD ...
  function NTSTATUS (line 179) | static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, fcb* fcb, ccb* ...
  function NTSTATUS (line 307) | NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG bu...
  function NTSTATUS (line 409) | NTSTATUS set_reparse_point(PIRP Irp) {
  function NTSTATUS (line 482) | NTSTATUS delete_reparse_point(PIRP Irp) {

FILE: src/scrub.c
  type _scrub_context (line 22) | struct _scrub_context
  type scrub_context_stripe (line 24) | typedef struct {
  type scrub_context (line 35) | typedef struct _scrub_context {
  type path_part (line 41) | typedef struct {
  function log_file_checksum_error (line 47) | static void log_file_checksum_error(device_extension* Vcb, uint64_t addr...
  function log_file_checksum_error_shared (line 330) | static void log_file_checksum_error_shared(device_extension* Vcb, uint64...
  function log_tree_checksum_error (line 369) | static void log_tree_checksum_error(device_extension* Vcb, uint64_t addr...
  function log_tree_checksum_error_shared (line 406) | static void log_tree_checksum_error_shared(device_extension* Vcb, uint64...
  function log_unrecoverable_error (line 442) | static void log_unrecoverable_error(device_extension* Vcb, uint64_t addr...
  function log_error (line 605) | static void log_error(device_extension* Vcb, uint64_t addr, uint64_t dev...
  function scrub_read_completion (line 651) | _Function_class_(IO_COMPLETION_ROUTINE)
  function NTSTATUS (line 667) | static NTSTATUS scrub_extent_dup(device_extension* Vcb, chunk* c, uint64...
  function NTSTATUS (line 938) | static NTSTATUS scrub_extent_raid0(device_extension* Vcb, chunk* c, uint...
  function NTSTATUS (line 996) | static NTSTATUS scrub_extent_raid10(device_extension* Vcb, chunk* c, uin...
  function NTSTATUS (line 1375) | static NTSTATUS scrub_extent(device_extension* Vcb, chunk* c, ULONG type...
  function NTSTATUS (line 1625) | static NTSTATUS scrub_data_extent(device_extension* Vcb, chunk* c, uint6...
  type scrub_context_raid56_stripe (line 1667) | typedef struct {
  type scrub_context_raid56 (line 1678) | typedef struct {
  function scrub_read_completion_raid56 (line 1690) | _Function_class_(IO_COMPLETION_ROUTINE)
  function scrub_raid5_stripe (line 1706) | static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_co...
  function scrub_raid6_stripe (line 1895) | static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_co...
  function NTSTATUS (line 2425) | static NTSTATUS scrub_chunk_raid56_stripe_run(device_extension* Vcb, chu...
  function NTSTATUS (line 2836) | static NTSTATUS scrub_chunk_raid56(device_extension* Vcb, chunk* c, uint...
  function NTSTATUS (line 2923) | static NTSTATUS scrub_chunk(device_extension* Vcb, chunk* c, uint64_t* o...
  function scrub_thread (line 3138) | _Function_class_(KSTART_ROUTINE)
  function NTSTATUS (line 3260) | NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mo...
  function NTSTATUS (line 3301) | NTSTATUS query_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mo...
  function NTSTATUS (line 3401) | NTSTATUS pause_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mo...
  function NTSTATUS (line 3422) | NTSTATUS resume_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_m...
  function NTSTATUS (line 3440) | NTSTATUS stop_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mod...

FILE: src/search.c
  type fve_data (line 52) | typedef struct {
  function fs_ignored (line 63) | static bool fs_ignored(BTRFS_UUID* uuid) {
  type fve_callback_context (line 136) | typedef struct {
  function fve_callback (line 144) | _Function_class_(IO_WORKITEM_ROUTINE)
  function NTSTATUS (line 184) | static NTSTATUS __stdcall event_notification(PVOID NotificationStructure...
  function register_fve_callback (line 247) | static void register_fve_callback(PDEVICE_OBJECT devobj, PFILE_OBJECT fi...
  function test_vol (line 309) | static bool test_vol(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
  function NTSTATUS (line 405) | NTSTATUS remove_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING de...
  function disk_arrival (line 458) | void disk_arrival(PUNICODE_STRING devpath) {
  function remove_volume_child (line 529) | void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->...
  function volume_arrival (line 691) | bool volume_arrival(PUNICODE_STRING devpath, bool fve_callback) {
  function volume_arrival2 (line 789) | static void volume_arrival2(PUNICODE_STRING devpath) {
  function volume_removal (line 793) | void volume_removal(PUNICODE_STRING devpath) {
  type pnp_callback_context (line 850) | typedef struct {
  function do_pnp_callback (line 856) | _Function_class_(IO_WORKITEM_ROUTINE)
  function enqueue_pnp_callback (line 872) | static void enqueue_pnp_callback(PUNICODE_STRING name, pnp_callback func) {
  function volume_notification (line 912) | _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE)
  function pnp_notification (line 926) | _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE)
  function mountmgr_process_drive (line 940) | static void mountmgr_process_drive(PDEVICE_OBJECT mountmgr, PUNICODE_STR...
  function mountmgr_updated (line 1012) | static void mountmgr_updated(PDEVICE_OBJECT mountmgr, MOUNTMGR_MOUNT_POI...
  function mountmgr_thread (line 1042) | _Function_class_(KSTART_ROUTINE)

FILE: src/security.c
  type sid_header (line 23) | typedef struct {
  type dacl (line 35) | typedef struct {
  function add_user_mapping (line 56) | void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, uint32_t ...
  function add_group_mapping (line 145) | void add_group_mapping(WCHAR* sidstring, ULONG sidstringlength, uint32_t...
  function NTSTATUS (line 229) | NTSTATUS uid_to_sid(uint32_t uid, PSID* sid) {
  function sid_to_uid (line 310) | uint32_t sid_to_uid(PSID sid) {
  function gid_to_sid (line 341) | static void gid_to_sid(uint32_t gid, PSID* sid) {
  function ACL (line 372) | static ACL* load_default_acl() {
  function get_top_level_sd (line 415) | static void get_top_level_sd(fcb* fcb) {
  function fcb_get_sd (line 511) | void fcb_get_sd(fcb* fcb, struct _fcb* parent, bool look_for_xattr, PIRP...
  function NTSTATUS (line 636) | static NTSTATUS get_file_security(PFILE_OBJECT FileObject, SECURITY_DESC...
  function NTSTATUS (line 756) | static NTSTATUS set_file_security(device_extension* Vcb, PFILE_OBJECT Fi...
  function search_for_gid (line 906) | static bool search_for_gid(fcb* fcb, PSID sid) {
  function find_gid (line 924) | void find_gid(struct _fcb* fcb, struct _fcb* parfcb, PSECURITY_SUBJECT_C...
  function NTSTATUS (line 988) | NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* parfileref, ACCESS_STATE* as) {

FILE: src/send.c
  type send_dir (line 21) | typedef struct send_dir {
  type orphan (line 34) | typedef struct {
  type deleted_child (line 42) | typedef struct {
  type ref (line 48) | typedef struct {
  type pending_rmdir (line 55) | typedef struct {
  type send_ext (line 61) | typedef struct {
  type send_context (line 68) | typedef struct {
  function send_command (line 116) | static void send_command(send_context* context, uint16_t cmd) {
  function send_command_finish (line 125) | static void send_command_finish(send_context* context, ULONG pos) {
  function send_add_tlv (line 132) | static void send_add_tlv(send_context* context, uint16_t type, void* dat...
  function NTSTATUS (line 164) | static NTSTATUS get_orphan_name(send_context* context, uint64_t inode, u...
  function add_orphan (line 217) | static void add_orphan(send_context* context, orphan* o) {
  function NTSTATUS (line 235) | static NTSTATUS send_read_symlink(send_context* context, uint64_t inode,...
  function NTSTATUS (line 283) | static NTSTATUS send_inode(send_context* context, traverse_ptr* tp, trav...
  function NTSTATUS (line 497) | static NTSTATUS send_add_dir(send_context* context, uint64_t inode, send...
  function find_path_len (line 560) | static __inline uint16_t find_path_len(send_dir* parent, uint16_t namele...
  function find_path (line 571) | static void find_path(char* path, send_dir* parent, char* name, ULONG na...
  function send_add_tlv_path (line 586) | static void send_add_tlv_path(send_context* context, uint16_t type, send...
  function NTSTATUS (line 595) | static NTSTATUS found_path(send_context* context, send_dir* parent, char...
  function send_utimes_command_dir (line 656) | static void send_utimes_command_dir(send_context* context, send_dir* sd,...
  function NTSTATUS (line 670) | static NTSTATUS find_send_dir(send_context* context, uint64_t dir, uint6...
  function NTSTATUS (line 770) | static NTSTATUS send_inode_ref(send_context* context, traverse_ptr* tp, ...
  function NTSTATUS (line 872) | static NTSTATUS send_inode_extref(send_context* context, traverse_ptr* t...
  function send_subvol_header (line 969) | static void send_subvol_header(send_context* context, root* r, file_ref*...
  function send_chown_command (line 988) | static void send_chown_command(send_context* context, char* path, uint64...
  function send_chmod_command (line 1000) | static void send_chmod_command(send_context* context, char* path, uint64...
  function send_utimes_command (line 1013) | static void send_utimes_command(send_context* context, char* path, BTRFS...
  function send_truncate_command (line 1026) | static void send_truncate_command(send_context* context, char* path, uin...
  function NTSTATUS (line 1037) | static NTSTATUS send_unlink_command(send_context* context, send_dir* par...
  function send_rmdir_command (line 1053) | static void send_rmdir_command(send_context* context, uint16_t pathlen, ...
  function NTSTATUS (line 1061) | static NTSTATUS get_dir_last_child(send_context* context, uint64_t* last...
  function NTSTATUS (line 1103) | static NTSTATUS add_pending_rmdir(send_context* context, uint64_t last_i...
  function NTSTATUS (line 1133) | static NTSTATUS look_for_collision(send_context* context, send_dir* sd, ...
  function NTSTATUS (line 1175) | static NTSTATUS make_file_orphan(send_context* context, uint64_t inode, ...
  function NTSTATUS (line 1274) | static NTSTATUS flush_refs(send_context* context, traverse_ptr* tp1, tra...
  function NTSTATUS (line 1602) | static NTSTATUS wait_for_flush(send_context* context, traverse_ptr* tp1,...
  function NTSTATUS (line 1652) | static NTSTATUS add_ext_holes(device_extension* Vcb, LIST_ENTRY* exts, u...
  function NTSTATUS (line 1713) | static NTSTATUS divide_ext(send_ext* ext, uint64_t len, bool trunc) {
  function NTSTATUS (line 1785) | static NTSTATUS sync_ext_cutoff_points(send_context* context) {
  function send_add_tlv_clone_path (line 1841) | static bool send_add_tlv_clone_path(send_context* context, root* r, uint...
  function try_clone_edr (line 1937) | static bool try_clone_edr(send_context* context, send_ext* se, EXTENT_DA...
  function try_clone (line 2028) | static bool try_clone(send_context* context, send_ext* se) {
  function NTSTATUS (line 2127) | static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, ...
  function NTSTATUS (line 2532) | static NTSTATUS finish_inode(send_context* context, traverse_ptr* tp1, t...
  function NTSTATUS (line 2619) | static NTSTATUS send_extent_data(send_context* context, traverse_ptr* tp...
  type xattr_cmp (line 2760) | typedef struct {
  function NTSTATUS (line 2770) | static NTSTATUS send_xattr(send_context* context, traverse_ptr* tp, trav...
  function send_thread (line 2970) | _Function_class_(KSTART_ROUTINE)
  type _fcb (line 3655) | struct _fcb
  type _fcb (line 3697) | struct _fcb
  function NTSTATUS (line 3839) | NTSTATUS read_send_buffer(device_extension* Vcb, PFILE_OBJECT FileObject...

FILE: src/sha256.c
  type buffer_state (line 35) | struct buffer_state {
  function right_rot (line 43) | static inline uint32_t right_rot(uint32_t value, unsigned int count)
  function init_buf_state (line 52) | static void init_buf_state(struct buffer_state * state, const void * inp...
  function calc_chunk (line 62) | static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * s...
  function calc_sha256 (line 126) | void calc_sha256(uint8_t* hash, const void* input, size_t len)

FILE: src/shellext/balance.cpp
  function WCHAR (line 36) | static WCHAR hex_digit(uint8_t u) {
  function serialize (line 43) | static void serialize(void* data, ULONG len, WCHAR* s) {
  function INT_PTR (line 489) | INT_PTR CALLBACK BtrfsBalance::BalanceOptsDlgProc(HWND hwndDlg, UINT uMs...
  function INT_PTR (line 815) | static INT_PTR CALLBACK stub_BalanceOptsDlgProc(HWND hwndDlg, UINT uMsg,...
  function INT_PTR (line 836) | INT_PTR CALLBACK BtrfsBalance::BalanceDlgProc(HWND hwndDlg, UINT uMsg, W...
  function INT_PTR (line 940) | static INT_PTR CALLBACK stub_BalanceDlgProc(HWND hwndDlg, UINT uMsg, WPA...
  function from_hex_digit (line 1018) | static uint8_t from_hex_digit(WCHAR c) {
  function unserialize (line 1027) | static void unserialize(void* data, ULONG len, WCHAR* s) {
  function StartBalanceW (line 1041) | void CALLBACK StartBalanceW(HWND hwnd, HINSTANCE, LPWSTR lpszCmdLine, in...
  function PauseBalanceW (line 1102) | void CALLBACK PauseBalanceW(HWND hwnd, HINSTANCE, LPWSTR lpszCmdLine, in...
  function StopBalanceW (line 1149) | void CALLBACK StopBalanceW(HWND hwnd, HINSTANCE, LPWSTR lpszCmdLine, int) {

FILE: src/shellext/balance.h
  function class (line 23) | class BtrfsBalance {

FILE: src/shellext/contextmenu.cpp
  function HRESULT (line 55) | HRESULT __stdcall BtrfsContextMenu::QueryInterface(REFIID riid, void **p...
  function HRESULT (line 70) | HRESULT __stdcall BtrfsContextMenu::Initialize(PCIDLIST_ABSOLUTE pidlFol...
  function get_volume_path_parent (line 169) | static bool get_volume_path_parent(const WCHAR* fn, WCHAR* volpath, ULON...
  function show_reflink_paste (line 189) | static bool show_reflink_paste(const wstring& path) {
  function InitBitmapInfo (line 245) | static void InitBitmapInfo(BITMAPINFO* pbmi, ULONG cbInfo, LONG cx, LONG...
  function HRESULT (line 256) | static HRESULT Create32BitHBITMAP(HDC hdc, const SIZE *psize, void **ppv...
  function HRESULT (line 316) | HRESULT __stdcall BtrfsContextMenu::QueryContextMenu(HMENU hmenu, UINT i...
  function path_remove_file (line 403) | static void path_remove_file(wstring& path) {
  function path_strip_path (line 417) | static void path_strip_path(wstring& path) {
  function create_snapshot (line 428) | static void create_snapshot(HWND, const wstring& fn) {
  function sector_align (line 499) | static uint64_t __inline sector_align(uint64_t n, uint64_t a) {
  function HRESULT (line 922) | HRESULT __stdcall BtrfsContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO ...
  function HRESULT (line 1119) | HRESULT __stdcall BtrfsContextMenu::GetCommandString(UINT_PTR idCmd, UIN...
  function reflink_copy2 (line 1270) | static void reflink_copy2(const wstring& srcfn, const wstring& destdir, ...
  function ReflinkCopyW (line 1596) | void CALLBACK ReflinkCopyW(HWND, HINSTANCE, LPWSTR lpszCmdLine, int) {

FILE: src/shellext/contextmenu.h
  function virtual (line 35) | virtual ~BtrfsContextMenu() {
  function ULONG (line 49) | ULONG __stdcall AddRef() {
  function ULONG (line 53) | ULONG __stdcall Release() {

FILE: src/shellext/devices.cpp
  function wstring (line 36) | static wstring get_mountdev_name(const nt_handle& h ) {
  function find_devices (line 65) | static void find_devices(HWND, const GUID* guid, const mountmgr& mm, vec...
  function sort_devices (line 302) | static bool sort_devices(device i, device j) {
  function INT_PTR (line 547) | INT_PTR CALLBACK BtrfsDeviceAdd::DeviceAddDlgProc(HWND hwndDlg, UINT uMs...
  function INT_PTR (line 607) | static INT_PTR CALLBACK stub_DeviceAddDlgProc(HWND hwndDlg, UINT uMsg, W...
  function INT_PTR (line 676) | INT_PTR CALLBACK BtrfsDeviceResize::DeviceResizeDlgProc(HWND hwndDlg, UI...
  function INT_PTR (line 802) | static INT_PTR CALLBACK stub_DeviceResizeDlgProc(HWND hwndDlg, UINT uMsg...
  function AddDeviceW (line 826) | void CALLBACK AddDeviceW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine,...
  function RemoveDeviceW (line 854) | void CALLBACK RemoveDeviceW(HWND hwnd, HINSTANCE, LPWSTR lpszCmdLine, in...
  function ResizeDeviceW (line 915) | void CALLBACK ResizeDeviceW(HWND hwnd, HINSTANCE, LPWSTR lpszCmdLine, in...

FILE: src/shellext/devices.h
  type device (line 25) | typedef struct {
  type fs_identifier (line 41) | typedef struct {
  function class (line 127) | class BtrfsDeviceAdd {
  function class (line 144) | class BtrfsDeviceResize {

FILE: src/shellext/factory.cpp
  function HRESULT (line 26) | HRESULT __stdcall Factory::QueryInterface(const IID& iid, void** ppv) {
  function HRESULT (line 39) | HRESULT __stdcall Factory::LockServer(BOOL) {
  function HRESULT (line 43) | HRESULT __stdcall Factory::CreateInstance(IUnknown* pUnknownOuter, const...

FILE: src/shellext/factory.h
  type factory_type (line 22) | typedef enum {
  function class (line 30) | class Factory : public IClassFactory {

FILE: src/shellext/iconoverlay.cpp
  function HRESULT (line 24) | HRESULT __stdcall BtrfsIconOverlay::QueryInterface(REFIID riid, void **p...
  function HRESULT (line 35) | HRESULT __stdcall BtrfsIconOverlay::GetOverlayInfo(PWSTR pwszIconFile, i...
  function HRESULT (line 54) | HRESULT __stdcall BtrfsIconOverlay::GetPriority(int *pPriority) noexcept {
  function HRESULT (line 63) | HRESULT __stdcall BtrfsIconOverlay::IsMemberOf(PCWSTR pwszPath, DWORD) n...

FILE: src/shellext/iconoverlay.h
  function class (line 24) | class BtrfsIconOverlay : public IShellIconOverlayIdentifier {

FILE: src/shellext/main.cpp
  type _PROCESS_DPI_AWARENESS (line 38) | enum _PROCESS_DPI_AWARENESS {
  function set_dpi_aware (line 50) | void set_dpi_aware() {
  function format_size (line 65) | void format_size(uint64_t size, wstring& s, bool show_bytes) {
  function wstring (line 156) | wstring format_message(ULONG last_error) {
  function wstring (line 176) | wstring format_ntstatus(NTSTATUS Status) {
  function load_string (line 198) | bool load_string(HMODULE module, UINT id, wstring& s) {
  function wstring_sprintf (line 217) | void wstring_sprintf(wstring& s, wstring fmt, ...) {
  function STDAPI (line 238) | STDAPI DllCanUnloadNow(void) {
  function STDAPI (line 242) | STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
  function write_reg_key (line 284) | static void write_reg_key(HKEY root, const wstring& keyname, const WCHAR...
  function register_clsid (line 302) | static void register_clsid(const GUID clsid, const WCHAR* description) {
  function reg_delete_tree (line 329) | static void reg_delete_tree(HKEY hkey, const wstring& keyname) {
  function unregister_clsid (line 381) | static void unregister_clsid(const GUID clsid) {
  function reg_icon_overlay (line 396) | static void reg_icon_overlay(const GUID clsid, const wstring& name) {
  function unreg_icon_overlay (line 413) | static void unreg_icon_overlay(const wstring& name) {
  function reg_context_menu_handler (line 417) | static void reg_context_menu_handler(const GUID clsid, const wstring& fi...
  function unreg_context_menu_handler (line 432) | static void unreg_context_menu_handler(const wstring& filetype, const ws...
  function reg_prop_sheet_handler (line 436) | static void reg_prop_sheet_handler(const GUID clsid, const wstring& file...
  function unreg_prop_sheet_handler (line 451) | static void unreg_prop_sheet_handler(const wstring& filetype, const wstr...
  function STDAPI (line 455) | STDAPI DllRegisterServer(void) {
  function STDAPI (line 478) | STDAPI DllUnregisterServer(void) {
  function STDAPI (line 499) | STDAPI DllInstall(BOOL bInstall, LPCWSTR) {
  function BOOL (line 506) | BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void*) {
  function create_subvol (line 513) | static void create_subvol(const wstring& fn) {
  function CreateSubvolW (line 545) | void CALLBACK CreateSubvolW(HWND, HINSTANCE, LPWSTR lpszCmdLine, int) {
  function create_snapshot2 (line 554) | static void create_snapshot2(const wstring& source, const wstring& fn) {
  function CreateSnapshotW (line 591) | void CALLBACK CreateSnapshotW(HWND, HINSTANCE, LPWSTR lpszCmdLine, int) {
  function command_line_to_args (line 600) | void command_line_to_args(LPWSTR cmdline, vector<wstring>& args) {
  function string (line 625) | static string utf16_to_utf8(wstring_view utf16) {
  function wstring (line 689) | wstring utf8_to_utf16(string_view utf8) {
  function error_message (line 738) | void error_message(HWND hwnd, const char* msg) {

FILE: src/shellext/mappings.cpp
  class formatted_error (line 20) | class formatted_error : public exception {
    method formatted_error (line 23) | formatted_error(string_view s, Args&&... args) : msg(vformat(s, make_f...
  class lsa_handle_closer (line 34) | class lsa_handle_closer {
  class lsa_pointer_freer (line 46) | class lsa_pointer_freer {
  class hkey_closer (line 58) | class hkey_closer {
  class local_freer (line 70) | class local_freer {
  type mapping_entry (line 81) | struct mapping_entry {
  function unique_lsa_handle (line 89) | static unique_lsa_handle lsa_open_policy(ACCESS_MASK access) {
  function lsa_lookup_sids (line 104) | static void lsa_lookup_sids(LSA_HANDLE h, span<const PSID> sids,
  function resolve_names (line 120) | static void resolve_names(span<mapping_entry> entries) {
  function populate_list (line 154) | static void populate_list(HWND hwnd) {
  function init_dialog (line 245) | static void init_dialog(HWND hwnd) {
  function INT_PTR (line 289) | static INT_PTR CALLBACK MappingsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM ...
  function MappingsTest (line 329) | void CALLBACK MappingsTest(HWND hwnd, HINSTANCE, LPWSTR, int) {

FILE: src/shellext/mountmgr.h
  function class (line 10) | class mountmgr_point {
  function class (line 19) | class mountmgr {

FILE: src/shellext/propsheet.cpp
  type _FILE_ACCESS_INFORMATION (line 37) | struct _FILE_ACCESS_INFORMATION {
  type _FILE_STANDARD_INFORMATION (line 43) | struct _FILE_STANDARD_INFORMATION {
  type _FILE_FS_SIZE_INFORMATION (line 53) | struct _FILE_FS_SIZE_INFORMATION {
  function HRESULT (line 62) | HRESULT __stdcall BtrfsPropSheet::QueryInterface(REFIID riid, void **ppO...
  function DWORD (line 135) | DWORD BtrfsPropSheet::search_list_thread() {
  function DWORD (line 147) | static DWORD WINAPI global_search_list_thread(LPVOID lpParameter) {
  function HRESULT (line 153) | HRESULT BtrfsPropSheet::check_file(const wstring& fn, UINT i, UINT num_f...
  function HRESULT (line 299) | HRESULT BtrfsPropSheet::load_file_list() {
  function HRESULT (line 342) | HRESULT __stdcall BtrfsPropSheet::Initialize(PCIDLIST_ABSOLUTE pidlFolde...
  function ULONG (line 531) | static ULONG inode_type_to_string_ref(uint8_t type) {
  function INT_PTR (line 794) | static INT_PTR CALLBACK SizeDetailsDlgProc(HWND hwndDlg, UINT uMsg, WPAR...
  function set_check_box (line 839) | static void set_check_box(HWND hwndDlg, ULONG id, uint64_t min, uint64_t...
  function INT_PTR (line 1071) | static INT_PTR CALLBACK PropSheetDlgProc(HWND hwndDlg, UINT uMsg, WPARAM...
  function HRESULT (line 1288) | HRESULT __stdcall BtrfsPropSheet::AddPages(LPFNADDPROPSHEETPAGE pfnAddPa...
  function HRESULT (line 1331) | HRESULT __stdcall BtrfsPropSheet::ReplacePage(UINT, LPFNADDPROPSHEETPAGE...
  function ShowPropSheetW (line 1337) | void CALLBACK ShowPropSheetW(HWND hwnd, HINSTANCE, LPWSTR lpszCmdLine, i...

FILE: src/shellext/propsheet.h
  function virtual (line 119) | virtual ~BtrfsPropSheet() {
  function ULONG (line 130) | ULONG __stdcall AddRef() {
  function ULONG (line 134) | ULONG __stdcall Release() {

FILE: src/shellext/recv.cpp
  function unix_time_to_win (line 1065) | static __inline uint64_t unix_time_to_win(BTRFS_TIME* t) {
  function delete_directory (line 1112) | static void delete_directory(const wstring& dir) {
  function check_csum (line 1142) | static bool check_csum(btrfs_send_command* cmd, uint8_t* data) {
  function check_cpu (line 1362) | static void check_cpu() {
  function DWORD (line 1388) | DWORD BtrfsRecv::recv_thread() {
  function DWORD (line 1452) | static DWORD WINAPI global_recv_thread(LPVOID lpParameter) {
  function INT_PTR (line 1458) | INT_PTR CALLBACK BtrfsRecv::RecvProgressDlgProc(HWND hwndDlg, UINT uMsg,...
  function INT_PTR (line 1510) | static INT_PTR CALLBACK stub_RecvProgressDlgProc(HWND hwndDlg, UINT uMsg...
  function RecvSubvolGUIW (line 1543) | void CALLBACK RecvSubvolGUIW(HWND hwnd, HINSTANCE, LPWSTR lpszCmdLine, i...
  function RecvSubvolW (line 1618) | void CALLBACK RecvSubvolW(HWND, HINSTANCE, LPWSTR lpszCmdLine, int) {

FILE: src/shellext/recv.h
  type subvol_cache (line 25) | typedef struct {
  function class (line 31) | class BtrfsRecv {

FILE: src/shellext/scrub.cpp
  function wstring (line 32) | static wstring format_duration(uint64_t dur, const wchar_t* fmt) {
  function INT_PTR (line 437) | INT_PTR CALLBACK BtrfsScrub::ScrubDlgProc(HWND hwndDlg, UINT uMsg, WPARA...
  function INT_PTR (line 481) | static INT_PTR CALLBACK stub_ScrubDlgProc(HWND hwndDlg, UINT uMsg, WPARA...
  function ShowScrubW (line 497) | void CALLBACK ShowScrubW(HWND hwnd, HINSTANCE, LPWSTR lpszCmdLine, int) {
  function StartScrubW (line 526) | void CALLBACK StartScrubW(HWND, HINSTANCE, LPWSTR lpszCmdLine, int) {
  function StopScrubW (line 562) | void CALLBACK StopScrubW(HWND, HINSTANCE, LPWSTR lpszCmdLine, int) {

FILE: src/shellext/scrub.h
  function class (line 24) | class BtrfsScrub {

FILE: src/shellext/send.cpp
  function DWORD (line 27) | DWORD BtrfsSend::Thread() {
  function DWORD (line 224) | static DWORD WINAPI send_thread(LPVOID lpParameter) {
  function INT_PTR (line 417) | INT_PTR BtrfsSend::SendDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, L...
  function INT_PTR (line 509) | static INT_PTR CALLBACK stub_SendDlgProc(HWND hwndDlg, UINT uMsg, WPARAM...
  function SendSubvolGUIW (line 531) | void CALLBACK SendSubvolGUIW(HWND hwnd, HINSTANCE, LPWSTR lpszCmdLine, i...
  function send_subvol (line 560) | static void send_subvol(const wstring& subvol, const wstring& file, cons...
  function SendSubvolW (line 673) | void CALLBACK SendSubvolW(HWND, HINSTANCE, LPWSTR lpszCmdLine, int) {

FILE: src/shellext/send.h
  function class (line 22) | class BtrfsSend {

FILE: src/shellext/shellext.h
  type FS_INFORMATION_CLASS (line 95) | typedef enum _FSINFOCLASS {
  type FILE_STREAM_INFORMATION (line 113) | typedef struct _FILE_STREAM_INFORMATION {
  type REPARSE_DATA_BUFFER (line 126) | typedef struct _REPARSE_DATA_BUFFER {
  type DUPLICATE_EXTENTS_DATA (line 159) | typedef struct _DUPLICATE_EXTENTS_DATA {
  type FSCTL_GET_INTEGRITY_INFORMATION_BUFFER (line 166) | typedef struct _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER {
  type FSCTL_SET_INTEGRITY_INFORMATION_BUFFER (line 174) | typedef struct _FSCTL_SET_INTEGRITY_INFORMATION_BUFFER {
  function class (line 182) | class win_handle {

FILE: src/shellext/volpropsheet.cpp
  function HRESULT (line 36) | HRESULT __stdcall BtrfsVolPropSheet::QueryInterface(REFIID riid, void **...
  function HRESULT (line 51) | HRESULT __stdcall BtrfsVolPropSheet::Initialize(PCIDLIST_ABSOLUTE pidlFo...
  function INT_PTR (line 439) | INT_PTR CALLBACK BtrfsVolPropSheet::UsageDlgProc(HWND hwndDlg, UINT uMsg...
  function INT_PTR (line 518) | static INT_PTR CALLBACK stub_UsageDlgProc(HWND hwndDlg, UINT uMsg, WPARA...
  function add_lv_column (line 538) | static void add_lv_column(HWND list, int string, int cx) {
  function lv_sort (line 551) | static int CALLBACK lv_sort(LPARAM lParam1, LPARAM lParam2, LPARAM) {
  function find_dev_alloc (line 560) | static uint64_t find_dev_alloc(uint64_t dev_id, btrfs_usage* usage) {
  function INT_PTR (line 815) | INT_PTR CALLBACK BtrfsVolPropSheet::StatsDlgProc(HWND hwndDlg, UINT uMsg...
  function INT_PTR (line 890) | static INT_PTR CALLBACK stub_StatsDlgProc(HWND hwndDlg, UINT uMsg, WPARA...
  function INT_PTR (line 912) | INT_PTR CALLBACK BtrfsVolPropSheet::DeviceDlgProc(HWND hwndDlg, UINT uMs...
  function INT_PTR (line 1187) | static INT_PTR CALLBACK stub_DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPAR...
  function INT_PTR (line 1259) | static INT_PTR CALLBACK PropSheetDlgProc(HWND hwndDlg, UINT uMsg, WPARAM...
  function HRESULT (line 1359) | HRESULT __stdcall BtrfsVolPropSheet::AddPages(LPFNADDPROPSHEETPAGE pfnAd...
  function HRESULT (line 1402) | HRESULT __stdcall BtrfsVolPropSheet::ReplacePage(UINT, LPFNADDPROPSHEETP...
  function INT_PTR (line 1448) | INT_PTR BtrfsChangeDriveLetter::DlgProc(HWND hwndDlg, UINT uMsg, WPARAM ...
  function INT_PTR (line 1515) | static INT_PTR __stdcall dlg_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam...
  function ResetStatsW (line 1533) | void CALLBACK ResetStatsW(HWND hwnd, HINSTANCE, LPWSTR lpszCmdLine, int) {
  function ShowChangeDriveLetterW (line 1587) | void CALLBACK ShowChangeDriveLetterW(HWND hwnd, HINSTANCE, LPWSTR lpszCm...

FILE: src/shellext/volpropsheet.h
  function virtual (line 41) | virtual ~BtrfsVolPropSheet() {
  function ULONG (line 58) | ULONG __stdcall AddRef() {
  function ULONG (line 62) | ULONG __stdcall Release() {
  function class (line 108) | class BtrfsChangeDriveLetter {

FILE: src/tests/create.cpp
  function OBJECT_BASIC_INFORMATION (line 8) | static OBJECT_BASIC_INFORMATION query_object_basic_information(HANDLE h) {
  function check_dir_entry (line 52) | static void check_dir_entry(const u16string& dir, u16string_view name,
  function test_create (line 120) | void test_create(HANDLE token, const u16string& dir) {
  function unique_handle (line 1110) | static unique_handle open_by_id(HANDLE dir, const T& id, ACCESS_MASK acc...
  function create_or_get_object_id (line 1157) | static array<uint8_t, 16> create_or_get_object_id(HANDLE h) {
  function test_open_id (line 1186) | void test_open_id(HANDLE token, const u16string& dir) {

FILE: src/tests/cs.cpp
  function set_case_sensitive (line 5) | static void set_case_sensitive(HANDLE h, bool case_sensitive) {
  function unique_handle (line 21) | static unique_handle create_file_cs(u16string_view path, ACCESS_MASK acc...
  function test_cs (line 65) | void test_cs(const u16string& dir) {

FILE: src/tests/delete.cpp
  function set_disposition_information (line 5) | void set_disposition_information(HANDLE h, bool delete_file) {
  function set_disposition_information_ex (line 23) | void set_disposition_information_ex(HANDLE h, uint32_t flags) {
  function test_delete (line 41) | void test_delete(const u16string& dir) {
  function test_delete_ex (line 838) | void test_delete_ex(HANDLE token, const u16string& dir) {

FILE: src/tests/ea.cpp
  type _FILE_FULL_EA_INFORMATION (line 7) | struct _FILE_FULL_EA_INFORMATION {
  function ea_size (line 16) | static constexpr uint32_t ea_size(string_view name, string_view value) {
  function write_ea (line 25) | void write_ea(HANDLE h, string_view name, string_view value, bool need_e...
  function write_eas (line 50) | static void write_eas(HANDLE h, const array<pair<string_view, string_vie...
  function read_ea (line 88) | static vector<varbuf<FILE_FULL_EA_INFORMATION>> read_ea(HANDLE h) {
  function unique_handle (line 122) | static unique_handle create_file_ea(u16string_view path, ACCESS_MASK acc...
  function check_ea_dirent (line 196) | static void check_ea_dirent(const u16string& dir, u16string_view name, u...
  function read_eas (line 215) | static vector<varbuf<FILE_FULL_EA_INFORMATION>> read_eas(HANDLE h, const...
  function test_ea (line 285) | void test_ea(const u16string& dir) {

FILE: src/tests/fileinfo.cpp
  function set_basic_information (line 5) | void set_basic_information(HANDLE h, int64_t creation_time, int64_t last...
  function test_fileinfo (line 26) | void test_fileinfo(const u16string& dir) {

FILE: src/tests/io.cpp
  function adjust_token_privileges (line 10) | void adjust_token_privileges(HANDLE token, const LUID_AND_ATTRIBUTES& pr...
  function set_allocation (line 24) | void set_allocation(HANDLE h, uint64_t alloc) {
  function random_data (line 40) | vector<uint8_t> random_data(size_t len) {
  function write_file (line 54) | void write_file(HANDLE h, span<const uint8_t> data, optional<uint64_t> o...
  function unique_handle (line 73) | unique_handle create_event() {
  function write_file_wait (line 85) | void write_file_wait(HANDLE h, span<const uint8_t> data, optional<uint64...
  function read_file (line 114) | vector<uint8_t> read_file(HANDLE h, ULONG len, optional<uint64_t> offset) {
  function read_file_wait (line 140) | vector<uint8_t> read_file_wait(HANDLE h, ULONG len, optional<uint64_t> o...
  function set_position (line 176) | static void set_position(HANDLE h, uint64_t pos) {
  function set_valid_data_length (line 194) | void set_valid_data_length(HANDLE h, uint64_t vdl) {
  function set_end_of_file (line 210) | void set_end_of_file(HANDLE h, uint64_t eof) {
  function set_zero_data (line 226) | void set_zero_data(HANDLE h, uint64_t start, uint64_t end) {
  function test_io (line 252) | void test_io(HANDLE token, const u16string& dir) {

FILE: src/tests/links.cpp
  function query_links (line 5) | vector<pair<int64_t, u16string>> query_links(HANDLE h) {
  function set_link_information (line 53) | void set_link_information(HANDLE h, bool replace_if_exists, HANDLE root_...
  function set_link_information_ex (line 73) | static void set_link_information_ex(HANDLE h, ULONG flags, HANDLE root_d...
  function test_links (line 93) | void test_links(HANDLE token, const std::u16string& dir) {
  function test_links_ex (line 947) | void test_links_ex(HANDLE token, const u16string& dir) {

FILE: src/tests/mmap.cpp
  function unique_handle (line 5) | unique_handle create_section(ACCESS_MASK access, optional<uint64_t> max_...
  function unmap_view (line 42) | static void unmap_view(void* addr) {
  function lock_file (line 51) | static void lock_file(HANDLE h, uint64_t offset, uint64_t length, bool e...
  function align (line 66) | static constexpr unsigned int align(unsigned int x, unsigned int a) {
  function pe_image (line 70) | vector<uint8_t> pe_image(span<const std::byte> data) {
  function test_mmap (line 147) | void test_mmap(const u16string& dir) {

FILE: src/tests/oplock.cpp
  type oplock_type (line 26) | enum oplock_type {
  function unique_handle (line 37) | static unique_handle req_oplock(HANDLE h, IO_STATUS_BLOCK& iosb, enum op...
  function unique_handle (line 82) | static unique_handle req_oplock_win7(HANDLE h, IO_STATUS_BLOCK& iosb, en...
  function check_event (line 132) | static bool check_event(HANDLE h) {
  function lock_file_wait (line 144) | static void lock_file_wait(HANDLE h, uint64_t offset, uint64_t length, b...
  function unlock_file (line 169) | static void unlock_file(HANDLE h, uint64_t offset, uint64_t length) {
  function test_oplocks_ii (line 183) | void test_oplocks_ii(HANDLE token, const u16string& dir) {
  function test_oplocks_r (line 926) | void test_oplocks_r(HANDLE token, const u16string& dir) {
  function DWORD (line 1701) | static DWORD __stdcall wait_and_acknowledge(void* param) {
  function ack_oplock (line 1718) | static void ack_oplock(HANDLE event, HANDLE h) {
  function DWORD (line 1735) | static DWORD __stdcall wait_and_acknowledge_win7(void* param) {
  function ack_oplock_win7 (line 1762) | static void ack_oplock_win7(HANDLE event, HANDLE h) {
  function test_oplocks_i (line 1779) | void test_oplocks_i(HANDLE token, const u16string& dir) {
  function test_oplocks_rw (line 2440) | void test_oplocks_rw(HANDLE token, const u16string& dir) {
  function test_oplocks_batch (line 3117) | void test_oplocks_batch(HANDLE token, const u16string& dir) {
  function test_oplocks_rwh (line 3776) | void test_oplocks_rwh(HANDLE token, const u16string& dir) {
  function test_oplocks_filter (line 4449) | void test_oplocks_filter(HANDLE token, const u16string& dir) {
  function test_oplocks_rh (line 5090) | void test_oplocks_rh(HANDLE token, const u16string& dir) {

FILE: src/tests/overwrite.cpp
  function test_overwrite (line 5) | void test_overwrite(const u16string& dir) {

FILE: src/tests/rename.cpp
  function set_rename_information (line 5) | void set_rename_information(HANDLE h, bool replace_if_exists, HANDLE roo...
  function set_rename_information_ex (line 25) | static void set_rename_information_ex(HANDLE h, ULONG flags, HANDLE root...
  function test_rename (line 45) | void test_rename(const u16string& dir) {
  function test_rename_ex (line 1236) | void test_rename_ex(HANDLE token, const u16string& dir) {

FILE: src/tests/reparse.cpp
  function set_symlink (line 20) | static void set_symlink(HANDLE h, u16string_view substitute_name, u16str...
  function set_mount_point (line 61) | static void set_mount_point(HANDLE h, u16string_view substitute_name, u1...
  function set_ms_reparse_point (line 108) | static void set_ms_reparse_point(HANDLE h, uint32_t tag, span<const uint...
  function set_reparse_point_guid (line 141) | static void set_reparse_point_guid(HANDLE h, uint32_t tag, const uint8_t...
  function query_reparse_point (line 174) | static varbuf<REPARSE_DATA_BUFFER> query_reparse_point(HANDLE h) {
  function query_reparse_point_guid (line 207) | static varbuf<REPARSE_GUID_DATA_BUFFER> query_reparse_point_guid(HANDLE ...
  function delete_reparse_point (line 240) | static void delete_reparse_point(HANDLE h, uint32_t tag) {
  function delete_reparse_point_guid (line 268) | static void delete_reparse_point_guid(HANDLE h, uint32_t tag, const uint...
  function check_reparse_dirent (line 298) | static void check_reparse_dirent(const u16string& dir, u16string_view na...
  function test_reparse (line 324) | void test_reparse(HANDLE token, const u16string& dir) {

FILE: src/tests/security.cpp
  function unique_handle (line 34) | static unique_handle create_file_sd(u16string_view path, ACCESS_MASK acc...
  function unique_handle (line 72) | static unique_handle create_file_with_acl(u16string_view path, ACCESS_MA...
  function set_dacl (line 102) | void set_dacl(HANDLE h, ACCESS_MASK access) {
  function get_acl (line 136) | static vector<varbuf<ACE_HEADER>> get_acl(HANDLE h, unsigned int type) {
  function string (line 202) | static string sid_to_string(span<const uint8_t> sid) {
  function compare_sid (line 237) | static bool compare_sid(span<const uint8_t> sid1, span<const uint8_t> si...
  function set_owner (line 256) | static void set_owner(HANDLE h, span<const uint8_t> sid) {
  function get_owner (line 272) | static vector<uint8_t> get_owner(HANDLE h) {
  function set_group (line 318) | static void set_group(HANDLE h, span<const uint8_t> sid) {
  function get_group (line 334) | static vector<uint8_t> get_group(HANDLE h) {
  function set_audit (line 381) | static void set_audit(HANDLE h, ACCESS_MASK access, span<const uint8_t, ...
  function set_mandatory_access (line 416) | static void set_mandatory_access(HANDLE h, ACCESS_MASK access, span<cons...
  function unique_handle (line 450) | static unique_handle duplicate_token(HANDLE token) {
  function adjust_token_level (line 473) | static void adjust_token_level(HANDLE token, const void* sid) {
  function set_thread_token (line 486) | static void set_thread_token(HANDLE token) {
  function test_security (line 496) | void test_security(HANDLE token, const u16string& dir) {

FILE: src/tests/streams.cpp
  type _FILE_STREAM_INFORMATION (line 6) | struct _FILE_STREAM_INFORMATION {
  function query_streams (line 15) | static vector<varbuf<FILE_STREAM_INFORMATION>> query_streams(HANDLE h) {
  function test_streams (line 55) | void test_streams(const u16string& dir) {

FILE: src/tests/supersede.cpp
  function test_supersede (line 5) | void test_supersede(const u16string& dir) {

FILE: src/tests/test.cpp
  type fs_type (line 30) | enum fs_type
  function unique_handle (line 34) | unique_handle create_file(u16string_view path, ACCESS_MASK access, ULONG...
  function query_all_information (line 76) | varbuf<FILE_ALL_INFORMATION> query_all_information(HANDLE h) {
  function T (line 108) | T query_information(HANDLE h) {
  function query_dir (line 181) | vector<varbuf<T>> query_dir(const u16string& dir, u16string_view filter) {
  function print (line 300) | void print(string_view s, Args&&... args) {
  function test (line 306) | void test(const string& msg, const function<void()>& func) {
  function exp_status (line 342) | void exp_status(const function<void()>& func, NTSTATUS Status) {
  function u16string (line 356) | u16string query_file_name_information(HANDLE h, bool normalized) {
  function unique_handle (line 393) | static unique_handle open_process_token(HANDLE process, ACCESS_MASK acce...
  function disable_token_privileges (line 405) | void disable_token_privileges(HANDLE token) {
  function string (line 414) | string u16string_to_string(u16string_view sv) {
  function do_tests (line 430) | static void do_tests(u16string_view name, const u16string& dir) {
  function u16string (line 540) | static u16string to_u16string(time_t n) {
  function fs_driver_path (line 551) | static bool fs_driver_path(HANDLE h, u16string_view driver) {
  class sc_handle_closer (line 573) | class sc_handle_closer {
  function get_environment_variable (line 582) | static optional<u16string> get_environment_variable(const u16string& nam...
  function u16string (line 604) | static u16string get_driver_path(const u16string& driver) {
  function string (line 652) | static string get_version(const u16string& fn) {
  function string (line 674) | static string driver_string(const u16string& driver) {
  function wmain (line 686) | int wmain(int argc, wchar_t* argv[]) {

FILE: src/tests/test.h
  function fs_type (line 41) | enum class fs_type {
  function class (line 4314) | class formatted_error : public std::exception {
  type fs_type (line 4362) | enum fs_type

FILE: src/treefuncs.c
  function NTSTATUS (line 21) | __attribute__((nonnull(1,3,4,5)))
  function NTSTATUS (line 195) | __attribute__((nonnull(1,2,3,4)))
  function NTSTATUS (line 221) | __attribute__((nonnull(1,2,3)))
  function free_tree (line 264) | __attribute__((nonnull(1)))
  function tree_data (line 321) | __attribute__((nonnull(1)))
  function tree_data (line 331) | __attribute__((nonnull(1,2)))
  function tree_data (line 341) | __attribute__((nonnull(1,2)))
  function NTSTATUS (line 351) | __attribute__((nonnull(1,2,3,4)))
  function NTSTATUS (line 377) | __attribute__((nonnull(1,2,3,4,5)))
  function NTSTATUS (line 453) | __attribute__((nonnull(1,2,3,4)))
  function NTSTATUS (line 559) | __attribute__((nonnull(1,2,3,4)))
  function NTSTATUS (line 580) | __attribute__((nonnull(1,2,3,4)))
  function find_next_item (line 605) | __attribute__((nonnull(1,2,3)))
  function tree_data (line 709) | __attribute__((nonnull(1)))
  function find_prev_item (line 719) | __attribute__((nonnull(1,2,3)))
  function free_trees_root (line 778) | __attribute__((nonnull(1,2)))
  function free_trees (line 816) | __attribute__((nonnull(1)))
  function add_rollback (line 860) | __attribute__((nonnull(1,3)))
  function NTSTATUS (line 882) | __attribute__((nonnull(1,2)))
  function NTSTATUS (line 1010) | __attribute__((nonnull(1,2)))
  function clear_rollback (line 1050) | __attribute__((nonnull(1)))
  function do_rollback (line 1072) | __attribute__((nonnull(1,2)))
  function NTSTATUS (line 1219) | __attribute__((nonnull(1,2,3)))
  function clear_batch_list (line 1251) | __attribute__((nonnull(1,2)))
  function add_delete_inode_extref (line 1273) | __attribute__((nonnull(1,2,3)))
  function NTSTATUS (line 1322) | __attribute__((nonnull(1,2,3,4,6,7)))
  function NTSTATUS (line 1907) | __attribute__((nonnull(1,2)))
  function NTSTATUS (line 2367) | __attribute__((nonnull(1,2)))

FILE: src/ubtrfs/ubtrfs.c
  type DSTRING (line 74) | typedef struct {
  type STREAM_MESSAGE (line 80) | typedef struct {
  type options (line 91) | typedef struct {
  function FORCEINLINE (line 98) | FORCEINLINE VOID InitializeListHead(PLIST_ENTRY ListHead) {
  function FORCEINLINE (line 102) | FORCEINLINE VOID InsertTailList(PLIST_ENTRY ListHead, PLIST_ENTRY Entry) {
  type btrfs_item (line 112) | typedef struct {
  type used_space_extent (line 119) | typedef struct {
  type btrfs_chunk (line 125) | typedef struct {
  type btrfs_root (line 134) | typedef struct {
  type btrfs_dev (line 142) | typedef struct {
  type TEXTOUTPUT (line 164) | typedef struct {
  type FMIFS_MEDIA_FLAG (line 169) | typedef enum {
  type CALLBACKCOMMAND (line 196) | typedef enum {
  function IsListEmpty (line 218) | static bool IsListEmpty(LIST_ENTRY* head) {
  function LIST_ENTRY (line 222) | static LIST_ENTRY* RemoveHeadList(LIST_ENTRY* head) {
  function NTSTATUS (line 233) | NTSTATUS WINAPI ChkdskEx(PUNICODE_STRING DriveRoot, BOOLEAN FixErrors, B...
  function btrfs_root (line 249) | static btrfs_root* add_root(LIST_ENTRY* roots, uint64_t id) {
  function free_roots (line 262) | static void free_roots(LIST_ENTRY* roots) {
  function free_chunks (line 289) | static void free_chunks(LIST_ENTRY* chunks) {
  function add_item (line 310) | static void add_item(btrfs_root* r, uint64_t obj_id, uint8_t obj_type, u...
  function find_chunk_offset (line 343) | static uint64_t find_chunk_offset(uint64_t size, uint64_t offset, btrfs_...
  function btrfs_chunk (line 363) | static btrfs_chunk* add_chunk(LIST_ENTRY* chunks, uint64_t flags, btrfs_...
  function superblock_collision (line 431) | static bool superblock_collision(btrfs_chunk* c, uint64_t address) {
  function get_next_address (line 452) | static uint64_t get_next_address(btrfs_chunk* c) {
  type EXTENT_ITEM_METADATA (line 467) | typedef struct {
  type EXTENT_ITEM_METADATA2 (line 473) | typedef struct {
  function assign_addresses (line 480) | static void assign_addresses(LIST_ENTRY* roots, btrfs_chunk* sys_chunk, ...
  function NTSTATUS (line 571) | static NTSTATUS write_data(HANDLE h, uint64_t address, btrfs_chunk* c, v...
  function calc_tree_checksum (line 591) | static void calc_tree_checksum(tree_header* th, uint32_t node_size) {
  function NTSTATUS (line 611) | static NTSTATUS write_roots(HANDLE h, LIST_ENTRY* roots, uint32_t node_s...
  function get_uuid (line 676) | static void get_uuid(BTRFS_UUID* uuid) {
  function init_device (line 687) | static void init_device(btrfs_dev* dev, uint64_t id, uint64_t size, BTRF...
  function calc_superblock_checksum (line 706) | static void calc_superblock_checksum(superblock* sb) {
  function NTSTATUS (line 726) | static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* ...
  function win_time_to_unix (line 837) | static __inline void win_time_to_unix(LARGE_INTEGER t, BTRFS_TIME* out) {
  function add_inode_ref (line 844) | static void add_inode_ref(btrfs_root* r, uint64_t inode, uint64_t parent...
  function init_fs_tree (line 857) | static void init_fs_tree(btrfs_root* r, uint32_t node_size) {
  function add_block_group_items (line 881) | static void add_block_group_items(LIST_ENTRY* chunks, btrfs_root* root) {
  function NTSTATUS (line 898) | static NTSTATUS clear_first_megabyte(HANDLE h) {
  function is_ssd (line 916) | static bool is_ssd(HANDLE h) {
  function add_dir_item (line 951) | static void add_dir_item(btrfs_root* root, uint64_t inode, uint32_t hash...
  function set_default_subvol (line 970) | static void set_default_subvol(btrfs_root* root_root, uint32_t node_size) {
  function populate_free_space_root (line 1002) | static void populate_free_space_root(LIST_ENTRY* chunks, btrfs_root* fre...
  function NTSTATUS (line 1042) | static NTSTATUS write_btrfs(HANDLE h, uint64_t size, PUNICODE_STRING lab...
  function look_for_device (line 1132) | static bool look_for_device(btrfs_filesystem* bfs, BTRFS_UUID* devuuid) {
  function check_superblock_checksum (line 1149) | static bool check_superblock_checksum(superblock* sb) {
  function is_mounted_multi_device (line 1184) | static bool is_mounted_multi_device(HANDLE h, uint32_t sector_size) {
  function do_full_trim (line 1281) | static void do_full_trim(HANDLE h) {
  function is_power_of_two (line 1298) | static bool is_power_of_two(ULONG i) {
  function check_cpu (line 1303) | static void check_cpu() {
  function NTSTATUS (line 1320) | static NTSTATUS NTAPI FormatEx2(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_F...
  function BOOL (line 1486) | BOOL __stdcall FormatEx(DSTRING* root, STREAM_MESSAGE* message, options*...
  function SetSizes (line 1509) | void __stdcall SetSizes(ULONG sector, ULONG node) {
  function SetIncompatFlags (line 1517) | void __stdcall SetIncompatFlags(uint64_t incompat_flags) {
  function SetCompatROFlags (line 1521) | void __stdcall SetCompatROFlags(uint64_t compat_ro_flags) {
  function SetCsumType (line 1525) | void __stdcall SetCsumType(uint16_t csum_type) {
  function BOOL (line 1529) | BOOL __stdcall GetFilesystemInformation(uint32_t unk1, uint32_t unk2, vo...
  function BOOL (line 1535) | BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) {

FILE: src/volume.c
  function NTSTATUS (line 36) | NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
  function free_vol (line 50) | void free_vol(volume_device_extension* vde) {
  function NTSTATUS (line 95) | NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
  type vol_read_context (line 127) | typedef struct {
  function vol_read_completion (line 132) | _Function_class_(IO_COMPLETION_ROUTINE)
  function NTSTATUS (line 144) | NTSTATUS vol_read(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
  function NTSTATUS (line 225) | NTSTATUS vol_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
  function NTSTATUS (line 306) | static NTSTATUS vol_query_device_name(volume_device_extension* vde, PIRP...
  function NTSTATUS (line 333) | static NTSTATUS vol_query_unique_id(volume_device_extension* vde, PIRP I...
  function NTSTATUS (line 363) | static NTSTATUS vol_is_dynamic(PIRP Irp) {
  function NTSTATUS (line 379) | static NTSTATUS vol_check_verify(volume_device_extension* vde) {
  function NTSTATUS (line 405) | static NTSTATUS vol_get_disk_extents(volume_device_extension* vde, PIRP ...
  function NTSTATUS (line 495) | static NTSTATUS vol_is_writable(volume_device_extension* vde) {
  function NTSTATUS (line 526) | static NTSTATUS vol_get_length(volume_device_extension* vde, PIRP Irp) {
  function NTSTATUS (line 557) | static NTSTATUS vol_get_drive_geometry(PDEVICE_OBJECT DeviceObject, PIRP...
  function NTSTATUS (line 595) | static NTSTATUS vol_get_gpt_attributes(PIRP Irp) {
  function NTSTATUS (line 611) | static NTSTATUS vol_get_device_number(volume_device_extension* vde, PIRP...
  function vol_ioctl_completion (line 649) | _Function_class_(IO_COMPLETION_ROUTINE)
  function NTSTATUS (line 661) | static NTSTATUS vol_ioctl_passthrough(volume_device_extension* vde, PIRP...
  function NTSTATUS (line 731) | static NTSTATUS vol_query_stable_guid(volume_device_extension* vde, PIRP...
  function NTSTATUS (line 755) | NTSTATUS vol_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
  function NTSTATUS (line 832) | NTSTATUS mountmgr_add_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STR...
  function pnp_removal (line 862) | _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE)
  function allow_degraded_mount (line 877) | static bool allow_degraded_mount(BTRFS_UUID* uuid) {
  type drive_letter_removal (line 951) | typedef struct {
  function drive_letter_callback2 (line 958) | static void drive_letter_callback2(pdo_device_extension* pdode, PDEVICE_...
  function drive_letter_callback (line 1058) | _Function_class_(IO_WORKITEM_ROUTINE)
  function add_volume_device (line 1077) | void add_volume_device(superblock* sb, PUNICODE_STRING devpath, uint64_t...

FILE: src/worker-thread.c
  type job_info (line 20) | typedef struct {
  function NTSTATUS (line 26) | NTSTATUS do_read_job(PIRP Irp) {
  function NTSTATUS (line 68) | NTSTATUS do_write_job(device_extension* Vcb, PIRP Irp) {
  function do_job (line 95) | _Function_class_(WORKER_THREAD_ROUTINE)
  function add_thread_job (line 109) | bool add_thread_job(device_extension* Vcb, PIRP Irp) {

FILE: src/write.c
  type write_stripe (line 20) | typedef struct {
  function find_data_address_in_chunk (line 38) | __attribute__((nonnull(1, 2, 4)))
  function chunk (line 90) | __attribute__((nonnull(1)))
  type stripe (line 113) | typedef struct {
  function find_new_chunk_address (line 118) | __attribute__((nonnull(1)))
  function find_new_dup_stripes (line 140) | __attribute__((nonnull(1,2)))
  function find_new_stripe (line 252) | __attribute__((nonnull(1,2)))
  function NTSTATUS (line 366) | __attribute__((nonnull(1,3)))
  function NTSTATUS (line 712) | __attribute__((nonnull(1,3,5,8)))
  function except (line 897) | except (EXCEPTION_EXECUTE_HANDLER) {
  function NTSTATUS (line 982) | __attribute__((nonnull(1,2,5)))
  type log_stripe (line 1065) | typedef struct {
  function NTSTATUS (line 1070) | __attribute__((nonnull(1,2,4,6,10)))
  function NTSTATUS (line 1469) | __attribute__((nonnull(1,2,4,6,10)))
  function NTSTATUS (line 1908) | __attribute__((nonnull(1,3,5)))
  function get_raid56_lock_range (line 2178) | __attribute__((nonnull(1,4,5)))
  function NTSTATUS (line 2195) | __attribute__((nonnull(1,3)))
  function except (line 2222) | except (EXCEPTION_EXECUTE_HANDLER) {
  function write_data_completion (line 2278) | __attribute__((nonnull(2,3)))
  function free_write_data_stripes (line 2322) | __attribute__((nonnull(1)))
  function add_extent (line 2383) | __attribute__((nonnull(1,2,3)))
  function NTSTATUS (line 2401) | __attribute__((nonnull(1,2,6)))
  function add_insert_extent_rollback (line 2737) | __attribute__((nonnull(1,2,3)))
  function NTSTATUS (line 2757) | __attribute__((nonnull(1,3,7)))
  function remove_fcb_extent (line 2801) | __attribute__((nonnull(1, 2, 3)))
  function insert_extent_chunk (line 2823) | __attribute__((nonnull(1,2,3,9)))
  function try_extend_data (line 2908) | __attribute__((nonnull(1,2,5,7,10)))
  function NTSTATUS (line 3001) | __attribute__((nonnull(1)))
  function NTSTATUS (line 3058) | __attribute__((nonnull(1,4)))
  function NTSTATUS (line 3132) | __attribute__((nonnull(1,2,5,9)))
  function NTSTATUS (line 3244) | __attribute__((nonnull(1,4)))
  function NTSTATUS (line 3336) | __attribute__((nonnull(1,6)))
  function NTSTATUS (line 3570) | __attribute__((nonnull(1,2,5,6,11)))
  function NTSTATUS (line 3930) | __attribute__((nonnull(1, 4)))
  function NTSTATUS (line 4098) | __attribute__((nonnull(1,2,4,5,11)))
  function except (line 4555) | except (EXCEPTION_EXECUTE_HANDLER) {
  function NTSTATUS (line 4590) | __attribute__((nonnull(1,2)))
  function _Function_class_ (line 4663) | _Dispatch_type_(IRP_MJ_WRITE)
  function except (line 4748) | except (EXCEPTION_EXECUTE_HANDLER) {

FILE: src/zstd-shim.h
  function ZSTD_free (line 12) | static void ZSTD_free(void* ptr) {
Condensed preview — 117 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,302K chars).
[
  {
    "path": ".github/workflows/build.yml",
    "chars": 4584,
    "preview": "name: build\non: [push]\nenv:\n   PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/etc/eselect/wine/bin\n"
  },
  {
    "path": ".gitmodules",
    "chars": 158,
    "preview": "[submodule \"src/zstd\"]\n\tpath = src/zstd\n\turl = https://github.com/facebook/zstd\n[submodule \"src/zlib\"]\n\tpath = src/zlib\n"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 12497,
    "preview": "cmake_minimum_required(VERSION 3.15)\n\nproject(btrfs VERSION 1.9.0)\n\noption(WITH_TEST \"Compile test program\" ON)\n\nif(MSVC"
  },
  {
    "path": "CMakeSettings.json",
    "chars": 3162,
    "preview": "{\n  \"configurations\": [\n    {\n      \"name\": \"x64-Debug\",\n      \"generator\": \"Ninja\",\n      \"configurationType\": \"Debug\""
  },
  {
    "path": "LICENCE",
    "chars": 7651,
    "preview": "                   GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007"
  },
  {
    "path": "README.md",
    "chars": 29661,
    "preview": "WinBtrfs v1.9\n-------------\n\nWinBtrfs is a Windows driver for the next-generation Linux filesystem Btrfs.\nA reimplementa"
  },
  {
    "path": "btrfs-dump.pl",
    "chars": 36886,
    "preview": "#!/usr/bin/perl\n\n# Quick and dirty btrfs tree dumper. Great for diff'ing, which btrfs-debug-tree isn't...\n# Do something"
  },
  {
    "path": "mingw-amd64.cmake",
    "chars": 817,
    "preview": "#\n# To Cross-compile, use:\n#  cmake -DCMAKE_TOOLCHAIN_FILE=../mingw.cmake ..\n#\n# the name of the target operating system"
  },
  {
    "path": "mingw-x86.cmake",
    "chars": 920,
    "preview": "#\n# To Cross-compile, use:\n#  cmake -DCMAKE_TOOLCHAIN_FILE=../mingw.cmake ..\n#\n# the name of the target operating system"
  },
  {
    "path": "msvc-aarch64.cmake",
    "chars": 390,
    "preview": "set(CMAKE_SYSTEM_NAME Windows)\n\nSET(CMAKE_C_COMPILER /opt/msvc/bin/arm64/cl)\nSET(CMAKE_CXX_COMPILER /opt/msvc/bin/arm64/"
  },
  {
    "path": "msvc-amd64.cmake",
    "chars": 384,
    "preview": "set(CMAKE_SYSTEM_NAME Windows)\n\nSET(CMAKE_C_COMPILER /opt/msvc/bin/x64/cl)\nSET(CMAKE_CXX_COMPILER /opt/msvc/bin/x64/cl)\n"
  },
  {
    "path": "msvc-armv7.cmake",
    "chars": 384,
    "preview": "set(CMAKE_SYSTEM_NAME Windows)\n\nSET(CMAKE_C_COMPILER /opt/msvc/bin/arm/cl)\nSET(CMAKE_CXX_COMPILER /opt/msvc/bin/arm/cl)\n"
  },
  {
    "path": "msvc-x86.cmake",
    "chars": 456,
    "preview": "set(CMAKE_SYSTEM_NAME Windows)\n\nSET(CMAKE_C_COMPILER /opt/msvc/bin/x86/cl)\nSET(CMAKE_CXX_COMPILER /opt/msvc/bin/x86/cl)\n"
  },
  {
    "path": "send-dump.pl",
    "chars": 7699,
    "preview": "#!/usr/bin/perl\n\n# Dumper for btrfs send streams.\n# Released under the same terms, or lack thereof, as btrfs-dump.pl.\n\no"
  },
  {
    "path": "src/balance.c",
    "chars": 135144,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/blake2-impl.h",
    "chars": 5085,
    "preview": "/*\n   BLAKE2 reference source code package - reference C implementations\n\n   Copyright 2012, Samuel Neves <sneves@dei.uc"
  },
  {
    "path": "src/blake2b-ref.c",
    "chars": 6753,
    "preview": "/*\n   BLAKE2 reference source code package - reference C implementations\n\n   Copyright 2012, Samuel Neves <sneves@dei.uc"
  },
  {
    "path": "src/boot.c",
    "chars": 12174,
    "preview": "/* Copyright (c) Mark Harmstone 2019\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/btrfs-vol.inf",
    "chars": 1979,
    "preview": ";;;\n;;; WinBtrfs\n;;;\n;;;\n;;; Copyright (c) 2016-24 Mark Harmstone\n;;;\n\n[Version]\nSignature   = \"$Windows NT$\"\nClass     "
  },
  {
    "path": "src/btrfs.c",
    "chars": 212023,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/btrfs.cdf",
    "chars": 3451,
    "preview": "[CatalogHeader]\nName=btrfs.cat\nCatalogVersion=1\nHashAlgorithms=SHA1\nPageHashes=true\nEncodingType=0x00010001\nCATATTR1=0x1"
  },
  {
    "path": "src/btrfs.h",
    "chars": 16097,
    "preview": "/* btrfs.h\n * Generic btrfs header file. Thanks to whoever it was who wrote\n * https://btrfs.wiki.kernel.org/index.php/O"
  },
  {
    "path": "src/btrfs.inf",
    "chars": 4545,
    "preview": ";;;\r\n;;; WinBtrfs\r\n;;;\r\n;;;\r\n;;; Copyright (c) 2016-24 Mark Harmstone\r\n;;;\r\n\r\n[Version]\r\nSignature   = \"$Windows NT$\"\r\nC"
  },
  {
    "path": "src/btrfs.rc.in",
    "chars": 2450,
    "preview": "// Microsoft Visual C++ generated resource script.\n//\n#include \"@CMAKE_CURRENT_SOURCE_DIR@/src/resource.h\"\n\n#define APST"
  },
  {
    "path": "src/btrfs_drv.h",
    "chars": 63645,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/btrfsioctl.h",
    "chars": 8972,
    "preview": "// No copyright claimed in this file - do what you want with it.\n\n#pragma once\n\n#include \"btrfs.h\"\n\n#define FSCTL_BTRFS_"
  },
  {
    "path": "src/cache.c",
    "chars": 2754,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/calcthread.c",
    "chars": 9165,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/compress.c",
    "chars": 35335,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n * Copyright (c) Reimar Doeffinger 2006\n * Copyright (c) Markus Oberhumer 1996\n "
  },
  {
    "path": "src/crc32c-aarch64.asm",
    "chars": 769,
    "preview": "    AREA .text, CODE, READONLY\n\n    GLOBAL calc_crc32c_hw\n\n; uint32_t calc_crc32c_hw(uint32_t seed, const uint8_t* buf, "
  },
  {
    "path": "src/crc32c-gas.S",
    "chars": 3185,
    "preview": "/* Copyright (c) Mark Harmstone 2020\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/crc32c-masm.asm",
    "chars": 3133,
    "preview": "; Copyright (c) Mark Harmstone 2020\n;\n; This file is part of WinBtrfs.\n;\n; WinBtrfs is free software: you can redistribu"
  },
  {
    "path": "src/crc32c.c",
    "chars": 4456,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/crc32c.h",
    "chars": 450,
    "preview": "#pragma once\n\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(_X86_) || defined(_AMD64_) || def"
  },
  {
    "path": "src/create.c",
    "chars": 181302,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/devctrl.c",
    "chars": 10068,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/dirctrl.c",
    "chars": 41913,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/extent-tree.c",
    "chars": 81295,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/fastio.c",
    "chars": 17722,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/fileinfo.c",
    "chars": 209796,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/flushthread.c",
    "chars": 275219,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/free-space.c",
    "chars": 72474,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/fsctl.c",
    "chars": 192954,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/fsrtl.c",
    "chars": 5422,
    "preview": "/*\n * PROJECT:         ReactOS Kernel - Vista+ APIs\n * LICENSE:         LGPL-2.1-or-later (https://spdx.org/licenses/LGP"
  },
  {
    "path": "src/galois.c",
    "chars": 7000,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/mkbtrfs/mkbtrfs.c",
    "chars": 12617,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/mkbtrfs/mkbtrfs.rc.in",
    "chars": 6344,
    "preview": "// Microsoft Visual C++ generated resource script.\n//\n#include \"@CMAKE_CURRENT_SOURCE_DIR@/src/mkbtrfs/resource.h\"\n\n#def"
  },
  {
    "path": "src/mkbtrfs/resource.h",
    "chars": 1124,
    "preview": "//{{NO_DEPENDENCIES}}\r\n// Microsoft Visual C++ generated include file.\r\n// Used by mkbtrfs.rc\r\n//\r\n#define IDS_USAGE    "
  },
  {
    "path": "src/pnp.c",
    "chars": 15097,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/read.c",
    "chars": 146099,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/registry.c",
    "chars": 36773,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/reparse.c",
    "chars": 22727,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/resource.h",
    "chars": 403,
    "preview": "//{{NO_DEPENDENCIES}}\r\n// Microsoft Visual C++ generated include file.\r\n// Used by btrfs.rc\r\n//\r\n\r\n// Next default value"
  },
  {
    "path": "src/scrub.c",
    "chars": 144975,
    "preview": "/* Copyright (c) Mark Harmstone 2017\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/search.c",
    "chars": 36565,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/security.c",
    "chars": 28566,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/send.c",
    "chars": 141807,
    "preview": "/* Copyright (c) Mark Harmstone 2017\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/sha256.c",
    "chars": 7211,
    "preview": "#include <stdint.h>\n#include <string.h>\n\n// Public domain code from https://github.com/amosnier/sha-2\n\n// FIXME - x86 SH"
  },
  {
    "path": "src/shellext/balance.cpp",
    "chars": 51212,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/balance.h",
    "chars": 1929,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/contextmenu.cpp",
    "chars": 60160,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/contextmenu.h",
    "chars": 2364,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/devices.cpp",
    "chars": 34283,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/devices.h",
    "chars": 5088,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/factory.cpp",
    "chars": 2949,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/factory.h",
    "chars": 1743,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/iconoverlay.cpp",
    "chars": 2494,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/iconoverlay.h",
    "chars": 1743,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/main.cpp",
    "chars": 21930,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/mappings.cpp",
    "chars": 9241,
    "preview": "#include \"shellext.h\"\n#include \"resource.h\"\n#include <windows.h>\n#include <commctrl.h>\n#include <sddl.h>\n#include <ntsta"
  },
  {
    "path": "src/shellext/mountmgr.cpp",
    "chars": 7591,
    "preview": "#include \"shellext.h\"\n#include \"mountmgr.h\"\n#include <mountmgr.h>\n\nusing namespace std;\n\nmountmgr::mountmgr() {\n    UNIC"
  },
  {
    "path": "src/shellext/mountmgr.h",
    "chars": 867,
    "preview": "#pragma once\n\n#include <vector>\n#include <string>\n#include <sstream>\n#include <string_view>\n#include <iostream>\n#include"
  },
  {
    "path": "src/shellext/propsheet.cpp",
    "chars": 44647,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/propsheet.h",
    "chars": 5244,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/recv.cpp",
    "chars": 64274,
    "preview": "/* Copyright (c) Mark Harmstone 2017\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/shellext/recv.h",
    "chars": 3009,
    "preview": "/* Copyright (c) Mark Harmstone 2017\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/shellext/resource.h",
    "chars": 16016,
    "preview": "//{{NO_DEPENDENCIES}}\r\n// Microsoft Visual C++ generated include file.\r\n// Used by shellbtrfs.rc\r\n//\r\n#define IDI_ICON1 "
  },
  {
    "path": "src/shellext/scrub.cpp",
    "chars": 21553,
    "preview": "/* Copyright (c) Mark Harmstone 2017\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/shellext/scrub.h",
    "chars": 1329,
    "preview": "/* Copyright (c) Mark Harmstone 2017\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/shellext/send.cpp",
    "chars": 25624,
    "preview": "/* Copyright (c) Mark Harmstone 2017\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/shellext/send.h",
    "chars": 1589,
    "preview": "/* Copyright (c) Mark Harmstone 2017\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/shellext/shellbtrfs.def",
    "chars": 732,
    "preview": "EXPORTS\r\n    DllCanUnloadNow     \tPRIVATE\r\n    DllGetClassObject   \tPRIVATE\r\n    DllRegisterServer   \tPRIVATE\r\n    DllUn"
  },
  {
    "path": "src/shellext/shellbtrfs.manifest",
    "chars": 585,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVers"
  },
  {
    "path": "src/shellext/shellbtrfs.rc.in",
    "chars": 35759,
    "preview": "// Microsoft Visual C++ generated resource script.\n//\n#include \"@CMAKE_CURRENT_SOURCE_DIR@/src/shellext/resource.h\"\n\n#de"
  },
  {
    "path": "src/shellext/shellext.h",
    "chars": 9012,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/volpropsheet.cpp",
    "chars": 51376,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/shellext/volpropsheet.h",
    "chars": 3344,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/tests/create.cpp",
    "chars": 63602,
    "preview": "#include \"test.h\"\n#include <array>\n\n#define FSCTL_CREATE_OR_GET_OBJECT_ID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 48, METHOD_B"
  },
  {
    "path": "src/tests/cs.cpp",
    "chars": 12561,
    "preview": "#include \"test.h\"\n\nusing namespace std;\n\nstatic void set_case_sensitive(HANDLE h, bool case_sensitive) {\n    NTSTATUS St"
  },
  {
    "path": "src/tests/delete.cpp",
    "chars": 58686,
    "preview": "#include \"test.h\"\n\nusing namespace std;\n\nvoid set_disposition_information(HANDLE h, bool delete_file) {\n    NTSTATUS Sta"
  },
  {
    "path": "src/tests/ea.cpp",
    "chars": 46892,
    "preview": "#include \"test.h\"\n#include <array>\n\nusing namespace std;\n\n#ifdef _MSC_VER\ntypedef struct _FILE_FULL_EA_INFORMATION {\n   "
  },
  {
    "path": "src/tests/fileinfo.cpp",
    "chars": 18855,
    "preview": "#include \"test.h\"\n\nusing namespace std;\n\nvoid set_basic_information(HANDLE h, int64_t creation_time, int64_t last_access"
  },
  {
    "path": "src/tests/io.cpp",
    "chars": 46379,
    "preview": "#include \"test.h\"\n#include <random>\n#include <span>\n#include <array>\n\nusing namespace std;\n\n#define FSCTL_SET_ZERO_DATA "
  },
  {
    "path": "src/tests/links.cpp",
    "chars": 45717,
    "preview": "#include \"test.h\"\n\nusing namespace std;\n\nvector<pair<int64_t, u16string>> query_links(HANDLE h) {\n    IO_STATUS_BLOCK io"
  },
  {
    "path": "src/tests/manifest.xml",
    "chars": 1244,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com"
  },
  {
    "path": "src/tests/mmap.cpp",
    "chars": 23304,
    "preview": "#include \"test.h\"\n\nusing namespace std;\n\nunique_handle create_section(ACCESS_MASK access, optional<uint64_t> max_size, U"
  },
  {
    "path": "src/tests/oplock.cpp",
    "chars": 192877,
    "preview": "#include \"test.h\"\n#include <thread>\n\nusing namespace std;\n\n#define FSCTL_REQUEST_OPLOCK_LEVEL_1 CTL_CODE(FILE_DEVICE_FIL"
  },
  {
    "path": "src/tests/overwrite.cpp",
    "chars": 5567,
    "preview": "#include \"test.h\"\n\nusing namespace std;\n\nvoid test_overwrite(const u16string& dir) {\n    unique_handle h;\n\n    test(\"Try"
  },
  {
    "path": "src/tests/rename.cpp",
    "chars": 64293,
    "preview": "#include \"test.h\"\n\nusing namespace std;\n\nvoid set_rename_information(HANDLE h, bool replace_if_exists, HANDLE root_dir, "
  },
  {
    "path": "src/tests/reparse.cpp",
    "chars": 71449,
    "preview": "#include \"test.h\"\n\n#define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_A"
  },
  {
    "path": "src/tests/security.cpp",
    "chars": 41367,
    "preview": "#include \"test.h\"\n#include <array>\n\nusing namespace std;\n\n#ifdef _MSC_VER\n#define ThreadImpersonationToken ((THREADINFOC"
  },
  {
    "path": "src/tests/streams.cpp",
    "chars": 39834,
    "preview": "#include \"test.h\"\n\nusing namespace std;\n\n#ifdef _MSC_VER\ntypedef struct _FILE_STREAM_INFORMATION {\n    ULONG NextEntryOf"
  },
  {
    "path": "src/tests/supersede.cpp",
    "chars": 3726,
    "preview": "#include \"test.h\"\n\nusing namespace std;\n\nvoid test_supersede(const u16string& dir) {\n    unique_handle h;\n\n    test(\"Cre"
  },
  {
    "path": "src/tests/test.cpp",
    "chars": 26326,
    "preview": "/* Copyright (c) Mark Harmstone 2021\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/tests/test.h",
    "chars": 201634,
    "preview": "/* Copyright (c) Mark Harmstone 2021\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/tests/test.rc.in",
    "chars": 1627,
    "preview": "#define APSTUDIO_READONLY_SYMBOLS\n#include <winresrc.h>\n#undef APSTUDIO_READONLY_SYMBOLS\n\n//////////////////////////////"
  },
  {
    "path": "src/treefuncs.c",
    "chars": 80580,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/ubtrfs/resource.h",
    "chars": 404,
    "preview": "//{{NO_DEPENDENCIES}}\r\n// Microsoft Visual C++ generated include file.\r\n// Used by ubtrfs.rc\r\n//\r\n\r\n// Next default valu"
  },
  {
    "path": "src/ubtrfs/ubtrfs.c",
    "chars": 44739,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/ubtrfs/ubtrfs.def",
    "chars": 208,
    "preview": "EXPORTS\r\n    ChkdskEx\t\t\tPRIVATE\r\n    FormatEx\t\t\tPRIVATE\r\n    GetFilesystemInformation\tPRIVATE\r\n    SetSizes\t\t\tPRIVATE\r\n "
  },
  {
    "path": "src/ubtrfs/ubtrfs.rc.in",
    "chars": 2468,
    "preview": "// Microsoft Visual C++ generated resource script.\n//\n#include \"@CMAKE_CURRENT_SOURCE_DIR@/src/ubtrfs/resource.h\"\n\n#defi"
  },
  {
    "path": "src/volume.c",
    "chars": 41923,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/worker-thread.c",
    "chars": 4452,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/write.c",
    "chars": 173034,
    "preview": "/* Copyright (c) Mark Harmstone 2016-17\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can re"
  },
  {
    "path": "src/xor-gas.S",
    "chars": 5121,
    "preview": "/* Copyright (c) Mark Harmstone 2020\n *\n * This file is part of WinBtrfs.\n *\n * WinBtrfs is free software: you can redis"
  },
  {
    "path": "src/xor-masm.asm",
    "chars": 5137,
    "preview": "; Copyright (c) Mark Harmstone 2020\n;\n; This file is part of WinBtrfs.\n;\n; WinBtrfs is free software: you can redistribu"
  },
  {
    "path": "src/zstd-shim.h",
    "chars": 386,
    "preview": "#include <stddef.h>\n#include <stdint.h>\n\nstatic void* ZSTD_malloc(size_t size) {\n    return NULL;\n}\n\nstatic void* ZSTD_c"
  }
]

About this extraction

This page contains the full source code of the maharmstone/btrfs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 117 files (4.0 MB), approximately 1.0M tokens, and a symbol index with 1292 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!