diff -pruN 0.11.1+ds-4/_clang-format 0.13.1+ds-1/_clang-format
--- 0.11.1+ds-4/_clang-format	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/_clang-format	2023-01-27 02:25:50.000000000 +0000
@@ -62,4 +62,3 @@ ForEachMacros:   [ foreach, Q_FOREACH, B
 SpaceBeforeParens: ControlStatements
 DisableFormat:   false
 ...
-
diff -pruN 0.11.1+ds-4/CMakeLists.txt 0.13.1+ds-1/CMakeLists.txt
--- 0.11.1+ds-4/CMakeLists.txt	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/CMakeLists.txt	2023-01-27 02:25:50.000000000 +0000
@@ -1,72 +1,87 @@
 cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_STANDARD 11)
 
 project(securefs)
-if (POLICY CMP0048)
-  cmake_policy(SET CMP0048 NEW)
+enable_testing()
+cmake_policy(SET CMP0048 NEW)
+cmake_policy(SET CMP0069 NEW)
+set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
+
+include(CheckIPOSupported)
+check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT error)
+
+if(IPO_SUPPORTED)
+    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
+    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON)
+    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL ON)
 endif()
+set(CMAKE_FIND_FRAMEWORK NEVER)
 
-set (CMAKE_FIND_FRAMEWORK NEVER)
-
-execute_process (
-    COMMAND bash -c "uname -m"
-    OUTPUT_VARIABLE architecture
-)
+execute_process(COMMAND bash -c "uname -m" OUTPUT_VARIABLE architecture)
 
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake-modules/")
 include(GetGitRevisionDescription)
 git_describe(GIT_VERSION --tags)
-configure_file(${CMAKE_SOURCE_DIR}/sources/git-version.cpp.in ${CMAKE_BINARY_DIR}/git-version.cpp)
+configure_file(${CMAKE_SOURCE_DIR}/sources/git-version.cpp.in
+               ${CMAKE_BINARY_DIR}/git-version.cpp)
 
-if (UNIX)
-    find_path(FUSE_INCLUDE_DIR fuse.h PATHS /usr/local/include PATH_SUFFIXES osxfuse)
-    if (APPLE)
-        find_library(FUSE_LIBRARIES osxfuse PATHS /usr/local/lib)
-    else()
-        find_library(FUSE_LIBRARIES fuse PATHS /usr/local/lib)
-    endif()
+file(COPY ${CMAKE_SOURCE_DIR}/external/cmake-cryptopp/CMakeLists.txt
+     DESTINATION ${CMAKE_SOURCE_DIR}/external/cryptopp)
+
+if(UNIX)
+    find_path(FUSE_INCLUDE_DIR fuse.h PATHS /usr/local/include)
+    find_library(FUSE_LIBRARIES fuse PATHS /usr/local/lib)
     include_directories(${FUSE_INCLUDE_DIR})
     link_libraries(${FUSE_LIBRARIES})
     add_compile_options(-Wall -Wextra -Wno-unknown-pragmas)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=gnu++11")
-
-    if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
-        add_compile_options(-Wthread-safety -Wthread-safety-negative)
-    endif()
 
-    if (APPLE)
+    if(APPLE)
         link_libraries(-Wl,-dead_strip)
-    else ()
+    else()
         add_compile_options(-pthread)
         link_libraries(-pthread)
-    endif ()
+    endif()
     link_libraries(${CMAKE_DL_LIBS})
-else ()
+else()
     add_definitions(-DNOMINMAX=1)
     add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
     add_definitions(-D__STDC__=1)
-    if (NOT WINFSP_PREFIX)
+    if(NOT WINFSP_PREFIX)
         message("WINFSP_PREFIX not set, fallback to default value")
         set(WINFSP_PREFIX "C:/Program Files (x86)/WinFsp")
-    endif ()
-    if (${CMAKE_SIZEOF_VOID_P} EQUAL 8)
+    endif()
+    if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
         set(ARCH x64)
-    else ()
+    else()
         set(ARCH x86)
-    endif ()
+    endif()
     set(FUSE_INCLUDE_DIR ${WINFSP_PREFIX}/inc/fuse)
     include_directories(${WINFSP_PREFIX}/inc)
     include_directories(${FUSE_INCLUDE_DIR})
     link_libraries(${WINFSP_PREFIX}/lib/winfsp-${ARCH}.lib)
-    link_libraries(-DELAYLOAD:winfsp-${ARCH}.dll)
     link_libraries(delayimp.lib)
-    add_compile_options(/MP)
-endif ()
+    if(MSVC)
+        link_libraries(-DELAYLOAD:winfsp-${ARCH}.dll)
+        add_compile_options(/utf-8)
+    elseif(MINGW)
+        link_libraries(-delayload=winfsp-${ARCH}.dll)
+    endif()
+endif()
 
-add_definitions(-D_REENTRANT -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=28 -DUTF8PROC_EXPORTS=1)
+if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+    add_compile_options(-Wthread-safety)
+    if(MINGW)
+        add_compile_options(-fansi-escape-codes -fcolor-diagnostics)
+    endif()
+endif()
 
-if (NOT CMAKE_BUILD_TYPE)
+add_definitions(-D_REENTRANT -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=28
+                -DUTF8PROC_EXPORTS=1)
+
+if(NOT CMAKE_BUILD_TYPE)
     set(CMAKE_BUILD_TYPE Release)
-endif ()
+endif()
 
 include_directories(sources)
 set(EXTERNAL_DIR external)
@@ -76,58 +91,44 @@ set(CRYPTOPP_DIR ${EXTERNAL_DIR}/cryptop
 add_subdirectory(${CRYPTOPP_DIR})
 link_libraries(cryptopp-static)
 
-file(GLOB SOURCES sources/*.cpp sources/*.h ${EXTERNAL_DIR}/*.h ${EXTERNAL_DIR}/*.hpp ${EXTERNAL_DIR}/*.cpp ${CMAKE_BINARY_DIR}/git-version.cpp ${EXTERNAL_DIR}/utf8proc/utf8proc.h ${EXTERNAL_DIR}/utf8proc/utf8proc.c)
-file(GLOB TEST_SOURCES test/*.cpp)
+add_subdirectory(${EXTERNAL_DIR}/argon2)
+include_directories(${EXTERNAL_DIR}/argon2/include)
+link_libraries(argon2_static)
+
+file(
+    GLOB
+    SOURCES
+    sources/*.cpp
+    sources/*.h
+    ${EXTERNAL_DIR}/*.h
+    ${EXTERNAL_DIR}/*.hpp
+    ${EXTERNAL_DIR}/*.cpp
+    ${CMAKE_BINARY_DIR}/git-version.cpp
+    ${EXTERNAL_DIR}/utf8proc/utf8proc.h
+    ${EXTERNAL_DIR}/utf8proc/utf8proc.c)
+file(GLOB TEST_SOURCES test/*.h test/*.cpp)
 add_library(securefs-static STATIC ${SOURCES})
 link_libraries(securefs-static)
 
-add_executable(securefs main.cpp)
-add_executable(securefs_test ${TEST_SOURCES})
-
-include(CheckCXXSourceRuns)
-CHECK_CXX_SOURCE_RUNS("int main() { thread_local int i = 0; return i; }" HAS_THREAD_LOCAL)
-
-CHECK_CXX_SOURCE_RUNS("
-#include <time.h>
-
-int main() {
-    timespec ts;
-    clock_gettime(CLOCK_REALTIME, &ts);
-    return 0;
-}
-" HAS_CLOCK_GETTIME)
-
-CHECK_CXX_SOURCE_RUNS("
-#include <unistd.h>
-#include <sys/stat.h>
-
-int main() {
-    futimens(-1, nullptr);
-    return 0;
-}
-" HAS_FUTIMENS)
-
-CHECK_CXX_SOURCE_RUNS("
-#include <unistd.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-int main() {
-    utimensat(-1, nullptr, nullptr, 0);
-    return 0;
-}
-" HAS_UTIMENSAT)
+if(MSVC)
+    add_executable(securefs main.cpp securefs.manifest)
+else()
+    add_executable(securefs main.cpp)
+endif()
 
-configure_file(sources/securefs_config.in securefs_config.h)
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
+add_executable(securefs_test ${TEST_SOURCES})
 
-enable_testing()
 add_test(NAME sec_test COMMAND securefs_test)
 find_package(Python3 COMPONENTS Interpreter)
-if (Python3_FOUND)
-    add_test(NAME simple_test COMMAND ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/test/simple_test.py)
-else()
-add_test(NAME simple_test COMMAND python3 ${PROJECT_SOURCE_DIR}/test/simple_test.py)
+if(Python3_FOUND)
+    add_test(
+        NAME simple_test
+        COMMAND ${CMAKE_COMMAND} -E env SECUREFS_BINARY=$<TARGET_FILE:securefs>
+                ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/test/simple_test.py)
 endif()
 
 install(TARGETS securefs DESTINATION bin)
+
+if(MINGW)
+    target_link_libraries(securefs PRIVATE -municode)
+endif()
diff -pruN 0.11.1+ds-4/debian/changelog 0.13.1+ds-1/debian/changelog
--- 0.11.1+ds-4/debian/changelog	2021-10-03 02:28:41.000000000 +0000
+++ 0.13.1+ds-1/debian/changelog	2023-01-27 02:31:37.000000000 +0000
@@ -1,3 +1,24 @@
+securefs (0.13.1+ds-1) unstable; urgency=medium
+
+  * New upstream version 0.13.1+ds
+
+ -- Yanhao <yanhaocs@gmail.com>  Fri, 27 Jan 2023 10:31:37 +0800
+
+securefs (0.13.0+ds-2) unstable; urgency=medium
+
+  * Fix autopkgtest by add allow-stderr tag (CLoses: #1021083).
+
+ -- Yanhao <yanhaocs@gmail.com>  Sun, 16 Oct 2022 18:02:42 +0800
+
+securefs (0.13.0+ds-1) unstable; urgency=medium
+
+  * New upstream version 0.13.0+ds
+  * Update copyright information
+  * Update patches:
+    - Build use native argon2 library
+
+ -- Yanhao <yanhaocs@gmail.com>  Sat, 17 Sep 2022 15:45:53 +0800
+
 securefs (0.11.1+ds-4) unstable; urgency=medium
 
   * Bump Standards-Version to 4.6.0
diff -pruN 0.11.1+ds-4/debian/control 0.13.1+ds-1/debian/control
--- 0.11.1+ds-4/debian/control	2021-10-03 02:28:41.000000000 +0000
+++ 0.13.1+ds-1/debian/control	2023-01-27 02:31:37.000000000 +0000
@@ -11,7 +11,8 @@ Build-Depends: catch,
                libjsoncpp-dev,
                libtclap-dev,
                libutf8proc-dev,
-               libutfcpp-dev
+               libutfcpp-dev,
+               libargon2-dev
 Rules-Requires-Root: no
 Standards-Version: 4.6.0
 Homepage: https://github.com/netheril96/securefs
diff -pruN 0.11.1+ds-4/debian/copyright 0.13.1+ds-1/debian/copyright
--- 0.11.1+ds-4/debian/copyright	2021-10-03 02:28:41.000000000 +0000
+++ 0.13.1+ds-1/debian/copyright	2023-01-27 02:31:37.000000000 +0000
@@ -21,10 +21,6 @@ Files: sources/crypto.cpp
 Copyright: 2015, ARKconcepts / Sasha Kotlyar
 License: ISC
 
-Files: sources/scrypt.cpp
-Copyright: 2009, Colin Percival
-License: BSD-2-Clause
-
 Files: sources/myutils.h
 Copyright: 2012-2014, Zhihao Yan
 License: BSD-2-Clause
diff -pruN 0.11.1+ds-4/debian/patches/0001-use-system-libcrypto.patch 0.13.1+ds-1/debian/patches/0001-use-system-libcrypto.patch
--- 0.11.1+ds-4/debian/patches/0001-use-system-libcrypto.patch	2021-10-03 02:28:41.000000000 +0000
+++ 0.13.1+ds-1/debian/patches/0001-use-system-libcrypto.patch	2023-01-27 02:31:37.000000000 +0000
@@ -1,17 +1,34 @@
 From: Yanhao Mo <yanhaocs@gmail.com>
-Date: Sun, 30 Aug 2020 16:28:56 +0800
+Date: Sat, 17 Sep 2022 16:55:54 +0800
 Subject: use system libcrypto
 
 ---
- CMakeLists.txt       |  6 +-----
- sources/commands.cpp | 12 ------------
- 2 files changed, 1 insertion(+), 17 deletions(-)
+ CMakeLists.txt | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
 
 diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 7b5e57d..601768e 100755
+index e055dd5..9b3814c 100755
 --- a/CMakeLists.txt
 +++ b/CMakeLists.txt
-@@ -72,9 +72,7 @@ include_directories(sources)
+@@ -3,7 +3,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
+ set(CMAKE_CXX_STANDARD 11)
+ 
+ project(securefs)
+-enable_testing()
+ cmake_policy(SET CMP0048 NEW)
+ cmake_policy(SET CMP0069 NEW)
+ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
+@@ -26,9 +25,6 @@ git_describe(GIT_VERSION --tags)
+ configure_file(${CMAKE_SOURCE_DIR}/sources/git-version.cpp.in
+                ${CMAKE_BINARY_DIR}/git-version.cpp)
+ 
+-file(COPY ${CMAKE_SOURCE_DIR}/external/cmake-cryptopp/CMakeLists.txt
+-     DESTINATION ${CMAKE_SOURCE_DIR}/external/cryptopp)
+-
+ if(UNIX)
+     find_path(FUSE_INCLUDE_DIR fuse.h PATHS /usr/local/include)
+     find_library(FUSE_LIBRARIES fuse PATHS /usr/local/lib)
+@@ -87,9 +83,7 @@ include_directories(sources)
  set(EXTERNAL_DIR external)
  include_directories(${EXTERNAL_DIR})
  
@@ -20,37 +37,5 @@ index 7b5e57d..601768e 100755
 -link_libraries(cryptopp-static)
 +link_libraries(crypto++)
  
- file(GLOB SOURCES sources/*.cpp sources/*.h ${EXTERNAL_DIR}/*.h ${EXTERNAL_DIR}/*.hpp ${EXTERNAL_DIR}/*.cpp ${CMAKE_BINARY_DIR}/git-version.cpp ${EXTERNAL_DIR}/utf8proc/utf8proc.h ${EXTERNAL_DIR}/utf8proc/utf8proc.c)
- file(GLOB TEST_SOURCES test/*.cpp)
-@@ -121,8 +119,6 @@ int main() {
- configure_file(sources/securefs_config.in securefs_config.h)
- include_directories(${CMAKE_CURRENT_BINARY_DIR})
- 
--enable_testing()
--add_test(NAME sec_test COMMAND securefs_test)
- find_package(Python3 COMPONENTS Interpreter)
- if (Python3_FOUND)
-     add_test(NAME simple_test COMMAND ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/test/simple_test.py)
-diff --git a/sources/commands.cpp b/sources/commands.cpp
-index 7994d80..2d163d6 100644
---- a/sources/commands.cpp
-+++ b/sources/commands.cpp
-@@ -1260,18 +1260,6 @@ public:
- 
- #ifdef CRYPTOPP_DISABLE_ASM
-         fputs("\nBuilt without hardware acceleration\n", stdout);
--#else
--#if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
--        printf("\nHardware features available:\nSSE2: %s\nSSE3: %s\nSSE4.1: %s\nSSE4.2: "
--               "%s\nAES-NI: %s\nCLMUL: %s\nSHA: %s\n",
--               HasSSE2() ? "true" : "false",
--               HasSSSE3() ? "true" : "false",
--               HasSSE41() ? "true" : "false",
--               HasSSE42() ? "true" : "false",
--               HasAESNI() ? "true" : "false",
--               HasCLMUL() ? "true" : "false",
--               HasSHA() ? "true" : "false");
--#endif
- #endif
-         return 0;
-     }
+ add_subdirectory(${EXTERNAL_DIR}/argon2)
+ include_directories(${EXTERNAL_DIR}/argon2/include)
diff -pruN 0.11.1+ds-4/debian/patches/0002-use-system-jsoncpp.patch 0.13.1+ds-1/debian/patches/0002-use-system-jsoncpp.patch
--- 0.11.1+ds-4/debian/patches/0002-use-system-jsoncpp.patch	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/debian/patches/0002-use-system-jsoncpp.patch	2023-01-27 02:31:37.000000000 +0000
@@ -0,0 +1,34 @@
+From: Yanhao Mo <yanhaocs@gmail.com>
+Date: Sat, 17 Sep 2022 16:57:38 +0800
+Subject: use system jsoncpp
+
+---
+ CMakeLists.txt       | 1 +
+ sources/commands.cpp | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 9b3814c..e5f7a5f 100755
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -84,6 +84,7 @@ set(EXTERNAL_DIR external)
+ include_directories(${EXTERNAL_DIR})
+ 
+ link_libraries(crypto++)
++link_libraries(jsoncpp)
+ 
+ add_subdirectory(${EXTERNAL_DIR}/argon2)
+ include_directories(${EXTERNAL_DIR}/argon2/include)
+diff --git a/sources/commands.cpp b/sources/commands.cpp
+index 18a4ae0..e2d38ee 100644
+--- a/sources/commands.cpp
++++ b/sources/commands.cpp
+@@ -15,7 +15,7 @@
+ #include <cryptopp/scrypt.h>
+ #include <cryptopp/secblock.h>
+ #include <fuse.h>
+-#include <json/json.h>
++#include <jsoncpp/json/json.h>
+ #include <tclap/CmdLine.h>
+ #include <utf8proc/utf8proc.h>
+ 
diff -pruN 0.11.1+ds-4/debian/patches/0002-use-system-libjsoncpp.patch 0.13.1+ds-1/debian/patches/0002-use-system-libjsoncpp.patch
--- 0.11.1+ds-4/debian/patches/0002-use-system-libjsoncpp.patch	2021-10-03 02:28:41.000000000 +0000
+++ 0.13.1+ds-1/debian/patches/0002-use-system-libjsoncpp.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,34 +0,0 @@
-From: Yanhao Mo <yanhaocs@gmail.com>
-Date: Sun, 30 Aug 2020 16:29:45 +0800
-Subject: use system libjsoncpp
-
----
- CMakeLists.txt       | 1 +
- sources/commands.cpp | 2 +-
- 2 files changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 601768e..6187b05 100755
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -73,6 +73,7 @@ set(EXTERNAL_DIR external)
- include_directories(${EXTERNAL_DIR})
- 
- link_libraries(crypto++)
-+link_libraries(jsoncpp)
- 
- file(GLOB SOURCES sources/*.cpp sources/*.h ${EXTERNAL_DIR}/*.h ${EXTERNAL_DIR}/*.hpp ${EXTERNAL_DIR}/*.cpp ${CMAKE_BINARY_DIR}/git-version.cpp ${EXTERNAL_DIR}/utf8proc/utf8proc.h ${EXTERNAL_DIR}/utf8proc/utf8proc.c)
- file(GLOB TEST_SOURCES test/*.cpp)
-diff --git a/sources/commands.cpp b/sources/commands.cpp
-index 2d163d6..a917bcb 100644
---- a/sources/commands.cpp
-+++ b/sources/commands.cpp
-@@ -12,7 +12,7 @@
- #include <cryptopp/osrng.h>
- #include <cryptopp/secblock.h>
- #include <fuse.h>
--#include <json/json.h>
-+#include <jsoncpp/json/json.h>
- #include <tclap/CmdLine.h>
- #include <utf8proc/utf8proc.h>
- 
diff -pruN 0.11.1+ds-4/debian/patches/0003-use-system-utf8proc.patch 0.13.1+ds-1/debian/patches/0003-use-system-utf8proc.patch
--- 0.11.1+ds-4/debian/patches/0003-use-system-utf8proc.patch	2021-10-03 02:28:41.000000000 +0000
+++ 0.13.1+ds-1/debian/patches/0003-use-system-utf8proc.patch	2023-01-27 02:31:37.000000000 +0000
@@ -1,33 +1,41 @@
 From: Yanhao Mo <yanhaocs@gmail.com>
-Date: Sun, 30 Aug 2020 16:29:59 +0800
+Date: Sat, 17 Sep 2022 17:00:08 +0800
 Subject: use system utf8proc
 
 ---
- CMakeLists.txt       | 3 ++-
+ CMakeLists.txt       | 5 ++---
  sources/commands.cpp | 2 +-
  sources/mystring.cpp | 2 +-
- 3 files changed, 4 insertions(+), 3 deletions(-)
+ 3 files changed, 4 insertions(+), 5 deletions(-)
 
 diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 6187b05..a1de92a 100755
+index e5f7a5f..e39fa73 100755
 --- a/CMakeLists.txt
 +++ b/CMakeLists.txt
-@@ -74,8 +74,9 @@ include_directories(${EXTERNAL_DIR})
+@@ -85,6 +85,7 @@ include_directories(${EXTERNAL_DIR})
  
  link_libraries(crypto++)
  link_libraries(jsoncpp)
 +link_libraries(utf8proc)
  
--file(GLOB SOURCES sources/*.cpp sources/*.h ${EXTERNAL_DIR}/*.h ${EXTERNAL_DIR}/*.hpp ${EXTERNAL_DIR}/*.cpp ${CMAKE_BINARY_DIR}/git-version.cpp ${EXTERNAL_DIR}/utf8proc/utf8proc.h ${EXTERNAL_DIR}/utf8proc/utf8proc.c)
-+file(GLOB SOURCES sources/*.cpp sources/*.h ${EXTERNAL_DIR}/*.h ${EXTERNAL_DIR}/*.hpp ${EXTERNAL_DIR}/*.cpp ${CMAKE_BINARY_DIR}/git-version.cpp)
- file(GLOB TEST_SOURCES test/*.cpp)
+ add_subdirectory(${EXTERNAL_DIR}/argon2)
+ include_directories(${EXTERNAL_DIR}/argon2/include)
+@@ -98,9 +99,7 @@ file(
+     ${EXTERNAL_DIR}/*.h
+     ${EXTERNAL_DIR}/*.hpp
+     ${EXTERNAL_DIR}/*.cpp
+-    ${CMAKE_BINARY_DIR}/git-version.cpp
+-    ${EXTERNAL_DIR}/utf8proc/utf8proc.h
+-    ${EXTERNAL_DIR}/utf8proc/utf8proc.c)
++    ${CMAKE_BINARY_DIR}/git-version.cpp)
+ file(GLOB TEST_SOURCES test/*.h test/*.cpp)
  add_library(securefs-static STATIC ${SOURCES})
  link_libraries(securefs-static)
 diff --git a/sources/commands.cpp b/sources/commands.cpp
-index a917bcb..2820068 100644
+index e2d38ee..53b7502 100644
 --- a/sources/commands.cpp
 +++ b/sources/commands.cpp
-@@ -14,7 +14,7 @@
+@@ -17,7 +17,7 @@
  #include <fuse.h>
  #include <jsoncpp/json/json.h>
  #include <tclap/CmdLine.h>
@@ -35,7 +43,7 @@ index a917bcb..2820068 100644
 +#include <utf8proc.h>
  
  #include <algorithm>
- #include <memory>
+ #include <iostream>
 diff --git a/sources/mystring.cpp b/sources/mystring.cpp
 index e9b649f..ac20fd8 100644
 --- a/sources/mystring.cpp
diff -pruN 0.11.1+ds-4/debian/patches/0004-use-system-argon2.patch 0.13.1+ds-1/debian/patches/0004-use-system-argon2.patch
--- 0.11.1+ds-4/debian/patches/0004-use-system-argon2.patch	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/debian/patches/0004-use-system-argon2.patch	2023-01-27 02:31:37.000000000 +0000
@@ -0,0 +1,24 @@
+From: Yanhao Mo <yanhaocs@gmail.com>
+Date: Sat, 17 Sep 2022 17:12:49 +0800
+Subject: use system argon2
+
+---
+ CMakeLists.txt | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index e39fa73..6d9a3bd 100755
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -86,10 +86,7 @@ include_directories(${EXTERNAL_DIR})
+ link_libraries(crypto++)
+ link_libraries(jsoncpp)
+ link_libraries(utf8proc)
+-
+-add_subdirectory(${EXTERNAL_DIR}/argon2)
+-include_directories(${EXTERNAL_DIR}/argon2/include)
+-link_libraries(argon2_static)
++link_libraries(argon2)
+ 
+ file(
+     GLOB
diff -pruN 0.11.1+ds-4/debian/patches/series 0.13.1+ds-1/debian/patches/series
--- 0.11.1+ds-4/debian/patches/series	2021-10-03 02:28:41.000000000 +0000
+++ 0.13.1+ds-1/debian/patches/series	2023-01-27 02:31:37.000000000 +0000
@@ -1,3 +1,4 @@
 0001-use-system-libcrypto.patch
-0002-use-system-libjsoncpp.patch
+0002-use-system-jsoncpp.patch
 0003-use-system-utf8proc.patch
+0004-use-system-argon2.patch
diff -pruN 0.11.1+ds-4/debian/tests/control 0.13.1+ds-1/debian/tests/control
--- 0.11.1+ds-4/debian/tests/control	2021-10-03 02:28:41.000000000 +0000
+++ 0.13.1+ds-1/debian/tests/control	2023-01-27 02:31:37.000000000 +0000
@@ -9,4 +9,4 @@ Restrictions: build-needed, isolation-ma
 
 Test-Command: cd obj-x86_64-linux-gnu && ./securefs_test
 Depends: fuse, libcrypto++-dev, libfuse-dev, libjsoncpp-dev, libutf8proc-dev
-Restrictions: build-needed
+Restrictions: build-needed, allow-stderr
diff -pruN 0.11.1+ds-4/external/_clang-format 0.13.1+ds-1/external/_clang-format
--- 0.11.1+ds-4/external/_clang-format	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/external/_clang-format	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+DisableFormat: true
diff -pruN 0.11.1+ds-4/external/cmake-cryptopp/CMakeLists.txt 0.13.1+ds-1/external/cmake-cryptopp/CMakeLists.txt
--- 0.11.1+ds-4/external/cmake-cryptopp/CMakeLists.txt	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/external/cmake-cryptopp/CMakeLists.txt	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,1269 @@
+# Please ensure your changes or patch meets minimum requirements.
+#   The minimum requirements are 2.8.6. It roughly equates to
+#   Ubuntu 14.05 LTS or Solaris 11.3. Please do not check in something
+#   for 3.5.0 or higher because it will break LTS operating systems
+#   and a number of developer boards used for testing. To test your
+#   changes, please set up a Ubuntu 14.05 LTS system.
+
+# Should we be setting things like this? We are not a C project
+# so nothing should be done with the C compiler. But there is
+# no reliable way to tell CMake we are C++.
+# Cannot set this... Breaks Linux PowerPC with Clang:
+# SET(CMAKE_C_COMPILER ${CMAKE_CXX_COMPILER})
+# # error "The CMAKE_C_COMPILER is set to a C++ compiler"
+
+if(NOT DEFINED cryptopp_DISPLAY_CMAKE_SUPPORT_WARNING)
+  set(cryptopp_DISPLAY_CMAKE_SUPPORT_WARNING 1)
+endif()
+if(cryptopp_DISPLAY_CMAKE_SUPPORT_WARNING)
+  message( STATUS
+"*************************************************************************\n"
+"The Crypto++ library does not officially support CMake. CMake support is a\n"
+"community effort, and the library works with the folks using CMake to help\n"
+"improve it. If you find an issue then please fix it or report it at\n"
+"https://github.com/noloader/cryptopp-cmake.\n"
+"-- *************************************************************************"
+)
+endif()
+
+# Print useful information
+message( STATUS "CMake version ${CMAKE_VERSION}" )
+message( STATUS "System ${CMAKE_SYSTEM_NAME}" )
+message( STATUS "Processor ${CMAKE_SYSTEM_PROCESSOR}" )
+
+if (${CMAKE_VERSION} VERSION_LESS "3.0.0")
+  project(cryptopp)
+  set(cryptopp_VERSION_MAJOR 8)
+  set(cryptopp_VERSION_MINOR 6)
+  set(cryptopp_VERSION_PATCH 0)
+else ()
+  cmake_policy(SET CMP0048 NEW)
+  project(cryptopp VERSION 8.6.0)
+  if (NOT ${CMAKE_VERSION} VERSION_LESS "3.1.0")
+    cmake_policy(SET CMP0054 NEW)
+  endif ()
+endif ()
+
+# Need to set SRC_DIR manually after removing the Python library code.
+set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+# Make RelWithDebInfo the default (it does e.g. add '-O2 -g -DNDEBUG' for GNU)
+#   If not in multi-configuration environments, no explicit build type or CXX
+#   flags are set by the user and if we are the root CMakeLists.txt file.
+if (NOT CMAKE_CONFIGURATION_TYPES AND
+    NOT CMAKE_NO_BUILD_TYPE AND
+    NOT CMAKE_BUILD_TYPE AND
+    NOT CMAKE_CXX_FLAGS AND
+    CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+  set(CMAKE_BUILD_TYPE RelWithDebInfo)
+endif ()
+
+include(GNUInstallDirs)
+include(CheckCXXCompilerFlag)
+
+# We now carry around test programs. test_cxx.cpp is the default C++ one.
+# Also see https://github.com/weidai11/cryptopp/issues/741.
+set(TEST_PROG_DIR ${SRC_DIR}/TestPrograms)
+set(TEST_CXX_FILE ${TEST_PROG_DIR}/test_cxx.cpp)
+
+# https://github.com/noloader/cryptopp-cmake/issues/56
+# https://stackoverflow.com/a/40152725
+if (APPLE)
+  set(USE_INTERMEDIATE_OBJECTS_TARGET OFF)
+endif()
+
+#============================================================================
+# Settable options
+#============================================================================
+
+option(BUILD_STATIC "Build static library" ON)
+option(BUILD_SHARED "Build shared library" OFF)
+option(BUILD_TESTING "Build library tests" ON)
+option(BUILD_DOCUMENTATION "Use Doxygen to create the HTML based API documentation" OFF)
+option(USE_INTERMEDIATE_OBJECTS_TARGET "Use a common intermediate objects target for the static and shared library targets" ON)
+
+if (${CMAKE_VERSION} VERSION_GREATER "3.1")
+  option(USE_OPENMP "Enable OpenMP to parallelize some of the algorithms. Note that this isn't always faster, see https://www.cryptopp.com/wiki/OpenMP" OFF)
+endif()
+
+
+# These are IA-32 options.
+option(DISABLE_ASM "Disable ASM" OFF)
+option(DISABLE_SSSE3 "Disable SSSE3" OFF)
+option(DISABLE_SSE4 "Disable SSE4" OFF)
+option(DISABLE_AESNI "Disable AES-NI" OFF)
+option(DISABLE_CLMUL "Disable CLMUL" OFF)
+option(DISABLE_SHA "Disable SHA" OFF)
+option(DISABLE_AVX "Disable AVX" OFF)
+option(DISABLE_AVX2 "Disable AVX2" OFF)
+
+# These are ARM A-32 options
+option(DISABLE_ARM_NEON "Disable NEON" OFF)
+
+# These are Aarch64 options
+option(DISABLE_ARM_AES "Disable ASIMD" OFF)
+option(DISABLE_ARM_AES "Disable AES" OFF)
+option(DISABLE_ARM_PMULL "Disable PMULL" OFF)
+option(DISABLE_ARM_SHA "Disable SHA" OFF)
+
+# These are PowerPC options
+option(DISABLE_ALTIVEC "Disable Altivec" OFF)
+option(DISABLE_POWER7 "Disable POWER7" OFF)
+option(DISABLE_POWER8 "Disable POWER8" OFF)
+option(DISABLE_POWER9 "Disable POWER9" OFF)
+
+set(CRYPTOPP_DATA_DIR "" CACHE PATH "Crypto++ test data directory")
+
+#============================================================================
+# Compiler options
+#============================================================================
+
+set(CRYPTOPP_COMPILE_DEFINITIONS)
+set(CRYPTOPP_COMPILE_OPTIONS)
+
+# Stop hiding the damn output...
+# set(CMAKE_VERBOSE_MAKEFILE ON)
+
+# Stop CMake complaining...
+if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+  set(MACOSX_RPATH FALSE)
+endif()
+
+# Always 1 ahead in Master. Also see http://groups.google.com/forum/#!topic/cryptopp-users/SFhqLDTQPG4
+set(LIB_VER ${cryptopp_VERSION_MAJOR}${cryptopp_VERSION_MINOR}${cryptopp_VERSION_PATCH})
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
+  list(APPEND CRYPTOPP_COMPILE_OPTIONS -wd68 -wd186 -wd279 -wd327 -wd161 -wd3180)
+endif ()
+
+# Also see http://github.com/weidai11/cryptopp/issues/395
+if (DISABLE_ASM)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_ASM)
+endif ()
+if (DISABLE_SSSE3)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_SSSE3)
+endif ()
+if (DISABLE_SSE4)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_SSSE4)
+endif ()
+if (DISABLE_CLMUL)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_CLMUL)
+endif ()
+if (DISABLE_AESNI)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_AESNI)
+endif ()
+if (DISABLE_RDRAND)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_RDRAND)
+endif ()
+if (DISABLE_RDSEED)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_RDSEED)
+endif ()
+if (DISABLE_AVX)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_AVX)
+endif ()
+if (DISABLE_AVX2)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_AVX2)
+endif ()
+if (DISABLE_SHA)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_SHA)
+endif ()
+if (DISABLE_ARM_NEON)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_ARM_NEON)
+endif ()
+if (DISABLE_ARM_ASIMD)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_ARM_ASIMD)
+endif ()
+if (DISABLE_ARM_AES)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_ARM_AES)
+endif ()
+if (DISABLE_ARM_PMULL)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_ARM_PMULL)
+endif ()
+if (DISABLE_ARM_SHA)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_ARM_SHA)
+endif ()
+if (DISABLE_ALTIVEC)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_ALTIVEC)
+endif ()
+if (DISABLE_POWER7)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_POWER7)
+endif ()
+if (DISABLE_POWER8)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_POWER8)
+endif ()
+if (DISABLE_POWER9)
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_POWER9)
+endif ()
+if (NOT CRYPTOPP_DATA_DIR STREQUAL "")
+  list(APPEND CRYPTOPP_COMPILE_DEFINITIONS "CRYPTOPP_DATA_DIR=${CRYPTOPP_DATA_DIR}")
+endif ()
+
+###############################################################################
+
+# Try to find a Posix compatible grep and sed. Solaris, Digital Unix,
+#   Tru64, HP-UX and a few others need tweaking
+
+if (EXISTS /usr/xpg4/bin/grep)
+  set(GREP_CMD /usr/xpg4/bin/grep)
+elseif (EXISTS /usr/gnu/bin/grep)
+  set(GREP_CMD /usr/gnu/bin/grep)
+elseif (EXISTS /usr/linux/bin/grep)
+  set(GREP_CMD /usr/linux/bin/grep)
+else ()
+  set(GREP_CMD grep)
+endif ()
+
+if (EXISTS /usr/xpg4/bin/sed)
+  set(SED_CMD /usr/xpg4/bin/sed)
+elseif (EXISTS /usr/gnu/bin/sed)
+  set(SED_CMD /usr/gnu/bin/sed)
+elseif (EXISTS /usr/linux/bin/sed)
+  set(SED_CMD /usr/linux/bin/sed)
+else ()
+  set(SED_CMD sed)
+endif ()
+
+###############################################################################
+
+function(CheckCompileOption opt var)
+
+  if (MSVC)
+
+    # TODO: improve this...
+    CHECK_CXX_COMPILER_FLAG(${opt} ${var})
+
+  elseif (CMAKE_CXX_COMPILER_ID MATCHES "SunPro")
+
+    message(STATUS "Performing Test ${var}")
+    execute_process(
+      COMMAND sh -c "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${opt} -c ${TEST_CXX_FILE} 2>&1"
+      COMMAND ${GREP_CMD} -i -c -E "illegal value ignored"
+      RESULT_VARIABLE COMMAND_RESULT
+      OUTPUT_VARIABLE COMMAND_OUTPUT
+      OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+    # No dereference below. Thanks for the warning, CMake (not!).
+    if (COMMAND_RESULT AND NOT COMMAND_OUTPUT)
+      set(${var} 1 PARENT_SCOPE)
+      message(STATUS "Performing Test ${var} - Success")
+    else ()
+      set(${var} 0 PARENT_SCOPE)
+      message(STATUS "Performing Test ${var} - Failed")
+    endif ()
+
+  # Must use CMAKE_CXX_COMPILER here due to XLC 13.1 and LLVM front-end.
+  elseif (CMAKE_CXX_COMPILER MATCHES "xlC")
+
+    message(STATUS "Performing Test ${var}")
+    execute_process(
+      COMMAND sh -c "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${opt} -c ${TEST_CXX_FILE} 2>&1"
+      COMMAND ${GREP_CMD} -i -c -E "Unrecognized value"
+      RESULT_VARIABLE COMMAND_RESULT
+      OUTPUT_VARIABLE COMMAND_OUTPUT
+      OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+    # No dereference below. Thanks for the warning, CMake (not!).
+    if (COMMAND_RESULT AND NOT COMMAND_OUTPUT)
+      set(${var} 1 PARENT_SCOPE)
+      message(STATUS "Performing Test ${var} - Success")
+    else ()
+      set(${var} 0 PARENT_SCOPE)
+      message(STATUS "Performing Test ${var} - Failed")
+    endif ()
+
+  else ()
+
+    CHECK_CXX_COMPILER_FLAG(${opt} ${var})
+
+  endif ()
+
+endfunction(CheckCompileOption)
+
+function(CheckCompileLinkOption opt var prog)
+
+  if (MSVC)
+
+    # TODO: improve this...
+    CHECK_CXX_COMPILER_FLAG(${opt} ${var})
+
+  elseif (APPLE)
+
+    message(STATUS "Performing Test ${var}")
+    try_compile(COMMAND_SUCCESS ${CMAKE_BINARY_DIR} ${prog} COMPILE_DEFINITIONS ${opt})
+    if (COMMAND_SUCCESS)
+      set(${var} 1 PARENT_SCOPE)
+      message(STATUS "Performing Test ${var} - Success")
+    else ()
+      set(${var} 0 PARENT_SCOPE)
+      message(STATUS "Performing Test ${var} - Failed")
+    endif ()
+
+  else ()
+
+    message(STATUS "Performing Test ${var}")
+    try_compile(COMMAND_SUCCESS ${CMAKE_BINARY_DIR} ${prog} COMPILE_DEFINITIONS ${opt})
+    if (COMMAND_SUCCESS)
+        set(${var} 1 PARENT_SCOPE)
+        message(STATUS "Performing Test ${var} - Success")
+    else ()
+      set(${var} 0 PARENT_SCOPE)
+      message(STATUS "Performing Test ${var} - Failed")
+    endif ()
+
+  endif ()
+
+endfunction(CheckCompileLinkOption)
+
+function(AddCompileOption opt)
+
+    if ("${COMMAND_OUTPUT}" NOT STREQUAL "")
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "${opt}")
+    endif ()
+
+endfunction(AddCompileOption)
+
+###############################################################################
+
+function(DumpMachine output pattern)
+
+  if (MSVC)
+
+    # CMake does not provide a generic shell/terminal mechanism
+    #  and Microsoft environments don't know what 'sh' is.
+    set(${output} 0 PARENT_SCOPE)
+
+  else ()
+    execute_process(
+      COMMAND sh -c "${CMAKE_CXX_COMPILER} -dumpmachine 2>&1"
+      COMMAND ${GREP_CMD} -i -c -E "${pattern}"
+      OUTPUT_VARIABLE ${output}
+      OUTPUT_STRIP_TRAILING_WHITESPACE)
+    set(${output} "${${output}}" PARENT_SCOPE)
+  endif()
+
+endfunction(DumpMachine)
+
+# Thanks to Anonimal for MinGW; see http://github.com/weidai11/cryptopp/issues/466
+DumpMachine(CRYPTOPP_AMD64 "(x86_64|AMD64|amd64)")
+DumpMachine(CRYPTOPP_I386 "^i.86$")
+DumpMachine(CRYPTOPP_MINGW32 "^mingw32")
+DumpMachine(CRYPTOPP_MINGW64 "(w64-mingw32|mingw64)")
+DumpMachine(CRYPTOPP_ARMV8 "(armv8|arm64|aarch32|aarch64)")
+DumpMachine(CRYPTOPP_ARM32 "(arm|armhf|arm7l|eabihf)")
+DumpMachine(CRYPTOPP_PPC32 "^(powerpc|ppc)")
+DumpMachine(CRYPTOPP_PPC64 "^ppc64")
+
+# Cleanup 32/64 bit
+if (CRYPTOPP_AMD64)
+  set (CRYPTOPP_I386 0)
+endif ()
+
+if (CRYPTOPP_ARMV8)
+  set (CRYPTOPP_ARM32 0)
+endif ()
+
+if (CRYPTOPP_PPC64)
+  set (CRYPTOPP_PPC32 0)
+endif ()
+
+
+###############################################################################
+
+# Test SunCC for a string like 'CC: Sun C++ 5.13 SunOS_i386'
+if (NOT CRYPTOPP_SOLARIS AND NOT MSVC)
+  execute_process(COMMAND sh -c "${CMAKE_CXX_COMPILER} -V 2>&1"
+    COMMAND ${GREP_CMD} -i -c "SunOS"
+    OUTPUT_VARIABLE CRYPTOPP_SOLARIS
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+endif ()
+
+# Test GCC for a string like 'i386-pc-solaris2.11'
+if (NOT CRYPTOPP_SOLARIS AND NOT MSVC)
+  execute_process(COMMAND sh -c "${CMAKE_CXX_COMPILER} -dumpmachine 2>&1"
+    COMMAND ${GREP_CMD} -i -c "Solaris"
+    OUTPUT_VARIABLE CRYPTOPP_SOLARIS
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+endif ()
+
+# Fixup PowerPC. If both 32-bit and 64-bit use 64-bit.
+if (CRYPTOPP_PPC32 AND CRYPTOPP_PPC64)
+  unset(CRYPTOPP_PPC32)
+endif ()
+
+# Fixup for xlC compiler. -dumpmachine fails so we miss PowerPC
+# TODO: something better than proxying the platform via compiler
+# Must use CMAKE_CXX_COMPILER here due to XLC 13.1 and LLVM front-end.
+if (CMAKE_CXX_COMPILER MATCHES "xlC")
+  message ("-- Fixing platform due to IBM xlC")
+  set(CRYPTOPP_PPC64 1)
+endif ()
+
+# DumpMachine SunCC style
+if (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
+
+  # SunCC is 32-bit, but it builds both 32 and 64 bit. Use
+  execute_process(COMMAND sh -c "${CMAKE_CXX_COMPILER} -V 2>&1"
+    COMMAND ${GREP_CMD} -i -c "Sparc"
+    OUTPUT_VARIABLE CRYPTOPP_SPARC
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  execute_process(COMMAND sh -c "${CMAKE_CXX_COMPILER} -V 2>&1"
+    COMMAND ${GREP_CMD} -i -c -E "i386|i86"
+    OUTPUT_VARIABLE CRYPTOPP_I386
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  execute_process(COMMAND isainfo -k
+    COMMAND ${GREP_CMD} -i -c "i386"
+    OUTPUT_VARIABLE KERNEL_I386
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  execute_process(COMMAND isainfo -k
+    COMMAND ${GREP_CMD} -i -c "amd64"
+    OUTPUT_VARIABLE KERNEL_AMD64
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  execute_process(COMMAND isainfo -k
+    COMMAND ${GREP_CMD} -i -c "Sparc"
+    OUTPUT_VARIABLE KERNEL_SPARC
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  execute_process(COMMAND isainfo -k
+    COMMAND ${GREP_CMD} -i -c -E "UltraSarc|Sparc64|SparcV9"
+    OUTPUT_VARIABLE KERNEL_SPARC64
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+endif ()
+
+###############################################################################
+
+# TODO: what about ICC and LLVM on Windows?
+if (MSVC)
+  if (CMAKE_SYSTEM_VERSION MATCHES "10\\.0.*")
+    # https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt
+    list(APPEND CRYPTOPP_COMPILE_DEFINITIONS "_WIN32_WINNT=0x0A00")
+  endif ()
+  # winapifamily.h is missing on AppVeyor machines
+  INCLUDE (CheckIncludeFiles)
+  CHECK_INCLUDE_FILES (winapifamily.h HAVE_WINAPIFAMILY_H)
+  if (HAVE_WINAPIFAMILY_H)
+    list(APPEND CRYPTOPP_COMPILE_OPTIONS "/FIwinapifamily.h")
+  endif()
+endif ()
+
+# Enable PIC for all target machines except 32-bit i386 due to register pressures.
+if (NOT CRYPTOPP_I386)
+  SET(CMAKE_POSITION_INDEPENDENT_CODE 1)
+endif ()
+
+# IBM XLC compiler options for AIX and Linux.
+# Must use CMAKE_CXX_COMPILER here due to XLC 13.1 and LLVM front-end.
+if (CMAKE_CXX_COMPILER MATCHES "xlC")
+
+  #CheckCompileLinkOption("-qxlcompatmacros" CRYPTOPP_XLC_COMPAT "${TEST_CXX_FILE}")
+  #if (CRYPTOPP_XLC_COMPAT)
+  #  list(APPEND CRYPTOPP_COMPILE_OPTIONS "-qxlcompatmacros")
+  #endif ()
+
+  CheckCompileLinkOption("-qrtti" CRYPTOPP_PPC_RTTI "${TEST_CXX_FILE}")
+  if (CRYPTOPP_PPC_RTTI)
+    list(APPEND CRYPTOPP_COMPILE_OPTIONS "-qrtti")
+  endif ()
+
+  CheckCompileLinkOption("-qmaxmem=-1" CRYPTOPP_PPC_MAXMEM "${TEST_CXX_FILE}")
+  if (CRYPTOPP_PPC_MAXMEM)
+    list(APPEND CRYPTOPP_COMPILE_OPTIONS "-qmaxmem=-1")
+  endif ()
+
+  CheckCompileLinkOption("-qthreaded" CRYPTOPP_PPC_THREADED "${TEST_CXX_FILE}")
+  if (CRYPTOPP_PPC_THREADED)
+    list(APPEND CRYPTOPP_COMPILE_OPTIONS "-qthreaded")
+  endif ()
+endif ()
+
+# Solaris specific
+if (CRYPTOPP_SOLARIS)
+
+  # SunCC needs -template=no%extdef
+  if (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
+    list(APPEND CRYPTOPP_COMPILE_OPTIONS "-template=no%extdef")
+  endif ()
+
+  # SunCC needs -xregs=no%appl on Sparc (not x86) for libraries (not test program)
+  # TODO: wire this up properly
+  if (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro" AND (CRYPTOPP_SPARC OR CRYPTOPP_SPARC64))
+    list(APPEND CRYPTOPP_COMPILE_OPTIONS "-xregs=no%appl")
+  endif ()
+
+  # GCC needs to enable use of '/' for division in the assembler
+  if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+    list(APPEND CRYPTOPP_COMPILE_OPTIONS "-Wa,--divide")
+  endif ()
+
+endif ()
+
+#============================================================================
+# Sources & headers
+#============================================================================
+
+# Library headers
+file(GLOB cryptopp_HEADERS ${SRC_DIR}/*.h)
+
+# Remove headers used to build test suite
+list(REMOVE_ITEM cryptopp_HEADERS
+    ${SRC_DIR}/bench.h
+    ${SRC_DIR}/validate.h
+    )
+
+# Test sources. You can use the GNUmakefile to generate the list: `make sources`.
+set(cryptopp_SOURCES_TEST
+    ${SRC_DIR}/test.cpp
+    ${SRC_DIR}/bench1.cpp
+    ${SRC_DIR}/bench2.cpp
+    ${SRC_DIR}/bench3.cpp
+    ${SRC_DIR}/validat0.cpp
+    ${SRC_DIR}/validat1.cpp
+    ${SRC_DIR}/validat2.cpp
+    ${SRC_DIR}/validat3.cpp
+    ${SRC_DIR}/validat4.cpp
+    ${SRC_DIR}/validat5.cpp
+    ${SRC_DIR}/validat6.cpp
+    ${SRC_DIR}/validat7.cpp
+    ${SRC_DIR}/validat8.cpp
+    ${SRC_DIR}/validat9.cpp
+    ${SRC_DIR}/validat10.cpp
+    ${SRC_DIR}/regtest1.cpp
+    ${SRC_DIR}/regtest2.cpp
+    ${SRC_DIR}/regtest3.cpp
+    ${SRC_DIR}/regtest4.cpp
+    ${SRC_DIR}/datatest.cpp
+    ${SRC_DIR}/fipsalgt.cpp
+    ${SRC_DIR}/fipstest.cpp
+    ${SRC_DIR}/dlltest.cpp
+    #${SRC_DIR}/adhoc.cpp
+    )
+
+# Library sources. You can use the GNUmakefile to generate the list: `make sources`.
+# Makefile sorted them at http://github.com/weidai11/cryptopp/pull/426.
+file(GLOB cryptopp_SOURCES ${SRC_DIR}/*.cpp)
+list(SORT cryptopp_SOURCES)
+list(REMOVE_ITEM cryptopp_SOURCES
+    ${SRC_DIR}/cryptlib.cpp
+    ${SRC_DIR}/cpu.cpp
+    ${SRC_DIR}/integer.cpp
+    ${SRC_DIR}/pch.cpp
+    ${SRC_DIR}/simple.cpp
+    ${SRC_DIR}/adhoc.cpp
+    ${cryptopp_SOURCES_TEST}
+    )
+set(cryptopp_SOURCES
+    ${SRC_DIR}/cryptlib.cpp
+    ${SRC_DIR}/cpu.cpp
+    ${SRC_DIR}/integer.cpp
+    ${cryptopp_SOURCES}
+    )
+
+if(ANDROID)
+    include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
+    list(APPEND cryptopp_SOURCES ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
+endif()
+
+set(cryptopp_SOURCES_ASM)
+
+if (MSVC AND NOT DISABLE_ASM)
+  if (${CMAKE_GENERATOR} MATCHES ".*ARM")
+    message(STATUS "Disabling ASM because ARM is specified as target platform.")
+  else ()
+    enable_language(ASM_MASM)
+    list(APPEND cryptopp_SOURCES_ASM
+      ${SRC_DIR}/rdrand.asm
+      ${SRC_DIR}/rdseed.asm
+      )
+    if (CMAKE_SIZEOF_VOID_P EQUAL 8)
+      list(APPEND cryptopp_SOURCES_ASM
+        ${SRC_DIR}/x64dll.asm
+        ${SRC_DIR}/x64masm.asm
+        )
+      set_source_files_properties(${cryptopp_SOURCES_ASM} PROPERTIES COMPILE_DEFINITIONS "_M_X64")
+    else ()
+      set_source_files_properties(${cryptopp_SOURCES_ASM} PROPERTIES COMPILE_DEFINITIONS "_M_X86" COMPILE_FLAGS "/safeseh")
+    endif ()
+    set_source_files_properties(${cryptopp_SOURCES_ASM} PROPERTIES LANGUAGE ASM_MASM)
+  endif ()
+endif ()
+
+#============================================================================
+# Architecture flags
+#============================================================================
+
+# TODO: Android, AIX, IBM xlC, iOS and a few other profiles are missing.
+
+# New as of Pull Request 461, http://github.com/weidai11/cryptopp/pull/461.
+# Must use CMAKE_CXX_COMPILER here due to XLC 13.1 and LLVM front-end.
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Intel" OR CMAKE_CXX_COMPILER MATCHES "xlC")
+
+  if (CRYPTOPP_AMD64 OR CRYPTOPP_I386)
+
+    # For Darwin and a GCC port compiler, we need to check for -Wa,-q first. -Wa,-q
+    # is a GCC option, and it tells GCC to use the Clang Integrated Assembler. We
+    # need LLVM's assembler because GAS is too old on Apple platforms. GAS will
+    # not assemble modern ISA, like AVX or AVX2.
+	if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+      CheckCompileLinkOption("-Wa,-q" CRYPTOPP_X86_WAQ
+                             "${TEST_PROG_DIR}/test_x86_sse2.cpp")
+
+      if (CRYPTOPP_X86_WAQ)
+        list(APPEND CRYPTOPP_COMPILE_OPTIONS "-Wa,-q")
+      endif ()
+	endif ()
+
+    # Now we can move on to normal feature testing.
+    CheckCompileLinkOption("-msse2" CRYPTOPP_X86_SSE2
+                           "${TEST_PROG_DIR}/test_x86_sse2.cpp")
+    CheckCompileLinkOption("-mssse3" CRYPTOPP_X86_SSSE3
+                           "${TEST_PROG_DIR}/test_x86_ssse3.cpp")
+    CheckCompileLinkOption("-msse4.1" CRYPTOPP_X86_SSE41
+                           "${TEST_PROG_DIR}/test_x86_sse41.cpp")
+    CheckCompileLinkOption("-msse4.2" CRYPTOPP_X86_SSE42
+                           "${TEST_PROG_DIR}/test_x86_sse42.cpp")
+    CheckCompileLinkOption("-mssse3 -mpclmul" CRYPTOPP_X86_CLMUL
+                           "${TEST_PROG_DIR}/test_x86_clmul.cpp")
+    CheckCompileLinkOption("-msse4.1 -maes" CRYPTOPP_X86_AES
+                           "${TEST_PROG_DIR}/test_x86_aes.cpp")
+    CheckCompileLinkOption("-mavx" CRYPTOPP_X86_AVX
+                           "${TEST_PROG_DIR}/test_x86_avx.cpp")
+    CheckCompileLinkOption("-mavx2" CRYPTOPP_X86_AVX2
+                           "${TEST_PROG_DIR}/test_x86_avx2.cpp")
+    CheckCompileLinkOption("-msse4.2 -msha" CRYPTOPP_X86_SHA
+                           "${TEST_PROG_DIR}/test_x86_sha.cpp")
+    if (EXISTS "${TEST_PROG_DIR}/test_asm_mixed.cpp")
+      CheckCompileLinkOption("" CRYPTOPP_MIXED_ASM
+                             "${TEST_PROG_DIR}/test_asm_mixed.cpp")
+    else ()
+      CheckCompileLinkOption("" CRYPTOPP_MIXED_ASM
+                             "${TEST_PROG_DIR}/test_mixed_asm.cpp")
+    endif ()
+
+    # https://github.com/weidai11/cryptopp/issues/756
+    if (NOT CRYPTOPP_MIXED_ASM)
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_MIXED_ASM")
+    endif ()
+
+    if (NOT CRYPTOPP_X86_SSE2 AND NOT DISABLE_ASM)
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_ASM")
+    elseif (CRYPTOPP_X86_SSE2 AND NOT DISABLE_ASM)
+      set_source_files_properties(${SRC_DIR}/sse_simd.cpp PROPERTIES COMPILE_FLAGS "-msse2")
+      set_source_files_properties(${SRC_DIR}/chacha_simd.cpp PROPERTIES COMPILE_FLAGS "-msse2")
+      set_source_files_properties(${SRC_DIR}/donna_sse.cpp PROPERTIES COMPILE_FLAGS "-msse2")
+    endif ()
+    if (NOT CRYPTOPP_X86_SSSE3 AND NOT DISABLE_SSSE3)
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SSSE3")
+    elseif (CRYPTOPP_X86_SSSE3 AND NOT DISABLE_SSSE3)
+      set_source_files_properties(${SRC_DIR}/aria_simd.cpp PROPERTIES COMPILE_FLAGS "-mssse3")
+      set_source_files_properties(${SRC_DIR}/cham_simd.cpp PROPERTIES COMPILE_FLAGS "-mssse3")
+      set_source_files_properties(${SRC_DIR}/keccak_simd.cpp PROPERTIES COMPILE_FLAGS "-mssse3")
+      set_source_files_properties(${SRC_DIR}/lea_simd.cpp PROPERTIES COMPILE_FLAGS "-mssse3")
+      set_source_files_properties(${SRC_DIR}/lsh256_sse.cpp PROPERTIES COMPILE_FLAGS "-mssse3")
+      set_source_files_properties(${SRC_DIR}/lsh512_sse.cpp PROPERTIES COMPILE_FLAGS "-mssse3")
+      set_source_files_properties(${SRC_DIR}/simon128_simd.cpp PROPERTIES COMPILE_FLAGS "-mssse3")
+      set_source_files_properties(${SRC_DIR}/speck128_simd.cpp PROPERTIES COMPILE_FLAGS "-mssse3")
+      if (NOT CRYPTOPP_X86_SSE41 AND NOT DISABLE_SSE4)
+        list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SSE4")
+      elseif (CRYPTOPP_X86_SSE41 AND NOT DISABLE_SSE4)
+        set_source_files_properties(${SRC_DIR}/blake2s_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.1")
+        set_source_files_properties(${SRC_DIR}/blake2b_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.1")
+      endif ()
+      if (NOT CRYPTOPP_X86_SSE42 AND NOT DISABLE_SSE4)
+        list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SSE4")
+      elseif (CRYPTOPP_X86_SSE42 AND NOT DISABLE_SSE4)
+        set_source_files_properties(${SRC_DIR}/crc_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.2")
+        if (NOT CRYPTOPP_X86_CLMUL AND NOT DISABLE_CLMUL)
+          list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_CLMUL")
+        elseif (CRYPTOPP_X86_CLMUL AND NOT DISABLE_CLMUL)
+          set_source_files_properties(${SRC_DIR}/gcm_simd.cpp PROPERTIES COMPILE_FLAGS "-mssse3 -mpclmul")
+          set_source_files_properties(${SRC_DIR}/gf2n_simd.cpp PROPERTIES COMPILE_FLAGS "-mpclmul")
+        endif ()
+        if (NOT CRYPTOPP_X86_AES AND NOT DISABLE_AES)
+          list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_AESNI")
+        elseif (CRYPTOPP_X86_AES AND NOT DISABLE_AES)
+          set_source_files_properties(${SRC_DIR}/rijndael_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.1 -maes")
+          set_source_files_properties(${SRC_DIR}/sm4_simd.cpp PROPERTIES COMPILE_FLAGS "-mssse3 -maes")
+        endif ()
+        if (NOT CRYPTOPP_X86_AVX2 AND NOT DISABLE_AVX2)
+          list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_AVX2")
+        elseif (CRYPTOPP_X86_AVX2 AND NOT DISABLE_AVX2)
+          set_source_files_properties(${SRC_DIR}/chacha_avx.cpp PROPERTIES COMPILE_FLAGS "-mavx2")
+          set_source_files_properties(${SRC_DIR}/lsh256_avx.cpp PROPERTIES COMPILE_FLAGS "-mavx2")
+          set_source_files_properties(${SRC_DIR}/lsh512_avx.cpp PROPERTIES COMPILE_FLAGS "-mavx2")
+        endif ()
+        if (NOT CRYPTOPP_X86_SHA AND NOT DISABLE_SHA)
+          list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SHANI")
+        elseif (CRYPTOPP_X86_SHA AND NOT DISABLE_SHA)
+          set_source_files_properties(${SRC_DIR}/sha_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.2 -msha")
+          set_source_files_properties(${SRC_DIR}/shacal2_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.2 -msha")
+        endif ()
+      endif ()
+    endif ()
+
+  elseif (CRYPTOPP_ARMV8)
+
+    # This checks for <arm_acle.h>
+    CheckCompileLinkOption("-march=armv8-a" CRYPTOPP_ARM_ACLE_HEADER
+                           "${TEST_PROG_DIR}/test_arm_acle_header.cpp")
+
+    # Use <arm_acle.h> if available
+    if (CRYPTOPP_ARM_NEON_HEADER)
+      CheckCompileOption("-march=armv8-a -DCRYPTOPP_ARM_ACLE_HEADER=1" CRYPTOPP_ARMV8A_ASIMD)
+      CheckCompileOption("-march=armv8-a+crc -DCRYPTOPP_ARM_ACLE_HEADER=1" CRYPTOPP_ARMV8A_CRC)
+      CheckCompileOption("-march=armv8-a+crypto -DCRYPTOPP_ARM_ACLE_HEADER=1" CRYPTOPP_ARMV8A_CRYPTO)
+    else ()
+      CheckCompileOption("-march=armv8-a" CRYPTOPP_ARMV8A_ASIMD)
+      CheckCompileOption("-march=armv8-a+crc" CRYPTOPP_ARMV8A_CRC)
+      CheckCompileOption("-march=armv8-a+crypto" CRYPTOPP_ARMV8A_CRYPTO)
+    endif ()
+
+    if (CRYPTOPP_ARMV8A_ASIMD)
+      set_source_files_properties(${SRC_DIR}/aria_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a")
+      set_source_files_properties(${SRC_DIR}/blake2s_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a")
+      set_source_files_properties(${SRC_DIR}/blake2b_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a")
+      set_source_files_properties(${SRC_DIR}/chacha_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a")
+      set_source_files_properties(${SRC_DIR}/cham_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a")
+      set_source_files_properties(${SRC_DIR}/lea_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a")
+      set_source_files_properties(${SRC_DIR}/neon_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a")
+      set_source_files_properties(${SRC_DIR}/simon128_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a")
+      set_source_files_properties(${SRC_DIR}/speck128_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a")
+    else ()
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_ARM_ASIMD")
+    endif ()
+    if (CRYPTOPP_ARMV8A_CRC)
+      set_source_files_properties(${SRC_DIR}/crc_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a+crc")
+    else ()
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_ARM_CRC32")
+    endif ()
+    if (CRYPTOPP_ARMV8A_CRYPTO)
+      set_source_files_properties(${SRC_DIR}/gcm_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a+crypto")
+      set_source_files_properties(${SRC_DIR}/gf2n_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a+crypto")
+      set_source_files_properties(${SRC_DIR}/rijndael_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a+crypto")
+      set_source_files_properties(${SRC_DIR}/sha_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a+crypto")
+      set_source_files_properties(${SRC_DIR}/shacal2_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv8-a+crypto")
+    else ()
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_ARM_AES")
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_ARM_PMULL")
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_ARM_SHA")
+    endif ()
+
+  elseif (CRYPTOPP_ARM32)
+
+    # This checks for <arm_neon.h>
+    CheckCompileLinkOption("-march=armv7-a -mfpu=neon" CRYPTOPP_ARM_NEON_HEADER
+                           "${TEST_PROG_DIR}/test_arm_neon_header.cpp")
+
+    # Use <arm_neon.h> if available
+    if (CRYPTOPP_ARM_NEON_HEADER)
+      CheckCompileLinkOption("-march=armv7-a -mfpu=neon -DCRYPTOPP_ARM_NEON_HEADER=1" CRYPTOPP_ARMV7A_NEON
+                             "${TEST_PROG_DIR}/test_arm_neon.cpp")
+    else ()
+      CheckCompileLinkOption("-march=armv7-a -mfpu=neon" CRYPTOPP_ARMV7A_NEON
+                             "${TEST_PROG_DIR}/test_arm_neon.cpp")
+    endif ()
+
+    if (CRYPTOPP_ARMV7A_NEON)
+
+      # Add Cryptogams ASM files for ARM on Linux. Linux is required due to GNU Assembler.
+      # AES requires -mthumb under Clang. Do not add -mthumb for SHA for any files.
+      if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
+        list(APPEND cryptopp_SOURCES ${SRC_DIR}/aes_armv4.S)
+        list(APPEND cryptopp_SOURCES ${SRC_DIR}/sha1_armv4.S)
+        list(APPEND cryptopp_SOURCES ${SRC_DIR}/sha256_armv4.S)
+        list(APPEND cryptopp_SOURCES ${SRC_DIR}/sha512_armv4.S)
+
+        set_source_files_properties(${SRC_DIR}/aes_armv4.S PROPERTIES LANGUAGE CXX)
+        set_source_files_properties(${SRC_DIR}/sha1_armv4.S PROPERTIES LANGUAGE CXX)
+        set_source_files_properties(${SRC_DIR}/sha256_armv4.S PROPERTIES LANGUAGE CXX)
+        set_source_files_properties(${SRC_DIR}/sha512_armv4.S PROPERTIES LANGUAGE CXX)
+
+        if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+          set_source_files_properties(${SRC_DIR}/aes_armv4.S PROPERTIES COMPILE_FLAGS "-march=armv7-a -mthumb -mfpu=neon -Wa,--noexecstack")
+        else ()
+          set_source_files_properties(${SRC_DIR}/aes_armv4.S PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon -Wa,--noexecstack")
+        endif ()
+
+        set_source_files_properties(${SRC_DIR}/sha1_armv4.S PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon -Wa,--noexecstack")
+        set_source_files_properties(${SRC_DIR}/sha256_armv4.S PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon -Wa,--noexecstack")
+        set_source_files_properties(${SRC_DIR}/sha512_armv4.S PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon -Wa,--noexecstack")
+      endif ()
+
+      set_source_files_properties(${SRC_DIR}/aria_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/blake2s_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/blake2b_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/chacha_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/cham_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/crc_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/lea_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/gcm_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/rijndael_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/neon_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/sha_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/simon128_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/speck128_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+      set_source_files_properties(${SRC_DIR}/sm4_simd.cpp PROPERTIES COMPILE_FLAGS "-march=armv7-a -mfpu=neon")
+    else ()
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_ARM_NEON")
+    endif ()
+
+  elseif (CRYPTOPP_PPC32 OR CRYPTOPP_PPC64)
+
+    # XLC requires -qaltivec in addition to Arch or CPU option
+    # Disable POWER9 due to https://github.com/weidai11/cryptopp/issues/986.
+    if (CMAKE_CXX_COMPILER MATCHES "xlC")
+      set(CRYPTOPP_ALTIVEC_FLAGS "-qaltivec")
+      set(CRYPTOPP_POWER4_FLAGS "-qarch=pwr4 -qaltivec")
+      set(CRYPTOPP_POWER5_FLAGS "-qarch=pwr5 -qaltivec")
+      set(CRYPTOPP_POWER6_FLAGS "-qarch=pwr6 -qaltivec")
+      set(CRYPTOPP_POWER7_VSX_FLAG  "-qarch=pwr7 -qvsx -qaltivec")
+      set(CRYPTOPP_POWER7_PWR_FLAGS "-qarch=pwr7 -qaltivec")
+      set(CRYPTOPP_POWER8_FLAGS "-qarch=pwr8 -qaltivec")
+      #set(CRYPTOPP_POWER9_FLAGS "-qarch=pwr9 -qaltivec")
+    else ()
+      set(CRYPTOPP_ALTIVEC_FLAGS "-maltivec")
+      set(CRYPTOPP_POWER7_VSX_FLAGS "-mcpu=power7 -mvsx")
+      set(CRYPTOPP_POWER7_PWR_FLAGS "-mcpu=power7")
+      set(CRYPTOPP_POWER8_FLAGS "-mcpu=power8")
+      #set(CRYPTOPP_POWER9_FLAGS "-mcpu=power9")
+    endif ()
+
+    CheckCompileLinkOption("${CRYPTOPP_ALTIVEC_FLAGS}" PPC_ALTIVEC_FLAG
+                           "${TEST_PROG_DIR}/test_ppc_altivec.cpp")
+
+    # Hack for XLC. Find the lowest PWR architecture.
+    if (CMAKE_CXX_COMPILER MATCHES "xlC")
+      if (NOT PPC_ALTIVEC_FLAG)
+        CheckCompileLinkOption("${CRYPTOPP_POWER4_FLAGS}" PPC_POWER4_FLAG
+                               "${TEST_PROG_DIR}/test_ppc_altivec.cpp")
+        if (PPC_POWER4_FLAG)
+          set(PPC_ALTIVEC_FLAG 1)
+          set(CRYPTOPP_ALTIVEC_FLAGS "${CRYPTOPP_POWER4_FLAGS}")
+        endif ()
+      endif ()
+      if (NOT PPC_ALTIVEC_FLAG)
+        CheckCompileLinkOption("${CRYPTOPP_POWER5_FLAGS}" PPC_POWER5_FLAG
+                               "${TEST_PROG_DIR}/test_ppc_altivec.cpp")
+        if (PPC_POWER5_FLAG)
+          set(PPC_ALTIVEC_FLAG 1)
+          set(CRYPTOPP_ALTIVEC_FLAGS "${CRYPTOPP_POWER5_FLAGS}")
+        endif ()
+      endif ()
+      if (NOT PPC_ALTIVEC_FLAG)
+        CheckCompileLinkOption("${CRYPTOPP_POWER6_FLAGS}" PPC_POWER6_FLAG
+                               "${TEST_PROG_DIR}/test_ppc_altivec.cpp")
+        if (PPC_POWER6_FLAG)
+          set(PPC_ALTIVEC_FLAG 1)
+          set(CRYPTOPP_ALTIVEC_FLAGS "${CRYPTOPP_POWER6_FLAGS}")
+        endif ()
+      endif ()
+    endif ()
+
+    # Hack for XLC and GCC. Find the right combination for PWR7 and the VSX unit.
+    CheckCompileLinkOption("${CRYPTOPP_POWER7_VSX_FLAGS}" PPC_POWER7_FLAG
+                           "${TEST_PROG_DIR}/test_ppc_power7.cpp")
+    if (PPC_POWER7_FLAG)
+      set (CRYPTOPP_POWER7_FLAGS "${CRYPTOPP_POWER7_VSX_FLAGS}")
+    else ()
+      CheckCompileLinkOption("${CRYPTOPP_POWER7_PWR_FLAGS}" PPC_POWER7_FLAG
+                             "${TEST_PROG_DIR}/test_ppc_power7.cpp")
+      if (PPC_POWER7_FLAG)
+        set (CRYPTOPP_POWER7_FLAGS "${CRYPTOPP_POWER7_PWR_FLAGS}")
+      endif ()
+    endif ()
+
+    CheckCompileLinkOption("${CRYPTOPP_POWER8_FLAGS}" PPC_POWER8_FLAG
+                           "${TEST_PROG_DIR}/test_ppc_power8.cpp")
+
+    # Disable POWER9 due to https://github.com/weidai11/cryptopp/issues/986.
+    #CheckCompileLinkOption("${CRYPTOPP_POWER9_FLAGS}" PPC_POWER9_FLAG
+    #                       "${TEST_PROG_DIR}/test_ppc_power9.cpp")
+
+    #if (PPC_POWER9_FLAG AND NOT DISABLE_POWER9)
+    #  set_source_files_properties(${SRC_DIR}/ppc_power9.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER9_FLAGS})
+    #endif ()
+
+    if (PPC_POWER8_FLAG AND NOT DISABLE_POWER8)
+      set_source_files_properties(${SRC_DIR}/ppc_power8.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      #set_source_files_properties(${SRC_DIR}/aria_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      set_source_files_properties(${SRC_DIR}/blake2b_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      set_source_files_properties(${SRC_DIR}/cham_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      #set_source_files_properties(${SRC_DIR}/crc_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      set_source_files_properties(${SRC_DIR}/gcm_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      set_source_files_properties(${SRC_DIR}/gf2n_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      set_source_files_properties(${SRC_DIR}/lea_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      set_source_files_properties(${SRC_DIR}/rijndael_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      set_source_files_properties(${SRC_DIR}/sha_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      set_source_files_properties(${SRC_DIR}/shacal2_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      set_source_files_properties(${SRC_DIR}/simon128_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+      set_source_files_properties(${SRC_DIR}/speck128_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER8_FLAGS})
+    endif ()
+
+    if (PPC_POWER7_FLAG AND NOT DISABLE_POWER7)
+      set_source_files_properties(${SRC_DIR}/ppc_power7.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_POWER7_FLAGS})
+    endif ()
+
+    if (PPC_ALTIVEC_FLAG AND NOT DISABLE_ALTIVEC)
+      set_source_files_properties(${SRC_DIR}/ppc_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_ALTIVEC_FLAGS})
+      set_source_files_properties(${SRC_DIR}/blake2s_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_ALTIVEC_FLAGS})
+      set_source_files_properties(${SRC_DIR}/chacha_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_ALTIVEC_FLAGS})
+    endif ()
+
+    # Drop to Altivec if Power8 unavailable
+    if (NOT PPC_POWER8_FLAG)
+      if (PPC_ALTIVEC_FLAG)
+        set_source_files_properties(${SRC_DIR}/gcm_simd.cpp PROPERTIES COMPILE_FLAGS ${CRYPTOPP_ALTIVEC_FLAGS})
+      endif ()
+    endif ()
+
+    if (NOT PPC_ALTIVEC_FLAG)
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_ALTIVEC")
+    elseif (NOT PPC_POWER7_FLAG)
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_POWER7")
+    elseif (NOT PPC_POWER8_FLAG)
+      list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_POWER8")
+    #elseif (NOT PPC_POWER9_FLAG)
+    #  list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_POWER9")
+    endif ()
+
+  endif ()
+endif ()
+
+# New as of Pull Request 461, http://github.com/weidai11/cryptopp/pull/461.
+if (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
+
+  if (CRYPTOPP_AMD64 OR CRYPTOPP_I386)
+
+    CheckCompileLinkOption("-xarch=sse2" CRYPTOPP_X86_SSE2
+                           "${TEST_PROG_DIR}/test_x86_sse2.cpp")
+    CheckCompileLinkOption("-xarch=ssse3" CRYPTOPP_X86_SSSE3
+                           "${TEST_PROG_DIR}/test_x86_ssse3.cpp")
+    CheckCompileLinkOption("-xarch=sse4_1" CRYPTOPP_X86_SSE41
+                           "${TEST_PROG_DIR}/test_x86_sse41.cpp")
+    CheckCompileLinkOption("-xarch=sse4_2" CRYPTOPP_X86_SSE42
+                           "${TEST_PROG_DIR}/test_x86_sse42.cpp")
+    CheckCompileLinkOption("-xarch=aes" CRYPTOPP_X86_CLMUL
+                           "${TEST_PROG_DIR}/test_x86_clmul.cpp")
+    CheckCompileLinkOption("-xarch=aes" CRYPTOPP_X86_AES
+                           "${TEST_PROG_DIR}/test_x86_aes.cpp")
+    CheckCompileLinkOption("-xarch=avx" CRYPTOPP_X86_AVX
+                           "${TEST_PROG_DIR}/test_x86_avx.cpp")
+    CheckCompileLinkOption("-xarch=avx2" CRYPTOPP_X86_AVX2
+                           "${TEST_PROG_DIR}/test_x86_avx2.cpp")
+    CheckCompileLinkOption("-xarch=sha" CRYPTOPP_X86_SHA
+                           "${TEST_PROG_DIR}/test_x86_sha.cpp")
+
+    # Each -xarch=XXX options must be added to LDFLAGS if the option is used during a compile.
+    set(XARCH_LDFLAGS "")
+
+    if (CRYPTOPP_X86_SSE2 AND NOT DISABLE_ASM)
+      set_source_files_properties(${SRC_DIR}/sse_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=sse2")
+      set_source_files_properties(${SRC_DIR}/chacha_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=sse2")
+      set(XARCH_LDFLAGS "-xarch=sse2")
+    endif ()
+    if (CRYPTOPP_X86_SSSE3 AND NOT DISABLE_SSSE3)
+      set_source_files_properties(${SRC_DIR}/aria_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=ssse3")
+      set_source_files_properties(${SRC_DIR}/cham_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=ssse3")
+      set_source_files_properties(${SRC_DIR}/lea_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=ssse3")
+      set_source_files_properties(${SRC_DIR}/simon128_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=ssse3")
+      set_source_files_properties(${SRC_DIR}/speck128_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=ssse3")
+      set(XARCH_LDFLAGS "${XARCH_LDFLAGS} -xarch=ssse3")
+      if (CRYPTOPP_X86_SSE41 AND NOT DISABLE_SSE4)
+        set_source_files_properties(${SRC_DIR}/blake2s_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=sse4_1")
+        set_source_files_properties(${SRC_DIR}/blake2b_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=sse4_1")
+        set(XARCH_LDFLAGS "${XARCH_LDFLAGS} -xarch=sse4_1")
+      endif ()
+      if (CRYPTOPP_X86_SSE42 AND NOT DISABLE_SSE4)
+        set_source_files_properties(${SRC_DIR}/crc_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=sse4_2")
+        set(XARCH_LDFLAGS "${XARCH_LDFLAGS} -xarch=sse4_2")
+        if (CRYPTOPP_X86_CLMUL AND NOT DISABLE_CLMUL)
+          set_source_files_properties(${SRC_DIR}/gcm_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=aes")
+          set_source_files_properties(${SRC_DIR}/gf2n_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=aes")
+        endif ()
+        if (CRYPTOPP_X86_AES AND NOT DISABLE_AES)
+          set_source_files_properties(${SRC_DIR}/rijndael_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=aes")
+          set_source_files_properties(${SRC_DIR}/sm4_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=aes")
+          set(XARCH_LDFLAGS "${XARCH_LDFLAGS} -xarch=aes")
+        endif ()
+        #if (CRYPTOPP_X86_AVX AND NOT DISABLE_AVX)
+        #  set_source_files_properties(${SRC_DIR}/XXX_avx.cpp PROPERTIES COMPILE_FLAGS "-xarch=avx2")
+        #  set(XARCH_LDFLAGS "${XARCH_LDFLAGS} -xarch=avx")
+        #endif ()
+        if (CRYPTOPP_X86_AVX2 AND NOT DISABLE_AVX2)
+          set_source_files_properties(${SRC_DIR}/chacha_avx.cpp PROPERTIES COMPILE_FLAGS "-xarch=avx2")
+          set(XARCH_LDFLAGS "${XARCH_LDFLAGS} -xarch=avx2")
+        endif ()
+        if (CRYPTOPP_X86_SHA AND NOT DISABLE_SHA)
+          set_source_files_properties(${SRC_DIR}/sha_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=sha")
+          set_source_files_properties(${SRC_DIR}/shacal2_simd.cpp PROPERTIES COMPILE_FLAGS "-xarch=sha")
+          set(XARCH_LDFLAGS "${XARCH_LDFLAGS} -xarch=sha")
+        endif ()
+      endif ()
+    endif ()
+
+    # https://stackoverflow.com/a/6088646/608639
+    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${XARCH_LDFLAGS} -M${SRC_DIR}/cryptopp.mapfile")
+    set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${XARCH_LDFLAGS} -M${SRC_DIR}/cryptopp.mapfile")
+    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${XARCH_LDFLAGS} -M${SRC_DIR}/cryptopp.mapfile")
+
+  # elseif (CRYPTOPP_SPARC OR CRYPTOPP_SPARC64)
+
+  endif ()
+endif ()
+
+#============================================================================
+# Compiler flags
+#============================================================================
+
+# add_compile_definitions added in CMake 3.12
+if (${CMAKE_VERSION} VERSION_LESS "3.12")
+  # https://stackoverflow.com/q/61250087
+  add_definitions("${CMAKE_CPP_FLAGS}" "${CMAKE_CXX_FLAGS}" "${CRYPTOPP_COMPILE_DEFINITIONS}" "${CRYPTOPP_COMPILE_OPTIONS}")
+else()
+  add_compile_definitions("${CMAKE_CPP_FLAGS}" "${CRYPTOPP_COMPILE_DEFINITIONS}")
+  add_compile_options("${CMAKE_CXX_FLAGS}" "${CRYPTOPP_COMPILE_OPTIONS}")
+endif()
+
+#============================================================================
+# Compile targets
+#============================================================================
+
+# Work around the archaic versions of cmake that do not support
+# target_compile_xxxx commands
+# !!! DO NOT try to use the old way for newer version - it does not work !!!
+function(cryptopp_target_compile_properties target)
+  # CMake >= 2.8.12
+  if (NOT ${CMAKE_VERSION} VERSION_LESS "2.8.12")
+    SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${CRYPTOPP_COMPILE_OPTIONS}")
+  else()
+    string (REPLACE ";" " " PROP_STR "${CRYPTOPP_COMPILE_OPTIONS}")
+    set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${PROP_STR}")
+  endif()
+  # CMake >= 2.8.11
+  if (NOT ${CMAKE_VERSION} VERSION_LESS "2.8.11")
+    target_compile_definitions(${target} PUBLIC ${CRYPTOPP_COMPILE_DEFINITIONS})
+  else()
+    string (REPLACE ";" " " PROP_STR "${CRYPTOPP_COMPILE_DEFINITIONS}")
+    set_target_properties(${target} PROPERTIES COMPILE_DEFINITIONS "${CRYPTOPP_COMPILE_DEFINITIONS}")
+  endif()
+endfunction()
+
+set(cryptopp_LIBRARY_SOURCES ${cryptopp_SOURCES_ASM})
+if (USE_INTERMEDIATE_OBJECTS_TARGET AND NOT ${CMAKE_VERSION} VERSION_LESS "2.8.8")
+  add_library(cryptopp-object OBJECT ${cryptopp_SOURCES})
+  cryptopp_target_compile_properties(cryptopp-object)
+
+  list(APPEND cryptopp_LIBRARY_SOURCES
+    $<TARGET_OBJECTS:cryptopp-object>
+    )
+else ()
+  list(APPEND cryptopp_LIBRARY_SOURCES
+    ${cryptopp_SOURCES}
+    )
+endif ()
+
+if (BUILD_STATIC)
+  add_library(cryptopp-static STATIC ${cryptopp_LIBRARY_SOURCES})
+  cryptopp_target_compile_properties(cryptopp-static)
+  # CMake >= 2.8.11
+  if (NOT ${CMAKE_VERSION} VERSION_LESS "2.8.11")
+    target_include_directories(cryptopp-static PUBLIC $<BUILD_INTERFACE:${SRC_DIR}> $<INSTALL_INTERFACE:include>)
+  else ()
+    set_target_properties(cryptopp-static PROPERTIES INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${SRC_DIR}> $<INSTALL_INTERFACE:include>")
+  endif ()
+endif ()
+
+if (BUILD_SHARED)
+  add_library(cryptopp-shared SHARED ${cryptopp_LIBRARY_SOURCES})
+  cryptopp_target_compile_properties(cryptopp-shared)
+  if (NOT ${CMAKE_VERSION} VERSION_LESS "2.8.11")
+    target_include_directories(cryptopp-shared PUBLIC $<BUILD_INTERFACE:${SRC_DIR}> $<INSTALL_INTERFACE:include>)
+  else ()
+    set_target_properties(cryptopp-shared PROPERTIES INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${SRC_DIR}> $<INSTALL_INTERFACE:include>")
+  endif ()
+endif ()
+
+# Set filenames for targets to be "cryptopp"
+if (NOT MSVC)
+  set(COMPAT_VERSION ${cryptopp_VERSION_MAJOR}.${cryptopp_VERSION_MINOR})
+
+  if (BUILD_STATIC)
+    set_target_properties(cryptopp-static
+        PROPERTIES
+        OUTPUT_NAME cryptopp)
+  endif ()
+  if (BUILD_SHARED)
+    set_target_properties(cryptopp-shared
+        PROPERTIES
+        SOVERSION ${COMPAT_VERSION}
+        OUTPUT_NAME cryptopp)
+  endif ()
+endif ()
+
+# Add alternate ways to invoke the build for the shared library that are
+# similar to how the crypto++ 'make' tool works.
+# see https://github.com/noloader/cryptopp-cmake/issues/32
+if (BUILD_STATIC)
+  add_custom_target(static DEPENDS cryptopp-static)
+endif ()
+if (BUILD_SHARED)
+  add_custom_target(shared DEPENDS cryptopp-shared)
+  add_custom_target(dynamic DEPENDS cryptopp-shared)
+endif ()
+
+#============================================================================
+# Third-party libraries
+#============================================================================
+
+if (WIN32)
+  if (BUILD_STATIC)
+    target_link_libraries(cryptopp-static ws2_32)
+  endif ()
+  if (BUILD_SHARED)
+    target_link_libraries(cryptopp-shared ws2_32)
+  endif ()
+endif ()
+
+# This may need to be expanded to "Solaris"
+if (CRYPTOPP_SOLARIS)
+  if (BUILD_STATIC)
+    target_link_libraries(cryptopp-static nsl socket)
+  endif ()
+  if (BUILD_SHARED)
+    target_link_libraries(cryptopp-shared nsl socket)
+  endif ()
+endif ()
+
+find_package(Threads)
+if (BUILD_STATIC)
+  target_link_libraries(cryptopp-static ${CMAKE_THREAD_LIBS_INIT})
+endif ()
+if (BUILD_SHARED)
+  target_link_libraries(cryptopp-shared ${CMAKE_THREAD_LIBS_INIT})
+endif ()
+
+
+#============================================================================
+# Setup OpenMP
+#============================================================================
+if (${CMAKE_VERSION} VERSION_GREATER "3.1" AND USE_OPENMP)
+  find_package(OpenMP)
+
+  if (OPENMP_FOUND OR OPENMP_CXX_FOUND)
+      message(STATUS "OpenMP: Found libomp without any special flags")
+  endif()
+
+  # If OpenMP wasn't found, try if we can find it in the default Macports location
+  if((NOT OPENMP_FOUND) AND (NOT OPENMP_CXX_FOUND) AND EXISTS "/opt/local/lib/libomp/libomp.dylib") # older cmake uses OPENMP_FOUND, newer cmake also sets OPENMP_CXX_FOUND, homebrew installations seem only to get the latter set.
+      set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I/opt/local/include/libomp/")
+      set(OpenMP_CXX_LIB_NAMES omp)
+      set(OpenMP_omp_LIBRARY /opt/local/lib/libomp/libomp.dylib)
+
+      find_package(OpenMP)
+      if (OPENMP_FOUND OR OPENMP_CXX_FOUND)
+          message(STATUS "OpenMP: Found libomp in macports default location.")
+      else()
+          message(FATAL_ERROR "OpenMP: Didn't find libomp. Tried macports default location but also didn't find it.")
+      endif()
+  endif()
+
+  # If OpenMP wasn't found, try if we can find it in the default Homebrew location
+  if((NOT OPENMP_FOUND) AND (NOT OPENMP_CXX_FOUND) AND EXISTS "/usr/local/opt/libomp/lib/libomp.dylib")
+      set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I/usr/local/opt/libomp/include")
+      set(OpenMP_CXX_LIB_NAMES omp)
+      set(OpenMP_omp_LIBRARY /usr/local/opt/libomp/lib/libomp.dylib)
+
+      find_package(OpenMP)
+      if (OPENMP_FOUND OR OPENMP_CXX_FOUND)
+          message(STATUS "OpenMP: Found libomp in homebrew default location.")
+      else()
+          message(FATAL_ERROR "OpenMP: Didn't find libomp. Tried homebrew default location but also didn't find it.")
+      endif()
+  endif()
+
+  set(Additional_OpenMP_Libraries_Workaround "")
+
+  # Workaround because older cmake on apple doesn't support FindOpenMP
+  if((NOT OPENMP_FOUND) AND (NOT OPENMP_CXX_FOUND))
+      if((APPLE AND ((CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")))
+              AND ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "7.0") AND (CMAKE_VERSION VERSION_LESS "3.12.0")))
+          message(STATUS "OpenMP: Applying workaround for OSX OpenMP with old cmake that doesn't have FindOpenMP")
+          set(OpenMP_CXX_FLAGS "-Xclang -fopenmp")
+          set(Additional_OpenMP_Libraries_Workaround "-lomp")
+      else()
+          message(FATAL_ERROR "OpenMP: Did not find OpenMP. Build without USE_OPENMP if you want to allow this.")
+      endif()
+  endif()
+
+  if(NOT TARGET OpenMP::OpenMP_CXX)
+      # We're on cmake < 3.9, handle behavior of the old FindOpenMP implementation
+      message(STATUS "OpenMP: Applying workaround for old CMake that doesn't define FindOpenMP using targets")
+      add_library(OpenMP_TARGET INTERFACE)
+      add_library(OpenMP::OpenMP_CXX ALIAS OpenMP_TARGET)
+      target_compile_options(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS}) # add to all targets depending on this
+      find_package(Threads REQUIRED)
+      target_link_libraries(OpenMP_TARGET INTERFACE Threads::Threads)
+      target_link_libraries(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS} ${Additional_OpenMP_Libraries_Workaround})
+  endif()
+
+  if (BUILD_STATIC)
+    target_link_libraries(cryptopp-static ${OpenMP_CXX_FLAGS}) # Workaround for Ubuntu 18.04 that otherwise doesn't set -fopenmp for linking
+    target_link_libraries(cryptopp-static OpenMP::OpenMP_CXX)
+  endif()
+  if (BUILD_SHARED)
+    target_link_libraries(cryptopp-shared ${OpenMP_CXX_FLAGS}) # Workaround for Ubuntu 18.04 that otherwise doesn't set -fopenmp for linking
+    target_link_libraries(cryptopp-shared OpenMP::OpenMP_CXX)
+  endif()
+endif()
+
+#============================================================================
+# Tests
+#============================================================================
+
+enable_testing()
+if (BUILD_TESTING)
+  add_executable(cryptest ${cryptopp_SOURCES_TEST})
+  target_link_libraries(cryptest cryptopp-static)
+
+  # Setting "cryptest" binary name to "cryptest.exe"
+  if (NOT (WIN32 OR CYGWIN))
+    set_target_properties(cryptest PROPERTIES OUTPUT_NAME cryptest.exe)
+  endif ()
+  if (NOT TARGET cryptest.exe)
+    add_custom_target(cryptest.exe)
+    add_dependencies(cryptest.exe cryptest)
+  endif ()
+
+  file(COPY ${SRC_DIR}/TestData DESTINATION ${PROJECT_BINARY_DIR})
+  file(COPY ${SRC_DIR}/TestVectors DESTINATION ${PROJECT_BINARY_DIR})
+
+  add_test(NAME cryptest COMMAND $<TARGET_FILE:cryptest> v)
+endif ()
+
+#============================================================================
+# Doxygen documentation
+#============================================================================
+
+if (BUILD_DOCUMENTATION)
+  find_package(Doxygen REQUIRED)
+
+  set(in_source_DOCS_DIR "${SRC_DIR}/html-docs")
+  set(out_source_DOCS_DIR "${PROJECT_BINARY_DIR}/html-docs")
+
+  add_custom_target(docs ALL
+      COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile -d CRYPTOPP_DOXYGEN_PROCESSING
+      WORKING_DIRECTORY ${SRC_DIR}
+      SOURCES ${SRC_DIR}/Doxyfile
+      )
+
+  if (NOT ${in_source_DOCS_DIR} STREQUAL ${out_source_DOCS_DIR})
+    add_custom_command(
+        TARGET docs POST_BUILD
+        COMMAND ${CMAKE_COMMAND} -E copy_directory "${in_source_DOCS_DIR}" "${out_source_DOCS_DIR}"
+        COMMAND ${CMAKE_COMMAND} -E remove_directory "${in_source_DOCS_DIR}"
+    )
+  endif ()
+endif ()
diff -pruN 0.11.1+ds-4/.github/workflows/ccpp.yml 0.13.1+ds-1/.github/workflows/ccpp.yml
--- 0.11.1+ds-4/.github/workflows/ccpp.yml	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/.github/workflows/ccpp.yml	2023-01-27 02:25:50.000000000 +0000
@@ -1,56 +1,79 @@
 name: C/C++ CI
 
-on:
-  push:
-    branches: [master]
-  pull_request:
-    branches: [master]
+on: [push, pull_request]
+
+env:
+  PYTHONUTF8: 1
 
 jobs:
   build-ubuntu:
-    runs-on: ubuntu-latest
-
+    runs-on: ubuntu-20.04
+    timeout-minutes: 35
     steps:
       - uses: actions/checkout@v1
         with:
           submodules: true
       - uses: actions/setup-python@v1
         with:
-          python-version: "3.x"
+          python-version: "3.6"
       - name: install
         run: sudo apt-get install fuse libfuse-dev
       - name: configure
-        run: mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..
+        run: mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release ..
       - name: build
-        run: cmake --build build
+        run: cmake --build build --config Release
       - name: test
-        run: cd build && ctest -V
+        run: cd build && ctest -V -C Release
       - name: upload
         uses: actions/upload-artifact@v1
         with:
           path: build/securefs
-          name: securefs-binary-ubuntu-debug
-
+          name: securefs-linux-amd64
+  build-mac:
+    runs-on: macos-10.15
+    timeout-minutes: 35
+    steps:
+      - uses: actions/checkout@v1
+        with:
+          submodules: true
+      - uses: actions/setup-python@v1
+        with:
+          python-version: "3.6"
+      - name: pip
+        run: pip install xattr
+      - name: install
+        run: brew install macfuse
+      - name: configure
+        run: mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release ..
+      - name: build
+        run: cmake --build build --config Release
+      - name: test
+        run: cd build && ctest -V -C Release
+      - name: upload
+        uses: actions/upload-artifact@v1
+        with:
+          path: build/securefs
+          name: securefs-macos-amd64
   build-windows:
     runs-on: windows-latest
-
+    timeout-minutes: 35
     steps:
       - uses: actions/checkout@v1
         with:
           submodules: true
       - uses: actions/setup-python@v1
         with:
-          python-version: "3.x"
+          python-version: "3.7"
       - name: install
         run: choco install winfsp
       - name: configure
-        run: mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..
+        run: mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release ..
       - name: build
-        run: cmake --build build --config Debug
+        run: cmake --build build --config Release
       - name: test
-        run: cd build && ctest -V -C Debug
+        run: cd build && ctest -V -C Release
       - name: upload
         uses: actions/upload-artifact@v1
         with:
-          path: build/Debug/securefs.exe
-          name: securefs-binary-win-debug.exe
+          path: build/Release/securefs.exe
+          name: securefs-windows-amd64
diff -pruN 0.11.1+ds-4/.gitignore 0.13.1+ds-1/.gitignore
--- 0.11.1+ds-4/.gitignore	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/.gitignore	2023-01-27 02:25:50.000000000 +0000
@@ -1,6 +1,8 @@
 .DS_Store
 ._*
 build/
+*-build/
+build-*/
 make/
 *.exe
 *.obj
@@ -8,3 +10,4 @@ make/
 .vscode
 out/
 CMakeSettings.json
+__pycache__
diff -pruN 0.11.1+ds-4/.gitmodules 0.13.1+ds-1/.gitmodules
--- 0.11.1+ds-4/.gitmodules	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/.gitmodules	2023-01-27 02:25:50.000000000 +0000
@@ -2,3 +2,15 @@
 	path = external/utf8proc
 	url = https://github.com/JuliaStrings/utf8proc.git
 	branch = release-1.2
+	shallow = true
+
+[submodule "external/argon2"]
+	path = external/argon2
+	url = https://github.com/netheril96/phc-winner-argon2
+	shallow = true
+
+[submodule "external/cryptopp"]
+	path = external/cryptopp
+	url = https://github.com/weidai11/cryptopp.git
+	shallow = true
+	ignore = untracked
diff -pruN 0.11.1+ds-4/LICENSE.md 0.13.1+ds-1/LICENSE.md
--- 0.11.1+ds-4/LICENSE.md	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/LICENSE.md	2023-01-27 02:25:50.000000000 +0000
@@ -758,13 +758,11 @@ Public License instead of this License.
 
 ------------------------------------------------------------------------------
 
-# [osxfuse] (https://github.com/osxfuse/osxfuse)
+# [macFUSE] (https://github.com/osxfuse/osxfuse)
 
-FUSE for macOS is a software developed by the osxfuse project and is covered
-under the following BSD-style license:
+macFUSE is covered under the following license:
 
-  Copyright (c) 2011-2016 Benjamin Fleischer
-  Copyright (c) 2011-2012 Erik Larsson
+  Copyright (c) 2011-2021 Benjamin Fleischer
   All rights reserved.
 
   Redistribution  and  use  in  source  and  binary  forms,  with   or   without
@@ -775,9 +773,13 @@ under the following BSD-style license:
   2. 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.
-  3. Neither the name of osxfuse nor the names of its contributors may  be  used
-     to endorse or promote products derived from this software without  specific
-     prior written permission.
+  3. Neither the name of the copyright holder nor the names of its  contributors
+     may be used to endorse or  promote  products  derived  from  this  software 
+     without specific prior written permission.
+  4. Redistributions in binary form, bundled with commercial software,  are  not
+     allowed without  specific  prior  written  permission.  This  includes  the
+     automated download or installation or  both  of  the  binary  form  in  the
+     context of commercial software.
 
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND  CONTRIBUTORS  "AS  IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT  NOT  LIMITED  TO,  THE
@@ -791,9 +793,9 @@ under the following BSD-style license:
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN  IF  ADVISED  OF  THE
   POSSIBILITY OF SUCH DAMAGE.
 
-FUSE for macOS is a fork of MacFUSE. MacFUSE has been developed by Google Inc..
-Additional information and the original source of MacFUSE are available on
-http://code.google.com/p/macfuse/. MacFUSE is covered under the following
+macFUSE is a fork of the legacy Google MacFUSE software. Additional information
+and the original source code of Google MacFUSE are available on
+http://code.google.com/p/macfuse/. Google MacFUSE is covered under the following
 BSD-style license:
 
   Copyright (c) 2007—2009 Google Inc.
@@ -830,9 +832,9 @@ BSD-style license:
 Portions of this package were derived from code developed by other authors.
 Please read further for specific details.
 
-* Unless otherwise noted, parts of the FUSE for macOS kernel extension contain
-  code derived from the FreeBSD version of FUSE, which is covered under the
-  following BSD-style license:
+* Unless otherwise noted, parts of the macFUSE kernel extension contain code
+  derived from the FreeBSD version of FUSE, which is covered under the following
+  BSD-style license:
 
     Copyright (C) 2005 Csaba Henk. All rights reserved.
 
@@ -856,12 +858,13 @@ Please read further for specific details
     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  OF  THE  USE  OF
     THIS  SOFTWARE,  EVEN  IF  ADVISED  OF  THE  POSSIBILITY  OF  SUCH   DAMAGE.
 
-* Parts of the FUSE for macOS kernel extension contain code derived from Tuxera
-  Inc.'s "rebel" branch. The original source of the "rebel" branch is available
-  on https://github.com/tuxera. These modifications are covered under the
-  following BSD-style license:
+* Parts of the macFUSE kernel extension contain code derived from Tuxera's
+  "rebel" branch. The original source code of the "rebel" branch is available on
+  https://github.com/tuxera. These modifications are covered under the following
+  BSD-style license:
 
     Copyright (c) 2010 Tuxera Inc.
+    Copyright (c) 2011-2012 Erik Larsson
     All rights reserved.
 
     Redistribution  and  use  in  source  and  binary  forms,  with  or  without
@@ -888,9 +891,9 @@ Please read further for specific details
     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  OF  THE
     POSSIBILITY OF SUCH DAMAGE.
 
-* Parts of FUSE for macOS contain code derived from Fuse4X. The original source
-  of Fuse4X is available on https://github.com/fuse4x. Fuse4X is covered under
-  the following BSD-style license:
+* Parts of macFUSE contain code derived from Fuse4X. The original source code of
+  Fuse4X is available on https://github.com/fuse4x. Fuse4X is covered under the
+  following BSD-style license:
 
     Copyright (c) 2011 Anatol Pomozov
     All rights reserved.
@@ -916,21 +919,20 @@ Please read further for specific details
     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  OF  THE
     POSSIBILITY OF SUCH DAMAGE.
 
-* Parts of the mount_osxfuse command-line program are covered under the Apple
+* Parts of the mount_macfuse command-line program are covered under the Apple
   Public Source License (APSL). You can read the APSL at:
 
     http://www.opensource.apple.com/license/apsl/
 
-* fuse_kernel.h is an unmodified copy of the interface header from the Linux
+* fuse_kernel.h is a modified copy of the interface header from the Linux
   FUSE distribution (https://github.com/libfuse/libfuse). fuse_kernel.h can be
   redistributed either under the GPL or under the BSD license. It is being
   redistributed here under the BSD license.
 
-* fuse_nodehash.c is a slightly modified version of HashNode.c from an
-  Apple Developer Technical Support (DTS) sample code example. The original
-  source, which is available on
-  http://developer.apple.com/library/mac/#samplecode/MFSLives/, has the
-  following disclaimer:
+* fuse_nodehash.c is a modified version of HashNode.c from an Apple Developer
+  Technical Support (DTS) sample code example. The original source, which is
+  available on http://developer.apple.com/library/mac/#samplecode/MFSLives/,
+  has the following disclaimer:
 
     Disclaimer: IMPORTANT: This Apple software  is  supplied  to  you  by  Apple
     Computer, Inc.  Apple") in consideration of your agreement to the  following
diff -pruN 0.11.1+ds-4/linux-build.sh 0.13.1+ds-1/linux-build.sh
--- 0.11.1+ds-4/linux-build.sh	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/linux-build.sh	2023-01-27 02:25:50.000000000 +0000
@@ -1,10 +1,12 @@
 #!/bin/bash
 set -x;
+set -e;
 SOURCE_DIR=$(dirname $(realpath "$0"));
 cd "${SOURCE_DIR}" && git submodule update --init;
 export TMPDIR=/dev/shm;
 cd $(mktemp -d -t securefs-build-XXXXX);
 cmake "${SOURCE_DIR}";
 make -j4;
+ctest;
 SECUREFS_BINARY_PATH=$(realpath ./securefs);
 echo "Please copy ${SECUREFS_BINARY_PATH} to anywhere in your \$PATH to use it";
diff -pruN 0.11.1+ds-4/README.md 0.13.1+ds-1/README.md
--- 0.11.1+ds-4/README.md	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/README.md	2023-01-27 02:25:50.000000000 +0000
@@ -16,41 +16,65 @@ Security, however, is often at odds with
 
 There are already many encrypting filesystem in widespread use. Some notable ones are TrueCrypt, FileVault, BitLocker, eCryptFS, encfs and gocryptfs. `securefs` differs from them in that it is the only one with all of the following features:
 
-* [Authenticated encryption](https://en.wikipedia.org/wiki/Authenticated_encryption) (hence secure against chosen ciphertext attacks)
-* [Probabilistic encryption](https://en.wikipedia.org/wiki/Probabilistic_encryption) (hence provides semantical security)
-* Supported on all major platforms (Mac, Linux, BSDs and Windows)
-* Efficient cloud synchronization (not a single preallocated file as container)
+- [Authenticated encryption](https://en.wikipedia.org/wiki/Authenticated_encryption) (hence secure against chosen ciphertext attacks)
+- [Probabilistic encryption](https://en.wikipedia.org/wiki/Probabilistic_encryption) (hence provides semantical security)
+- Supported on all major platforms (Mac, Linux, BSDs and Windows)
+- Efficient cloud synchronization (not a single preallocated file as container)
+- (Optional) File size obfuscation by random padding.
 
 ## Install
 
 [![Actions Status](https://github.com/netheril96/securefs/workflows/C%2FC%2B%2B%20CI/badge.svg)](https://github.com/netheril96/securefs/actions)
 
-
 ### macOS
 
-Install with [Homebrew](https://brew.sh). [osxfuse](https://osxfuse.github.io) has to be installed beforehand.
+Install with [Homebrew](https://brew.sh). [macFUSE](https://osxfuse.github.io) has to be installed beforehand.
+
 ```
-brew install securefs
+brew install netheril96/fuse/securefs
 ```
 
 ### Windows
 
 Windows users can download prebuilt package from the releases section. It depends on [WinFsp](https://github.com/billziss-gh/winfsp/releases) and [VC++ 2017 redistribution package](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads).
 
+On Windows, you should encrypt the pagefile to avoid leaking sensitive data on disk. Run with admin privileges with the command `fsutil behavior set EncryptPagingFile 1` before mounting a volume with `securefs`.
+
 ### Linux
 
 Linux users have to build it from source.
 
 First `fuse` must be installed.
 
-* On Debian based Linux distro, `sudo apt-get install fuse libfuse-dev build-essential cmake`.
-* On RPM based Linux, `sudo yum install fuse fuse-devel`.
+- On Debian based Linux distro, `sudo apt-get install fuse libfuse-dev build-essential cmake python3`.
+- On RPM based Linux, `sudo yum install fuse fuse-devel python3`.
 
 Then clone the sources by `git clone --recursive`, and execute `linux-build.sh`.
 
+### FreeBSD (unofficial)
+
+Install using packages (recommended):
+
+```bash
+pkg install fusefs-securefs
+```
+
+or ports:
+
+```bash
+make -C /usr/ports/sysutils/fusefs-securefs install
+```
+
+Make sure you load the fuse kernel module before using securefs:
+
+```bash
+kldload fuse
+sysrc -f /boot/loader.conf fuse_load="YES"  # Load fuse automatically at boot
+```
+
 ## Basic usage
 
-*It is recommended to disable or encrypt the swap and hibernation file. Otherwise plaintext and keys stored in the main memory may be written to disk by the OS at any time.*
+_It is recommended to disable or encrypt the swap and hibernation file. Otherwise plaintext and keys stored in the main memory may be written to disk by the OS at any time._
 
 Examples:
 
@@ -77,3 +101,9 @@ To request full format, which is no long
 ## Design and algorithms
 
 See [here](docs/design.md).
+
+## Caveat
+
+If you store `securefs` encrypted files on iCloud Drive, it might cause Spotlight Search on iOS to stop working. It is a bug in iOS, not in `securefs`.
+
+To work around that bug, you can disable the indexing of _Files_ app in Settings -> Siri & Suggestions.
diff -pruN 0.11.1+ds-4/securefs.manifest 0.13.1+ds-1/securefs.manifest
--- 0.11.1+ds-4/securefs.manifest	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/securefs.manifest	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+    <application xmlns="urn:schemas-microsoft-com:asm.v3">
+        <windowsSettings>
+            <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
+            <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
+        </windowsSettings>
+    </application>
+</assembly>
diff -pruN 0.11.1+ds-4/sources/btree_dir.h 0.13.1+ds-1/sources/btree_dir.h
--- 0.11.1+ds-4/sources/btree_dir.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/btree_dir.h	2023-01-27 02:25:50.000000000 +0000
@@ -113,7 +113,7 @@ public:
     void to_buffer(byte* buffer, size_t size) const;
 };
 
-class BtreeDirectory : public Directory
+class BtreeDirectory final : public Directory
 {
 private:
     typedef BtreeNode Node;
@@ -124,41 +124,52 @@ private:
     std::unordered_map<uint32_t, std::unique_ptr<Node>> m_node_cache;
 
 private:
-    bool read_node(uint32_t, Node&);
-    void read_free_page(uint32_t, FreePage&);
-    void write_node(uint32_t, const Node&);
-    void write_free_page(uint32_t, const FreePage&);
-    void deallocate_page(uint32_t);
-    uint32_t allocate_page();
-
-    Node* retrieve_node(uint32_t parent_num, uint32_t num);
-    Node* retrieve_existing_node(uint32_t num);
-    void del_node(Node*);
-    Node* get_root_node();
-    void flush_cache();
-    void clear_cache();
-    void adjust_children_in_cache(BtreeNode* n, uint32_t parent);
-    void adjust_children_in_cache(BtreeNode* n) { adjust_children_in_cache(n, n->page_number()); }
-    void rotate(BtreeNode* left, BtreeNode* right, Entry& separator);
-    void merge(BtreeNode* left, BtreeNode* right, BtreeNode* parent, ptrdiff_t entry_index);
-
-    std::tuple<Node*, ptrdiff_t, bool> find_node(const std::string& name);
-    std::pair<ptrdiff_t, BtreeNode*> find_sibling(const BtreeNode* parent, const BtreeNode* child);
-
-    void insert_and_balance(Node*, Entry, uint32_t additional_child, int depth);
-    Node* replace_with_sub_entry(Node*, ptrdiff_t index, int depth);
-    void balance_up(Node*, int depth);
+    bool read_node(uint32_t, Node&) THREAD_ANNOTATION_REQUIRES(*this);
+    void read_free_page(uint32_t, FreePage&) THREAD_ANNOTATION_REQUIRES(*this);
+    void write_node(uint32_t, const Node&) THREAD_ANNOTATION_REQUIRES(*this);
+    void write_free_page(uint32_t, const FreePage&) THREAD_ANNOTATION_REQUIRES(*this);
+    void deallocate_page(uint32_t) THREAD_ANNOTATION_REQUIRES(*this);
+    uint32_t allocate_page() THREAD_ANNOTATION_REQUIRES(*this);
+
+    Node* retrieve_node(uint32_t parent_num, uint32_t num) THREAD_ANNOTATION_REQUIRES(*this);
+    Node* retrieve_existing_node(uint32_t num) THREAD_ANNOTATION_REQUIRES(*this);
+    void del_node(Node*) THREAD_ANNOTATION_REQUIRES(*this);
+    Node* get_root_node() THREAD_ANNOTATION_REQUIRES(*this);
+    void flush_cache() THREAD_ANNOTATION_REQUIRES(*this);
+    void clear_cache() THREAD_ANNOTATION_REQUIRES(*this);
+    void adjust_children_in_cache(BtreeNode* n, uint32_t parent) THREAD_ANNOTATION_REQUIRES(*this);
+    void adjust_children_in_cache(BtreeNode* n) THREAD_ANNOTATION_REQUIRES(*this)
+    {
+        adjust_children_in_cache(n, n->page_number());
+    }
+    void rotate(BtreeNode* left, BtreeNode* right, Entry& separator)
+        THREAD_ANNOTATION_REQUIRES(*this);
+    void merge(BtreeNode* left, BtreeNode* right, BtreeNode* parent, ptrdiff_t entry_index)
+        THREAD_ANNOTATION_REQUIRES(*this);
+
+    std::tuple<Node*, ptrdiff_t, bool> find_node(const std::string& name)
+        THREAD_ANNOTATION_REQUIRES(*this);
+    std::pair<ptrdiff_t, BtreeNode*> find_sibling(const BtreeNode* parent, const BtreeNode* child)
+        THREAD_ANNOTATION_REQUIRES(*this);
+
+    void insert_and_balance(Node*, Entry, uint32_t additional_child, int depth)
+        THREAD_ANNOTATION_REQUIRES(*this);
+    Node* replace_with_sub_entry(Node*, ptrdiff_t index, int depth)
+        THREAD_ANNOTATION_REQUIRES(*this);
+    void balance_up(Node*, int depth) THREAD_ANNOTATION_REQUIRES(*this);
 
-    bool validate_node(const Node* n, int depth);
-    void write_dot_graph(const Node*, FILE*);
+    bool validate_node(const Node* n, int depth) THREAD_ANNOTATION_REQUIRES(*this);
+    void write_dot_graph(const Node*, FILE*) THREAD_ANNOTATION_REQUIRES(*this);
 
     template <class Callback>
-    void recursive_iterate(const Node* n, const Callback& cb, int depth);
+    void recursive_iterate(const Node* n, const Callback& cb, int depth)
+        THREAD_ANNOTATION_REQUIRES(*this);
     template <class Callback>
-    void mutable_recursive_iterate(Node* n, const Callback& cb, int depth);
+    void mutable_recursive_iterate(Node* n, const Callback& cb, int depth)
+        THREAD_ANNOTATION_REQUIRES(*this);
 
 protected:
-    void subflush() override;
+    void subflush() override THREAD_ANNOTATION_REQUIRES(*this);
 
 public:
     template <class... Args>
@@ -168,19 +179,22 @@ public:
     ~BtreeDirectory() override;
 
 protected:
-    bool get_entry_impl(const std::string& name, id_type& id, int& type) override;
-    bool add_entry_impl(const std::string& name, const id_type& id, int type) override;
-    bool remove_entry_impl(const std::string& name, id_type& id, int& type) override;
-    void iterate_over_entries_impl(const callback&) override;
+    bool get_entry_impl(const std::string& name, id_type& id, int& type) override
+        THREAD_ANNOTATION_REQUIRES(*this);
+    bool add_entry_impl(const std::string& name, const id_type& id, int type) override
+        THREAD_ANNOTATION_REQUIRES(*this);
+    bool remove_entry_impl(const std::string& name, id_type& id, int& type) override
+        THREAD_ANNOTATION_REQUIRES(*this);
+    void iterate_over_entries_impl(const callback&) override THREAD_ANNOTATION_REQUIRES(*this);
 
 public:
-    virtual bool empty() override;
-    void rebuild();
+    virtual bool empty() override THREAD_ANNOTATION_REQUIRES(*this);
+    void rebuild() THREAD_ANNOTATION_REQUIRES(*this);
 
 public:
-    bool validate_free_list();
-    bool validate_btree_structure();
-    void to_dot_graph(const char* filename);
+    bool validate_free_list() THREAD_ANNOTATION_REQUIRES(*this);
+    bool validate_btree_structure() THREAD_ANNOTATION_REQUIRES(*this);
+    void to_dot_graph(const char* filename) THREAD_ANNOTATION_REQUIRES(*this);
 };
 
 template <class... Args>
diff -pruN 0.11.1+ds-4/sources/commands.cpp 0.13.1+ds-1/sources/commands.cpp
--- 0.11.1+ds-4/sources/commands.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/commands.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -6,10 +6,13 @@
 #include "myutils.h"
 #include "operations.h"
 #include "platform.h"
+#include "win_get_proc.h"
 
+#include <argon2.h>
 #include <cryptopp/cpu.h>
 #include <cryptopp/hmac.h>
 #include <cryptopp/osrng.h>
+#include <cryptopp/scrypt.h>
 #include <cryptopp/secblock.h>
 #include <fuse.h>
 #include <json/json.h>
@@ -17,15 +20,18 @@
 #include <utf8proc/utf8proc.h>
 
 #include <algorithm>
+#include <iostream>
 #include <memory>
 #include <stdexcept>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <thread>
 #include <typeinfo>
 #include <unordered_map>
 #include <vector>
 
-#ifdef _MSC_VER
+#ifdef _WIN32
 #include <Windows.h>
 #else
 #include <dlfcn.h>
@@ -40,8 +46,11 @@ const char* const CONFIG_FILE_NAME = ".s
 const unsigned MIN_ITERATIONS = 20000;
 const unsigned MIN_DERIVE_SECONDS = 1;
 const size_t CONFIG_IV_LENGTH = 32, CONFIG_MAC_LENGTH = 16;
+
 const char* const PBKDF_ALGO_PKCS5 = "pkcs5-pbkdf2-hmac-sha256";
 const char* const PBKDF_ALGO_SCRYPT = "scrypt";
+const char* const PBKDF_ALGO_ARGON2ID = "argon2id";
+
 const char* const EMPTY_PASSWORD_WHEN_KEY_FILE_IS_USED = " ";
 
 const char* get_version_header(unsigned version)
@@ -79,10 +88,15 @@ void fix_hardlink_count(operations::File
                         NLinkFixPhase phase)
 {
     std::vector<std::pair<id_type, int>> listings;
-    dir->iterate_over_entries([&listings](const std::string&, const id_type& id, int type) {
-        listings.emplace_back(id, type);
-        return true;
-    });
+    {
+        FileLockGuard file_lock_guard(*dir);
+        dir->iterate_over_entries(
+            [&listings](const std::string&, const id_type& id, int type)
+            {
+                listings.emplace_back(id, type);
+                return true;
+            });
+    }
 
     for (auto&& entry : listings)
     {
@@ -101,8 +115,12 @@ void fix_hardlink_count(operations::File
         switch (phase)
         {
         case NLinkFixPhase::FixingNLink:
-            base->set_nlink(nlink_map->at(id));
-            break;
+        {
+            auto& fp = *base;
+            FileLockGuard file_lock_guard(fp);
+            fp.set_nlink(nlink_map->at(id));
+        }
+        break;
 
         case NLinkFixPhase::CollectingNLink:
             nlink_map->operator[](id)++;
@@ -126,10 +144,15 @@ void fix_helper(operations::FileSystemCo
                 std::unordered_set<id_type, id_hash>* all_ids)
 {
     std::vector<std::tuple<std::string, id_type, int>> listings;
-    dir->iterate_over_entries([&listings](const std::string& name, const id_type& id, int type) {
-        listings.emplace_back(name, id, type);
-        return true;
-    });
+    {
+        FileLockGuard file_lock_guard(*dir);
+        dir->iterate_over_entries(
+            [&listings](const std::string& name, const id_type& id, int type)
+            {
+                listings.emplace_back(name, id, type);
+                return true;
+            });
+    }
 
     for (auto&& entry : listings)
     {
@@ -149,7 +172,11 @@ void fix_helper(operations::FileSystemCo
                     "(Yes/No, default: no)\n",
                     (dir_name + '/' + name).c_str(),
                     e.what());
-            auto remove = [&]() { dir->remove_entry(name, id, type); };
+            auto remove = [&]()
+            {
+                FileLockGuard file_lock_guard(*dir);
+                dir->remove_entry(name, id, type);
+            };
             auto ignore = []() {};
             respond_to_user_action({{"\n", ignore},
                                     {"y\n", remove},
@@ -169,7 +196,9 @@ void fix_helper(operations::FileSystemCo
                    FileBase::type_name(type));
             fflush(stdout);
 
-            auto fix_type = [&]() {
+            auto fix_type = [&]()
+            {
+                FileLockGuard file_lock_guard(*dir);
                 dir->remove_entry(name, id, type);
                 dir->add_entry(name, id, real_type);
             };
@@ -211,17 +240,23 @@ void fix(const std::string& basedir, ope
                    hexify(id).c_str());
             fflush(stdout);
 
-            auto recover = [&]() {
+            auto recover = [&]()
+            {
                 auto base = open_as(fs->table, id, FileBase::BASE);
-                root_dir.get_as<Directory>()->add_entry(hexify(id), id, base->get_real_type());
+                auto& root_dir_fp = *root_dir;
+                FileLockGuard file_lock_guard(root_dir_fp);
+                root_dir_fp.cast_as<Directory>()->add_entry(hexify(id), id, base->get_real_type());
             };
 
-            auto remove = [&]() {
+            auto remove = [&]()
+            {
                 FileBase* base = fs->table.open_as(id, FileBase::BASE);
                 int real_type = base->get_real_type();
                 fs->table.close(base);
                 auto real_file_handle = open_as(fs->table, id, real_type);
-                real_file_handle->unlink();
+                auto& fp = *real_file_handle;
+                FileLockGuard file_lock_guard(fp);
+                fp.unlink();
             };
 
             auto ignore = []() {};
@@ -244,18 +279,18 @@ void fix(const std::string& basedir, ope
     puts("Fix complete");
 }
 
-void maybe_derive_with_keyfile(const securefs::key_type& password_dervied_key,
-                               StringRef maybe_key_file_path,
-                               securefs::key_type& out_key)
+void hmac_sha256(const securefs::key_type& base_key,
+                 StringRef maybe_key_file_path,
+                 securefs::key_type& out_key)
 {
     if (maybe_key_file_path.empty())
     {
-        out_key = password_dervied_key;
+        out_key = base_key;
         return;
     }
     auto file_stream = OSService::get_default().open_file_stream(maybe_key_file_path, O_RDONLY, 0);
     byte buffer[4096];
-    CryptoPP::HMAC<CryptoPP::SHA256> hmac(password_dervied_key.data(), password_dervied_key.size());
+    CryptoPP::HMAC<CryptoPP::SHA256> hmac(base_key.data(), base_key.size());
     while (true)
     {
         auto sz = file_stream->sequential_read(buffer, sizeof(buffer));
@@ -277,57 +312,83 @@ Json::Value generate_config(unsigned int
                             size_t pass_len,
                             unsigned block_size,
                             unsigned iv_size,
-                            unsigned rounds = 0)
+                            unsigned max_padding,
+                            unsigned rounds)
 {
+    securefs::key_type effective_salt;
+    hmac_sha256(salt, maybe_key_file_path, effective_salt);
+
     Json::Value config;
     config["version"] = version;
-    securefs::key_type password_derived_key;
+    key_type password_derived_key;
     CryptoPP::AlignedSecByteBlock encrypted_master_key(nullptr, master_key.size());
 
     if (pbkdf_algorithm == PBKDF_ALGO_PKCS5)
     {
-        config["iterations"] = securefs::pbkdf_hmac_sha256(password,
-                                                           pass_len,
-                                                           salt.data(),
-                                                           salt.size(),
-                                                           rounds ? rounds : MIN_ITERATIONS,
-                                                           rounds ? 0 : MIN_DERIVE_SECONDS,
-                                                           password_derived_key.data(),
-                                                           password_derived_key.size());
+        config["iterations"] = pbkdf_hmac_sha256(password,
+                                                 pass_len,
+                                                 effective_salt.data(),
+                                                 effective_salt.size(),
+                                                 rounds ? rounds : MIN_ITERATIONS,
+                                                 rounds ? 0 : MIN_DERIVE_SECONDS,
+                                                 password_derived_key.data(),
+                                                 password_derived_key.size());
     }
     else if (pbkdf_algorithm == PBKDF_ALGO_SCRYPT)
     {
-        uint32_t N = rounds > 0 ? rounds : (1u << 18u), r = 8, p = 1;
-        config["iterations"] = N;
+        uint32_t n = rounds > 0 ? rounds : (1u << 18u), r = 8, p = 1;
+        config["iterations"] = n;
         config["scrypt_r"] = r;
         config["scrypt_p"] = p;
-        securefs::libscrypt_scrypt(static_cast<const byte*>(password),
-                                   pass_len,
-                                   salt.data(),
-                                   salt.size(),
-                                   N,
-                                   r,
+        CryptoPP::Scrypt scrypt;
+        scrypt.DeriveKey(password_derived_key.data(),
+                         password_derived_key.size(),
+                         static_cast<const byte*>(password),
+                         pass_len,
+                         effective_salt.data(),
+                         effective_salt.size(),
+                         n,
+                         r,
+                         p);
+    }
+    else if (pbkdf_algorithm == PBKDF_ALGO_ARGON2ID)
+    {
+        const char* env_m_cost = getenv("SECUREFS_ARGON2_M_COST");
+        const char* env_p = getenv("SECUREFS_ARGON2_P");
+        uint32_t t_cost = rounds > 0 ? rounds : 9,
+                 m_cost = env_m_cost ? std::stoi(env_m_cost) : (1u << 18u),
+                 p = env_p ? std::stoi(env_p) : 4;
+        config["iterations"] = t_cost;
+        config["argon2_m_cost"] = m_cost;
+        config["argon2_p"] = p;
+        int rc = argon2id_hash_raw(t_cost,
+                                   m_cost,
                                    p,
+                                   password,
+                                   pass_len,
+                                   effective_salt.data(),
+                                   effective_salt.size(),
                                    password_derived_key.data(),
                                    password_derived_key.size());
+        if (rc)
+        {
+            throw_runtime_error("Argon2 hashing failed with status code " + std::to_string(rc));
+        }
     }
     else
     {
         throw_runtime_error("Unknown pbkdf algorithm " + pbkdf_algorithm);
     }
     config["pbkdf"] = pbkdf_algorithm;
-
-    config["salt"] = securefs::hexify(salt);
+    config["salt"] = hexify(salt);
 
     byte iv[CONFIG_IV_LENGTH];
     byte mac[CONFIG_MAC_LENGTH];
     generate_random(iv, array_length(iv));
 
-    securefs::key_type wrapping_key;
-    maybe_derive_with_keyfile(password_derived_key, maybe_key_file_path, wrapping_key);
-
     CryptoPP::GCM<CryptoPP::AES>::Encryption encryptor;
-    encryptor.SetKeyWithIV(wrapping_key.data(), wrapping_key.size(), iv, array_length(iv));
+    encryptor.SetKeyWithIV(
+        password_derived_key.data(), password_derived_key.size(), iv, array_length(iv));
     encryptor.EncryptAndAuthenticate(encrypted_master_key.data(),
                                      mac,
                                      array_length(mac),
@@ -339,9 +400,9 @@ Json::Value generate_config(unsigned int
                                      master_key.size());
 
     Json::Value encrypted_key;
-    encrypted_key["IV"] = securefs::hexify(iv, array_length(iv));
-    encrypted_key["MAC"] = securefs::hexify(mac, array_length(mac));
-    encrypted_key["key"] = securefs::hexify(encrypted_master_key);
+    encrypted_key["IV"] = hexify(iv, array_length(iv));
+    encrypted_key["MAC"] = hexify(mac, array_length(mac));
+    encrypted_key["key"] = hexify(encrypted_master_key);
 
     config["encrypted_key"] = std::move(encrypted_key);
 
@@ -350,19 +411,85 @@ Json::Value generate_config(unsigned int
         config["block_size"] = block_size;
         config["iv_size"] = iv_size;
     }
+    if (max_padding > 0)
+    {
+        config["max_padding"] = max_padding;
+    }
     return config;
 }
 
+void compute_password_derived_key(const Json::Value& config,
+                                  const void* password,
+                                  size_t pass_len,
+                                  key_type& salt,
+                                  key_type& password_derived_key)
+{
+    unsigned iterations = config["iterations"].asUInt();
+    std::string pbkdf_algorithm = config.get("pbkdf", PBKDF_ALGO_PKCS5).asString();
+    VERBOSE_LOG("Setting the password key derivation function to %s", pbkdf_algorithm.c_str());
+
+    if (pbkdf_algorithm == PBKDF_ALGO_PKCS5)
+    {
+        pbkdf_hmac_sha256(password,
+                          pass_len,
+                          salt.data(),
+                          salt.size(),
+                          iterations,
+                          0,
+                          password_derived_key.data(),
+                          password_derived_key.size());
+    }
+    else if (pbkdf_algorithm == PBKDF_ALGO_SCRYPT)
+    {
+        auto r = config["scrypt_r"].asUInt();
+        auto p = config["scrypt_p"].asUInt();
+        CryptoPP::Scrypt scrypt;
+        scrypt.DeriveKey(password_derived_key.data(),
+                         password_derived_key.size(),
+                         static_cast<const byte*>(password),
+                         pass_len,
+                         salt.data(),
+                         salt.size(),
+                         iterations,
+                         r,
+                         p);
+    }
+    else if (pbkdf_algorithm == PBKDF_ALGO_ARGON2ID)
+    {
+        auto m_cost = config["argon2_m_cost"].asUInt();
+        auto p = config["argon2_p"].asUInt();
+        int rc = argon2id_hash_raw(iterations,
+                                   m_cost,
+                                   p,
+                                   password,
+                                   pass_len,
+                                   salt.data(),
+                                   salt.size(),
+                                   password_derived_key.data(),
+                                   password_derived_key.size());
+        if (rc)
+        {
+            throw_runtime_error("Argon2 hashing failed with status code " + std::to_string(rc));
+        }
+    }
+    else
+    {
+        throw_runtime_error("Unknown pbkdf algorithm " + pbkdf_algorithm);
+    }
+}
+
 bool parse_config(const Json::Value& config,
                   StringRef maybe_key_file_path,
                   const void* password,
                   size_t pass_len,
                   CryptoPP::AlignedSecByteBlock& master_key,
                   unsigned& block_size,
-                  unsigned& iv_size)
+                  unsigned& iv_size,
+                  unsigned& max_padding)
 {
     using namespace securefs;
     unsigned version = config["version"].asUInt();
+    max_padding = config.get("max_padding", 0u).asUInt();
 
     if (version == 1)
     {
@@ -379,11 +506,9 @@ bool parse_config(const Json::Value& con
         throwInvalidArgumentException(strprintf("Unsupported version %u", version));
     }
 
-    unsigned iterations = config["iterations"].asUInt();
-
     byte iv[CONFIG_IV_LENGTH];
     byte mac[CONFIG_MAC_LENGTH];
-    key_type salt, password_derived_key;
+    key_type salt;
     CryptoPP::AlignedSecByteBlock encrypted_key;
 
     std::string salt_hex = config["salt"].asString();
@@ -400,52 +525,42 @@ bool parse_config(const Json::Value& con
     parse_hex(ekey_hex, encrypted_key.data(), encrypted_key.size());
     master_key.resize(encrypted_key.size());
 
-    std::string pbkdf_algorithm = config.get("pbkdf", PBKDF_ALGO_PKCS5).asString();
-    VERBOSE_LOG("Setting the password key derivation function to %s", pbkdf_algorithm.c_str());
-
-    if (pbkdf_algorithm == PBKDF_ALGO_PKCS5)
+    auto decrypt_and_verify = [&](const securefs::key_type& wrapping_key)
     {
-        pbkdf_hmac_sha256(password,
-                          pass_len,
-                          salt.data(),
-                          salt.size(),
-                          iterations,
-                          0,
-                          password_derived_key.data(),
-                          password_derived_key.size());
-    }
-    else if (pbkdf_algorithm == PBKDF_ALGO_SCRYPT)
+        CryptoPP::GCM<CryptoPP::AES>::Decryption decryptor;
+        decryptor.SetKeyWithIV(wrapping_key.data(), wrapping_key.size(), iv, array_length(iv));
+        return decryptor.DecryptAndVerify(
+            master_key.data(),
+            mac,
+            array_length(mac),
+            iv,
+            array_length(iv),
+            reinterpret_cast<const byte*>(get_version_header(version)),
+            strlen(get_version_header(version)),
+            encrypted_key.data(),
+            encrypted_key.size());
+    };
+
     {
-        auto r = config["scrypt_r"].asUInt();
-        auto p = config["scrypt_p"].asUInt();
-        libscrypt_scrypt(static_cast<const byte*>(password),
-                         pass_len,
-                         salt.data(),
-                         salt.size(),
-                         iterations,
-                         r,
-                         p,
-                         password_derived_key.data(),
-                         password_derived_key.size());
+        securefs::key_type new_salt;
+        hmac_sha256(salt, maybe_key_file_path, new_salt);
+
+        securefs::key_type password_derived_key;
+        compute_password_derived_key(config, password, pass_len, new_salt, password_derived_key);
+        if (decrypt_and_verify(password_derived_key))
+        {
+            return true;
+        }
     }
-    else
+
+    // `securefs` used to derive keyfile based key in another way. Try it here for compatibility.
     {
-        throw_runtime_error("Unknown pbkdf algorithm " + pbkdf_algorithm);
+        securefs::key_type wrapping_key;
+        securefs::key_type password_derived_key;
+        compute_password_derived_key(config, password, pass_len, salt, password_derived_key);
+        hmac_sha256(password_derived_key, maybe_key_file_path, wrapping_key);
+        return decrypt_and_verify(wrapping_key);
     }
-
-    securefs::key_type wrapping_key;
-    maybe_derive_with_keyfile(password_derived_key, maybe_key_file_path, wrapping_key);
-    CryptoPP::GCM<CryptoPP::AES>::Decryption decryptor;
-    decryptor.SetKeyWithIV(wrapping_key.data(), wrapping_key.size(), iv, array_length(iv));
-    return decryptor.DecryptAndVerify(master_key.data(),
-                                      mac,
-                                      array_length(mac),
-                                      iv,
-                                      array_length(iv),
-                                      reinterpret_cast<const byte*>(get_version_header(version)),
-                                      strlen(get_version_header(version)),
-                                      encrypted_key.data(),
-                                      encrypted_key.size());
 }
 }    // namespace
 
@@ -487,8 +602,9 @@ FSConfig CommandBase::read_config(FileSt
                       pass_len,
                       result.master_key,
                       result.block_size,
-                      result.iv_size))
-        throw_runtime_error("Invalid password");
+                      result.iv_size,
+                      result.max_padding))
+        throw_runtime_error("Invalid password and/or keyfile");
     result.version = value["version"].asUInt();
     return result;
 }
@@ -525,6 +641,7 @@ void CommandBase::write_config(FileStrea
                                pass_len,
                                config.block_size,
                                config.iv_size,
+                               config.max_padding,
                                rounds)
                    .toStyledString();
     stream->sequential_write(str.data(), str.size());
@@ -613,7 +730,7 @@ protected:
 static const std::string message_for_setting_pbkdf
     = strprintf("The algorithm to stretch passwords. Use %s for maximum protection (default), or "
                 "%s for compatibility with old versions of securefs",
-                PBKDF_ALGO_SCRYPT,
+                PBKDF_ALGO_ARGON2ID,
                 PBKDF_ALGO_PKCS5);
 
 class CreateCommand : public _SinglePasswordCommandBase
@@ -637,7 +754,16 @@ private:
         "store_time",
         "alias for \"--format 3\", enables the extension where timestamp are stored and encrypted"};
     TCLAP::ValueArg<std::string> pbkdf{
-        "", "pbkdf", message_for_setting_pbkdf, false, PBKDF_ALGO_SCRYPT, "string"};
+        "", "pbkdf", message_for_setting_pbkdf, false, PBKDF_ALGO_ARGON2ID, "string"};
+    TCLAP::ValueArg<unsigned> max_padding{
+        "",
+        "max-padding",
+        "Maximum number of padding (the unit is byte) to add to all files in order to obfuscate "
+        "their sizes. Each "
+        "file has a different padding. Enabling this has a large performance cost.",
+        false,
+        0,
+        "int"};
 
 public:
     void parse_cmdline(int argc, const char* const* argv) override
@@ -649,6 +775,8 @@ public:
         cmdline.add(&format);
         cmdline.add(&store_time);
         cmdline.add(&block_size);
+        cmdline.add(&pbkdf);
+        cmdline.add(&max_padding);
         cmdline.parse(argc, argv);
         get_password(true);
     }
@@ -663,7 +791,8 @@ public:
 
         if (format.isSet() && format.getValue() == 1 && (iv_size.isSet() || block_size.isSet()))
         {
-            fprintf(stderr, "IV and block size options are not available for filesystem format 1");
+            fprintf(stderr,
+                    "IV and block size options are not available for filesystem format 1\n");
             return 1;
         }
 
@@ -672,12 +801,13 @@ public:
         OSService::get_default().ensure_directory(data_dir.getValue(), 0755);
 
         FSConfig config;
-        config.master_key.resize(format_version < 4 ? KEY_LENGTH : 3 * KEY_LENGTH);
+        config.master_key.resize(format_version < 4 ? KEY_LENGTH : 4 * KEY_LENGTH);
         CryptoPP::OS_GenerateRandomBlock(false, config.master_key.data(), config.master_key.size());
 
         config.iv_size = format_version == 1 ? 32 : iv_size.getValue();
         config.version = format_version;
         config.block_size = block_size.getValue();
+        config.max_padding = max_padding.getValue();
 
         auto config_stream
             = open_config_stream(get_real_config_path(), O_WRONLY | O_CREAT | O_EXCL);
@@ -705,11 +835,13 @@ public:
 
             operations::FileSystemContext fs(opt);
             auto root = fs.table.create_as(fs.root_id, FileBase::DIRECTORY);
-            root->set_uid(securefs::OSService::getuid());
-            root->set_gid(securefs::OSService::getgid());
-            root->set_mode(S_IFDIR | 0755);
-            root->set_nlink(1);
-            root->flush();
+            auto& root_fp = *root;
+            FileLockGuard file_lock_guard(root_fp);
+            root_fp.set_uid(securefs::OSService::getuid());
+            root_fp.set_gid(securefs::OSService::getgid());
+            root_fp.set_mode(S_IFDIR | 0755);
+            root_fp.set_nlink(1);
+            root_fp.flush();
         }
         return 0;
     }
@@ -733,7 +865,7 @@ private:
         0,
         "integer"};
     TCLAP::ValueArg<std::string> pbkdf{
-        "", "pbkdf", message_for_setting_pbkdf, false, PBKDF_ALGO_SCRYPT, "string"};
+        "", "pbkdf", message_for_setting_pbkdf, false, PBKDF_ALGO_ARGON2ID, "string"};
     TCLAP::ValueArg<std::string> old_key_file{
         "", "oldkeyfile", "Path to original key file", false, "", "path"};
     TCLAP::ValueArg<std::string> new_key_file{
@@ -750,6 +882,25 @@ private:
         "When set to true, ask for password even if a key file is used. "
         "password+keyfile provides even stronger security than one of them alone.",
         false};
+    TCLAP::ValueArg<std::string> oldpass{
+        "",
+        "oldpass",
+        "The old password (prefer manually typing or piping since those methods are more secure)",
+        false,
+        "",
+        "string"};
+    TCLAP::ValueArg<std::string> newpass{
+        "",
+        "newpass",
+        "The new password (prefer manually typing or piping since those methods are more secure)",
+        false,
+        "",
+        "string"};
+
+    static void assign(StringRef value, CryptoPP::AlignedSecByteBlock& output)
+    {
+        output.Assign(reinterpret_cast<const byte*>(value.data()), value.size());
+    }
 
 public:
     void parse_cmdline(int argc, const char* const* argv) override
@@ -762,24 +913,34 @@ public:
         cmdline.add(&new_key_file);
         cmdline.add(&askoldpass);
         cmdline.add(&asknewpass);
+        cmdline.add(&oldpass);
+        cmdline.add(&newpass);
+        cmdline.add(&pbkdf);
         cmdline.parse(argc, argv);
-        if (old_key_file.getValue().empty() || askoldpass.getValue())
+        if (oldpass.isSet())
+        {
+            assign(oldpass.getValue(), old_password);
+        }
+        else if (old_key_file.getValue().empty() || askoldpass.getValue())
         {
             OSService::read_password_no_confirmation("Old password: ", &old_password);
         }
         else
         {
-            old_password.Assign(reinterpret_cast<const byte*>(EMPTY_PASSWORD_WHEN_KEY_FILE_IS_USED),
-                                strlen(EMPTY_PASSWORD_WHEN_KEY_FILE_IS_USED));
+            assign(EMPTY_PASSWORD_WHEN_KEY_FILE_IS_USED, old_password);
         }
-        if (new_key_file.getValue().empty() || asknewpass.getValue())
+
+        if (newpass.isSet())
+        {
+            assign(newpass.getValue(), new_password);
+        }
+        else if (new_key_file.getValue().empty() || asknewpass.getValue())
         {
             OSService::read_password_with_confirmation("New password: ", &new_password);
         }
         else
         {
-            new_password.Assign(reinterpret_cast<const byte*>(EMPTY_PASSWORD_WHEN_KEY_FILE_IS_USED),
-                                strlen(EMPTY_PASSWORD_WHEN_KEY_FILE_IS_USED));
+            assign(EMPTY_PASSWORD_WHEN_KEY_FILE_IS_USED, new_password);
         }
     }
 
@@ -794,7 +955,9 @@ public:
             stream.get(), old_password.data(), old_password.size(), old_key_file.getValue());
         stream = OSService::get_default().open_file_stream(
             tmp_path, O_WRONLY | O_CREAT | O_EXCL, 0644);
-        DEFER(if (std::uncaught_exception()) { OSService::get_default().remove_file(tmp_path); });
+        DEFER(if (std::uncaught_exception()) {
+            OSService::get_default().remove_file_nothrow(tmp_path);
+        });
         write_config(stream.get(),
                      new_key_file.getValue(),
                      pbkdf.getValue(),
@@ -859,14 +1022,52 @@ private:
                                                "none",
 #endif
                                                ""};
+    TCLAP::ValueArg<int> attr_timeout{"",
+                                      "attr-timeout",
+                                      "Number of seconds to cache file attributes. Default is 30.",
+                                      false,
+                                      30,
+                                      "int"};
+    TCLAP::SwitchArg skip_dot_dot{"",
+                                  "skip-dot-dot",
+                                  "When enabled, securefs will not return . and .. in `readdir` "
+                                  "calls. You should normally not need this.",
+                                  false};
 
 private:
     std::vector<const char*> to_c_style_args(const std::vector<std::string>& args)
     {
         std::vector<const char*> result(args.size());
-        std::transform(args.begin(), args.end(), result.begin(), [](const std::string& s) {
-            return s.c_str();
-        });
+        std::transform(args.begin(),
+                       args.end(),
+                       result.begin(),
+                       [](const std::string& s) { return s.c_str(); });
+        return result;
+    }
+#ifdef WIN32
+    static bool is_letter(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
+    static bool is_drive_mount(StringRef mount_point)
+    {
+        return mount_point.size() == 2 && is_letter(mount_point[0]) && mount_point[1] == ':';
+    }
+    static bool is_network_mount(StringRef mount_point)
+    {
+        return mount_point.starts_with("\\\\") && !mount_point.starts_with("\\\\?\\");
+    }
+#endif
+
+    static std::string escape_args(const std::vector<std::string>& args)
+    {
+        std::string result;
+        for (const auto& a : args)
+        {
+            result.append(securefs::escape_nonprintable(a.data(), a.size()));
+            result.push_back(' ');
+        }
+        if (!result.empty())
+        {
+            result.pop_back();
+        }
         return result;
     }
 
@@ -891,6 +1092,8 @@ public:
         cmdline.add(&fsname);
         cmdline.add(&fssubtype);
         cmdline.add(&noflock);
+        cmdline.add(&attr_timeout);
+        cmdline.add(&skip_dot_dot);
         cmdline.parse(argc, argv);
 
         get_password(false);
@@ -937,13 +1140,7 @@ public:
         }
 
 #ifdef WIN32
-        auto is_letter = [](char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); };
-        if (mount_point.getValue().size() != 2 || mount_point.getValue()[1] != ':'
-            || !is_letter(mount_point.getValue().front()))
-        {
-            WARN_LOG("The mount point on Windows should be a drive path, such as Z:, or some "
-                     "programs will get confused due to case sensitivity");
-        }
+        bool network_mount = is_network_mount(mount_point.getValue());
 #else
         try
         {
@@ -1004,14 +1201,39 @@ public:
                      e.what());
         }
 
-        std::vector<std::string> fuse_args;
-        fuse_args.push_back("securefs");
-        if (config.version < 4 || single_threaded.getValue())
+        std::vector<std::string> fuse_args{
+            "securefs",
+            "-o",
+            "hard_remove",
+            "-o",
+            "fsname=" + fsname.getValue(),
+            "-o",
+            "subtype=" + fssubtype.getValue(),
+            "-o",
+            strprintf("entry_timeout=%d", attr_timeout.getValue()),
+            "-o",
+            strprintf("attr_timeout=%d", attr_timeout.getValue()),
+            "-o",
+            strprintf("negative_timeout=%d", attr_timeout.getValue()),
+#ifndef _WIN32
+            "-o",
+            "atomic_o_trunc",
+#endif
+        };
+        if (single_threaded.getValue())
+        {
+            fuse_args.emplace_back("-s");
+        }
+        else
         {
-            fuse_args.push_back("-s");
+#ifdef _WIN32
+            fuse_args.emplace_back("-o");
+            fuse_args.emplace_back(
+                strprintf("ThreadCount=%d", 2 * std::thread::hardware_concurrency()));
+#endif
         }
         if (!background.getValue())
-            fuse_args.push_back("-f");
+            fuse_args.emplace_back("-f");
 
 #ifdef __APPLE__
         const char* copyfile_disable = ::getenv("COPYFILE_DISABLE");
@@ -1021,29 +1243,40 @@ public:
                         "environmental "
                         "variable COPYFILE_DISABLE is set to \"%s\"",
                         copyfile_disable);
-            fuse_args.push_back("-o");
-            fuse_args.push_back("noappledouble");
+            fuse_args.emplace_back("-o");
+            fuse_args.emplace_back("noappledouble");
         }
 #elif _WIN32
-        fuse_args.push_back("-ouid=-1,gid=-1");
+        fuse_args.emplace_back("-ouid=-1,gid=-1,umask=0");
+        if (network_mount)
+        {
+            fuse_args.emplace_back("--VolumePrefix=" + mount_point.getValue().substr(1));
+        }
+        fuse_args.emplace_back("-o");
+        fuse_args.emplace_back(strprintf("FileInfoTimeout=%d", attr_timeout.getValue() * 1000));
+        fuse_args.emplace_back("-o");
+        fuse_args.emplace_back(strprintf("DirInfoTimeout=%d", attr_timeout.getValue() * 1000));
+        fuse_args.emplace_back("-o");
+        fuse_args.emplace_back(strprintf("EaTimeout=%d", attr_timeout.getValue() * 1000));
+        fuse_args.emplace_back("-o");
+        fuse_args.emplace_back(strprintf("VolumeInfoTimeout=%d", attr_timeout.getValue() * 1000));
 #else
-        fuse_args.push_back("-o");
-        fuse_args.push_back("big_writes");
+        fuse_args.emplace_back("-o");
+        fuse_args.emplace_back("big_writes");
 #endif
-        fuse_args.push_back("-o");
-        fuse_args.push_back("fsname=" + fsname.getValue());
-        fuse_args.push_back("-o");
-        fuse_args.push_back("subtype=" + fssubtype.getValue());
         if (fuse_options.isSet())
         {
             for (const std::string& opt : fuse_options.getValue())
             {
-                fuse_args.push_back("-o");
-                fuse_args.push_back(opt);
+                fuse_args.emplace_back("-o");
+                fuse_args.emplace_back(opt);
             }
         }
 
-        fuse_args.push_back(mount_point.getValue().c_str());
+#ifdef WIN32
+        if (!network_mount)
+#endif
+            fuse_args.emplace_back(mount_point.getValue());
 
         VERBOSE_LOG("Filesystem parameters: format version %d, block size %u (bytes), iv size %u "
                     "(bytes)",
@@ -1062,7 +1295,8 @@ public:
         fsopt.iv_size = config.iv_size;
         fsopt.version = config.version;
         fsopt.master_key = config.master_key;
-        fsopt.flags = config.version < 3 ? 0 : kOptionStoreTime;
+        fsopt.flags = config.version != 3 ? 0 : kOptionStoreTime;
+        fsopt.max_padding_size = config.max_padding;
         if (insecure.getValue())
             fsopt.flags.value() |= kOptionNoAuthentication;
         bool case_insensitive = false;
@@ -1094,19 +1328,16 @@ public:
             INFO_LOG("Mounting as a Unicode normalized filesystem");
             fsopt.flags.value() |= kOptionNFCFileName;
         }
-        std::shared_ptr<FileStream> lock_stream;
-        DEFER(if (lock_stream) {
-            lock_stream->close();
-            lock_stream.reset();
-            fsopt.root->remove_file_nothrow(operations::LOCK_FILENAME);
-        });
+        if (skip_dot_dot.getValue())
+        {
+            fsopt.flags.value() |= kOptionSkipDotDot;
+        }
 
         if (config.version < 4)
         {
-
             try
             {
-                lock_stream = fsopt.root->open_file_stream(
+                fsopt.lock_stream = fsopt.root->open_file_stream(
                     securefs::operations::LOCK_FILENAME, O_CREAT | O_EXCL | O_RDONLY, 0644);
             }
             catch (const ExceptionBase& e)
@@ -1148,6 +1379,7 @@ public:
         {
             lite::init_fuse_operations(&operations, native_xattr);
         }
+        VERBOSE_LOG("Calling fuse_main with arguments: %s", escape_args(fuse_args).c_str());
         recreate_logger();
         return fuse_main(static_cast<int>(fuse_args.size()),
                          const_cast<char**>(to_c_style_args(fuse_args).data()),
@@ -1171,6 +1403,20 @@ public:
         add_all_args_from_base(cmdline);
         cmdline.parse(argc, argv);
 
+        fflush(stdout);
+        fflush(stderr);
+        puts("You should backup your repository before running this command. Are you sure you want "
+             "to continue? (yes/no)");
+        fflush(stdout);
+        char answer[100] = {};
+        if (fgets(answer, 100, stdin) == nullptr)
+        {
+            THROW_POSIX_EXCEPTION(errno, "fgets");
+        }
+        if (strcmp(answer, "yes\n") != 0)
+        {
+            throw_runtime_error("User aborted operation");
+        }
         get_password(false);
     }
 
@@ -1197,7 +1443,7 @@ public:
         fsopt.iv_size = config.iv_size;
         fsopt.version = config.version;
         fsopt.master_key = config.master_key;
-        fsopt.flags = 0;
+        fsopt.flags = config.version != 3 ? 0 : kOptionStoreTime;
 
         operations::FileSystemContext fs(fsopt);
         fix(data_dir.getValue(), &fs);
@@ -1233,8 +1479,7 @@ public:
 #ifdef WIN32
         HMODULE hd = GetModuleHandleW((sizeof(void*) == 8) ? L"winfsp-x64.dll" : L"winfsp-x86.dll");
         NTSTATUS(*fsp_version_func)
-        (uint32_t*)
-            = reinterpret_cast<decltype(fsp_version_func)>(GetProcAddress(hd, "FspVersion"));
+        (uint32_t*) = get_proc_address<decltype(fsp_version_func)>(hd, "FspVersion");
         if (fsp_version_func)
         {
             uint32_t vn;
@@ -1243,12 +1488,6 @@ public:
                 printf("WinFsp %u.%u\n", vn >> 16, vn & 0xFFFFu);
             }
         }
-#elif defined(__APPLE__)
-        typedef const char* version_function(void);
-        auto osx_version_func
-            = reinterpret_cast<version_function*>(::dlsym(RTLD_DEFAULT, "osxfuse_version"));
-        if (osx_version_func)
-            printf("osxfuse %s\n", osx_version_func());
 #else
         typedef int version_function(void);
         auto fuse_version_func
@@ -1358,6 +1597,8 @@ public:
         printf("Per file key generation algorithm: %s\n",
                format_version < 4 ? "HMAC-SHA256" : "AES");
         printf("Content cipher: %s\n", format_version < 4 ? "AES-256-GCM" : "AES-128-GCM");
+        printf("Maximum padding to obfuscate file sizes: %u byte(s)\n",
+               config_json.get("max_padding", 0u).asUInt());
         return 0;
     }
 };
@@ -1366,14 +1607,17 @@ int commands_main(int argc, const char*
 {
     try
     {
+        std::ios_base::sync_with_stdio(false);
         std::unique_ptr<CommandBase> cmds[] = {make_unique<MountCommand>(),
                                                make_unique<CreateCommand>(),
                                                make_unique<ChangePasswordCommand>(),
                                                make_unique<FixCommand>(),
                                                make_unique<VersionCommand>(),
                                                make_unique<InfoCommand>()};
+        const char* const program_name = argv[0];
 
-        auto print_usage = [&]() {
+        auto print_usage = [&]()
+        {
             fputs("Available subcommands:\n\n", stderr);
 
             for (auto&& command : cmds)
@@ -1392,7 +1636,7 @@ int commands_main(int argc, const char*
                 }
             }
 
-            fprintf(stderr, "\nType %s ${SUBCOMMAND} --help for details\n", argv[0]);
+            fprintf(stderr, "\nType %s ${SUBCOMMAND} --help for details\n", program_name);
             return 1;
         };
 
diff -pruN 0.11.1+ds-4/sources/commands.h 0.13.1+ds-1/sources/commands.h
--- 0.11.1+ds-4/sources/commands.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/commands.h	2023-01-27 02:25:50.000000000 +0000
@@ -16,6 +16,7 @@ struct FSConfig
     unsigned block_size;
     unsigned iv_size;
     unsigned version;
+    unsigned max_padding = 0;
 };
 
 class CommandBase
diff -pruN 0.11.1+ds-4/sources/common_platform.cpp 0.13.1+ds-1/sources/common_platform.cpp
--- 0.11.1+ds-4/sources/common_platform.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/common_platform.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -91,4 +91,45 @@ void FileStream::setxattr(const char*, v
 ssize_t FileStream::listxattr(char*, size_t) { throw VFSException(ENOTSUP); }
 
 void FileStream::removexattr(const char*) { throw VFSException(ENOTSUP); }
+
+void POSIXColourSetter::use(Colour::Code _colourCode) noexcept
+{
+    switch (_colourCode)
+    {
+    case Colour::Default:
+        return setColour("[0;39m");
+    case Colour::White:
+        return setColour("[0m");
+    case Colour::Red:
+        return setColour("[0;31m");
+    case Colour::Green:
+        return setColour("[0;32m");
+    case Colour::Blue:
+        return setColour("[0:34m");
+    case Colour::Cyan:
+        return setColour("[0;36m");
+    case Colour::Yellow:
+        return setColour("[0;33m");
+    case Colour::Grey:
+        return setColour("[1;30m");
+
+    case Colour::LightGrey:
+        return setColour("[0;37m");
+    case Colour::BrightRed:
+        return setColour("[1;31m");
+    case Colour::BrightGreen:
+        return setColour("[1;32m");
+    case Colour::BrightWhite:
+        return setColour("[1;37m");
+
+    default:
+        break;
+    }
+}
+
+void POSIXColourSetter::setColour(const char* _escapeCode) noexcept
+{
+    putc('\033', m_fp);
+    fputs(_escapeCode, m_fp);
+}
 }    // namespace securefs
diff -pruN 0.11.1+ds-4/sources/constants.h 0.13.1+ds-1/sources/constants.h
--- 0.11.1+ds-4/sources/constants.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/constants.h	2023-01-27 02:25:50.000000000 +0000
@@ -3,5 +3,5 @@
 namespace securefs
 {
 const unsigned kOptionNoAuthentication = 0x1, kOptionReadOnly = 0x2, kOptionStoreTime = 0x4,
-               kOptionCaseFoldFileName = 0x8, kOptionNFCFileName = 0x10;
+               kOptionCaseFoldFileName = 0x8, kOptionNFCFileName = 0x10, kOptionSkipDotDot = 0x20;
 }
diff -pruN 0.11.1+ds-4/sources/crypto.cpp 0.13.1+ds-1/sources/crypto.cpp
--- 0.11.1+ds-4/sources/crypto.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/crypto.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -1,6 +1,6 @@
 #include "crypto.h"
 #include "exceptions.h"
-#include "securefs_config.h"
+#include "lock_guard.h"
 
 #include <cryptopp/aes.h>
 #include <cryptopp/gcm.h>
@@ -10,10 +10,6 @@
 #include <cryptopp/rng.h>
 #include <cryptopp/sha.h>
 
-#if !HAS_THREAD_LOCAL
-#include <pthread.h>
-#endif
-
 // Some of the following codes are copied from https://github.com/arktronic/aes-siv.
 // The licence follows:
 
@@ -117,6 +113,8 @@ void AES_SIV::encrypt_and_authenticate(c
                                        void* ciphertext,
                                        void* siv)
 {
+    LockGuard<Mutex> lg(m_mutex);
+
     s2v(plaintext, text_len, additional_data, additional_len, siv);
     byte modded_iv[AES_SIV::IV_SIZE];
     memcpy(modded_iv, siv, AES_SIV::IV_SIZE);
@@ -137,6 +135,8 @@ bool AES_SIV::decrypt_and_verify(const v
                                  void* plaintext,
                                  const void* siv)
 {
+    LockGuard<Mutex> lg(m_mutex);
+
     byte temp_iv[AES_SIV::IV_SIZE];
     memcpy(temp_iv, siv, AES_SIV::IV_SIZE);
     // Clear the 31st and 63rd bits in the IV.
@@ -151,42 +151,11 @@ bool AES_SIV::decrypt_and_verify(const v
     return CryptoPP::VerifyBufsEqual(static_cast<const byte*>(siv), temp_iv, AES_SIV::IV_SIZE);
 }
 
-#if HAS_THREAD_LOCAL
-static thread_local CryptoPP::AutoSeededRandomPool rng;
 void generate_random(void* buffer, size_t size)
 {
+    static thread_local CryptoPP::AutoSeededRandomPool rng;
     rng.GenerateBlock(static_cast<byte*>(buffer), size);
 }
-#else
-static pthread_once_t CSRNG_ONCE = PTHREAD_ONCE_INIT;
-static pthread_key_t CSRNG_KEY;
-
-void generate_random(void* buffer, size_t size)
-{
-    int rc = pthread_once(&CSRNG_ONCE, []() {
-        int rc = pthread_key_create(
-            &CSRNG_KEY, [](void* p) { delete static_cast<CryptoPP::AutoSeededRandomPool*>(p); });
-        if (rc)
-            abort();
-    });
-    if (rc)
-    {
-        THROW_POSIX_EXCEPTION(rc, "pthread_once");
-    }
-    auto rng = static_cast<CryptoPP::AutoSeededRandomPool*>(pthread_getspecific(CSRNG_KEY));
-    if (!rng)
-    {
-        rng = new CryptoPP::AutoSeededRandomPool();
-        rc = pthread_setspecific(CSRNG_KEY, rng);
-        if (rc)
-        {
-            delete rng;
-            THROW_POSIX_EXCEPTION(rc, "pthread_setspecific");
-        }
-    }
-    rng->GenerateBlock(static_cast<byte*>(buffer), size);
-}
-#endif
 
 void hmac_sha256_calculate(
     const void* message, size_t msg_len, const void* key, size_t key_len, void* mac, size_t mac_len)
diff -pruN 0.11.1+ds-4/sources/crypto.h 0.13.1+ds-1/sources/crypto.h
--- 0.11.1+ds-4/sources/crypto.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/crypto.h	2023-01-27 02:25:50.000000000 +0000
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "platform.h"
+
 #include <cryptopp/aes.h>
 #include <cryptopp/cmac.h>
 #include <cryptopp/modes.h>
@@ -13,8 +15,16 @@ namespace securefs
 class AES_SIV
 {
 private:
-    CryptoPP::CMAC<CryptoPP::AES> m_cmac;
-    CryptoPP::CTR_Mode<CryptoPP::AES>::Encryption m_ctr;
+    Mutex m_mutex;
+    CryptoPP::CMAC<CryptoPP::AES> m_cmac THREAD_ANNOTATION_GUARDED_BY(m_mutex);
+    CryptoPP::CTR_Mode<CryptoPP::AES>::Encryption m_ctr THREAD_ANNOTATION_GUARDED_BY(m_mutex);
+
+private:
+    void s2v(const void* plaintext,
+             size_t text_len,
+             const void* additional_data,
+             size_t additional_len,
+             void* iv);
 
 public:
     static constexpr size_t IV_SIZE = 16;
@@ -23,11 +33,7 @@ public:
     explicit AES_SIV(const void* key, size_t size);
     ~AES_SIV();
 
-    void s2v(const void* plaintext,
-             size_t text_len,
-             const void* additional_data,
-             size_t additional_len,
-             void* iv);
+    DISABLE_COPY_MOVE(AES_SIV);
 
     void encrypt_and_authenticate(const void* plaintext,
                                   size_t text_len,
@@ -79,14 +85,4 @@ unsigned int pbkdf_hmac_sha256(const voi
                                size_t derive_len);
 
 void generate_random(void* buffer, size_t size);
-
-void libscrypt_scrypt(const uint8_t* passwd,
-                      size_t passwdlen,
-                      const uint8_t* salt,
-                      size_t saltlen,
-                      uint64_t N,
-                      uint32_t r,
-                      uint32_t p,
-                      uint8_t* buf,
-                      size_t buflen);
 }    // namespace securefs
diff -pruN 0.11.1+ds-4/sources/exceptions.h 0.13.1+ds-1/sources/exceptions.h
--- 0.11.1+ds-4/sources/exceptions.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/exceptions.h	2023-01-27 02:25:50.000000000 +0000
@@ -28,7 +28,7 @@ public:
     const char* what() const noexcept override;
 };
 
-class UnreachableCodeException : public ExceptionBase
+class UnreachableCodeException final : public ExceptionBase
 {
 private:
     const char* m_func;
@@ -50,7 +50,7 @@ public:
 
 #define UNREACHABLE() throw securefs::UnreachableCodeException(__FUNCTION__, __FILE__, __LINE__)
 
-class VFSException : public ExceptionBase
+class VFSException final : public ExceptionBase
 {
 private:
     int m_errno;
@@ -70,7 +70,7 @@ class SystemException : public Exception
 {
 };
 
-class POSIXException : public SystemException
+class POSIXException final : public SystemException
 {
 private:
     int m_errno;
@@ -210,7 +210,7 @@ public:
     int error_number() const noexcept override { return EFBIG; }
 };
 
-class InvalidCastException : public ExceptionBase
+class InvalidCastException final : public ExceptionBase
 {
 private:
     const char* from_name;
diff -pruN 0.11.1+ds-4/sources/files.cpp 0.13.1+ds-1/sources/files.cpp
--- 0.11.1+ds-4/sources/files.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/files.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -2,11 +2,13 @@
 #include "crypto.h"
 #include "myutils.h"
 
+#include <cryptopp/integer.h>
+#include <cryptopp/secblock.h>
+
 #include <algorithm>
 #include <unordered_map>
 #include <utility>
 
-#include <cryptopp/secblock.h>
 #include <sys/types.h>
 
 /**
@@ -110,6 +112,7 @@ FileBase::FileBase(std::shared_ptr<FileS
                    bool check,
                    unsigned block_size,
                    unsigned iv_size,
+                   unsigned max_padding_size,
                    bool store_time)
     : m_refcount(1)
     , m_header()
@@ -123,7 +126,7 @@ FileBase::FileBase(std::shared_ptr<FileS
 {
     warn_if_key_not_random(key_, __FILE__, __LINE__);
     key_type data_key, meta_key;
-    byte generated_keys[KEY_LENGTH * 3];
+    byte generated_keys[KEY_LENGTH * 4] = {};
     hkdf(key_.data(),
          key_.size(),
          nullptr,
@@ -131,7 +134,7 @@ FileBase::FileBase(std::shared_ptr<FileS
          id_.data(),
          id_.size(),
          generated_keys,
-         array_length(generated_keys));
+         max_padding_size > 0 ? 4 * KEY_LENGTH : 3 * KEY_LENGTH);
     memcpy(data_key.data(), generated_keys, KEY_LENGTH);
     memcpy(meta_key.data(), generated_keys + KEY_LENGTH, KEY_LENGTH);
     auto crypt = make_cryptstream_aes_gcm(std::static_pointer_cast<StreamBase>(data_stream),
@@ -155,11 +158,25 @@ FileBase::FileBase(std::shared_ptr<FileS
         generated_keys + 2 * KEY_LENGTH, KEY_LENGTH, null_iv, array_length(null_iv));
     m_xattr_dec.SetKeyWithIV(
         generated_keys + 2 * KEY_LENGTH, KEY_LENGTH, null_iv, array_length(null_iv));
+
+    if (max_padding_size > 0)
+    {
+        warn_if_key_not_random(generated_keys, sizeof(generated_keys), __FILE__, __LINE__);
+        CryptoPP::Integer integer(generated_keys + 3 * KEY_LENGTH,
+                                  KEY_LENGTH,
+                                  CryptoPP::Integer::UNSIGNED,
+                                  CryptoPP::BIG_ENDIAN_ORDER);
+        auto padding_size = static_cast<unsigned>(integer.Modulo(max_padding_size + 1));
+        m_stream = std::make_shared<PaddedStream>(std::move(m_stream), padding_size);
+    }
 }
 
 void FileBase::read_header()
 {
-    memset(m_flags, 0xFF, sizeof(m_flags));
+    for (auto& f : m_flags)
+    {
+        f.store(-1);
+    }
     size_t header_size = m_store_time ? EXTENDED_HEADER_SIZE : HEADER_SIZE;
     auto header = make_unique_array<byte>(header_size);
     auto rc = m_header->read_header(header.get(), header_size);
diff -pruN 0.11.1+ds-4/sources/files.h 0.13.1+ds-1/sources/files.h
--- 0.11.1+ds-4/sources/files.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/files.h	2023-01-27 02:25:50.000000000 +0000
@@ -3,12 +3,14 @@
 #include "myutils.h"
 #include "platform.h"
 #include "streams.h"
+#include "thread_safety_annotations.hpp"
 
 #include <atomic>
 #include <chrono>
 #include <functional>
 #include <memory>
 #include <string>
+#include <thread>
 #include <unordered_map>
 
 #include <cryptopp/aes.h>
@@ -22,7 +24,7 @@ class RegularFile;
 class Directory;
 class Symlink;
 
-class FileBase
+class THREAD_ANNOTATION_CAPABILITY("mutex") FileBase
 {
 private:
     static const size_t NUM_FLAGS = 7, HEADER_SIZE = 32, EXTENDED_HEADER_SIZE = 80,
@@ -35,27 +37,32 @@ private:
                   "Constants are wrong!");
 
 private:
+    securefs::Mutex m_lock;
     ptrdiff_t m_refcount;
-    std::shared_ptr<HeaderBase> m_header;
-    id_type m_id;
-    uint32_t m_flags[NUM_FLAGS];
-    fuse_timespec m_atime, m_mtime, m_ctime, m_birthtime;
-    std::shared_ptr<FileStream> m_data_stream, m_meta_stream;
-    CryptoPP::GCM<CryptoPP::AES>::Encryption m_xattr_enc;
-    CryptoPP::GCM<CryptoPP::AES>::Decryption m_xattr_dec;
-    bool m_dirty, m_check, m_store_time;
+    std::shared_ptr<HeaderBase> m_header THREAD_ANNOTATION_GUARDED_BY(*this);
+    const id_type m_id;
+    std::atomic<uint32_t> m_flags[NUM_FLAGS];
+    fuse_timespec m_atime THREAD_ANNOTATION_GUARDED_BY(*this),
+        m_mtime THREAD_ANNOTATION_GUARDED_BY(*this), m_ctime THREAD_ANNOTATION_GUARDED_BY(*this),
+        m_birthtime THREAD_ANNOTATION_GUARDED_BY(*this);
+    std::shared_ptr<FileStream> m_data_stream THREAD_ANNOTATION_GUARDED_BY(*this),
+        m_meta_stream THREAD_ANNOTATION_GUARDED_BY(*this);
+    CryptoPP::GCM<CryptoPP::AES>::Encryption m_xattr_enc THREAD_ANNOTATION_GUARDED_BY(*this);
+    CryptoPP::GCM<CryptoPP::AES>::Decryption m_xattr_dec THREAD_ANNOTATION_GUARDED_BY(*this);
+    bool m_dirty THREAD_ANNOTATION_GUARDED_BY(*this);
+    const bool m_check, m_store_time;
 
 private:
-    void read_header();
+    void read_header() THREAD_ANNOTATION_REQUIRES(*this);
 
     [[noreturn]] void throw_invalid_cast(int to_type);
 
 protected:
-    std::shared_ptr<StreamBase> m_stream;
+    std::shared_ptr<StreamBase> m_stream THREAD_ANNOTATION_GUARDED_BY(*this);
 
     uint32_t get_root_page() const noexcept { return m_flags[4]; }
 
-    void set_root_page(uint32_t value) noexcept
+    void set_root_page(uint32_t value) noexcept THREAD_ANNOTATION_REQUIRES(*this)
     {
         m_flags[4] = value;
         m_dirty = true;
@@ -63,7 +70,7 @@ protected:
 
     uint32_t get_start_free_page() const noexcept { return m_flags[5]; }
 
-    void set_start_free_page(uint32_t value) noexcept
+    void set_start_free_page(uint32_t value) noexcept THREAD_ANNOTATION_REQUIRES(*this)
     {
         m_flags[5] = value;
         m_dirty = true;
@@ -71,7 +78,7 @@ protected:
 
     uint32_t get_num_free_page() const noexcept { return m_flags[6]; }
 
-    void set_num_free_page(uint32_t value) noexcept
+    void set_num_free_page(uint32_t value) noexcept THREAD_ANNOTATION_REQUIRES(*this)
     {
         m_flags[6] = value;
         m_dirty = true;
@@ -80,7 +87,7 @@ protected:
     /**
      * Subclasss should override this if additional flush operations are needed
      */
-    virtual void subflush() {}
+    virtual void subflush() THREAD_ANNOTATION_REQUIRES(*this) {}
 
 public:
     static const byte REGULAR_FILE = S_IFREG >> 12, SYMLINK = S_IFLNK >> 12,
@@ -129,17 +136,23 @@ public:
                       bool check,
                       unsigned block_size,
                       unsigned iv_size,
-                      bool store_time = false);
+                      unsigned max_padding_size,
+                      bool store_time);
 
     virtual ~FileBase();
     DISABLE_COPY_MOVE(FileBase)
 
-    void initialize_empty(uint32_t mode, uint32_t uid, uint32_t gid);
+    void lock() THREAD_ANNOTATION_ACQUIRE() { m_lock.lock(); }
+    void unlock() THREAD_ANNOTATION_RELEASE() { m_lock.unlock(); }
+    bool try_lock() THREAD_ANNOTATION_TRY_ACQUIRE(true) { return m_lock.try_lock(); }
+
+    void initialize_empty(uint32_t mode, uint32_t uid, uint32_t gid)
+        THREAD_ANNOTATION_REQUIRES(*this);
 
     // --Begin of getters and setters for stats---
     uint32_t get_mode() const noexcept { return m_flags[0]; }
 
-    void set_mode(uint32_t value) noexcept
+    void set_mode(uint32_t value) noexcept THREAD_ANNOTATION_REQUIRES(*this)
     {
         if (get_mode() == value)
             return;
@@ -150,7 +163,7 @@ public:
 
     uint32_t get_uid() const noexcept { return m_flags[1]; }
 
-    void set_uid(uint32_t value) noexcept
+    void set_uid(uint32_t value) noexcept THREAD_ANNOTATION_REQUIRES(*this)
     {
         if (get_uid() == value)
             return;
@@ -161,7 +174,7 @@ public:
 
     uint32_t get_gid() const noexcept { return m_flags[2]; }
 
-    void set_gid(uint32_t value) noexcept
+    void set_gid(uint32_t value) noexcept THREAD_ANNOTATION_REQUIRES(*this)
     {
         if (get_gid() == value)
             return;
@@ -172,7 +185,7 @@ public:
 
     uint32_t get_nlink() const noexcept { return m_flags[3]; }
 
-    void set_nlink(uint32_t value) noexcept
+    void set_nlink(uint32_t value) noexcept THREAD_ANNOTATION_REQUIRES(*this)
     {
         if (get_nlink() == value)
             return;
@@ -181,33 +194,45 @@ public:
         m_dirty = true;
     }
 
-    void get_atime(fuse_timespec& out) const noexcept { out = m_atime; }
+    void get_atime(fuse_timespec& out) const noexcept THREAD_ANNOTATION_REQUIRES(*this)
+    {
+        out = m_atime;
+    }
 
-    void get_mtime(fuse_timespec& out) const noexcept { out = m_mtime; }
+    void get_mtime(fuse_timespec& out) const noexcept THREAD_ANNOTATION_REQUIRES(*this)
+    {
+        out = m_mtime;
+    }
 
-    void get_ctime(fuse_timespec& out) const noexcept { out = m_ctime; }
+    void get_ctime(fuse_timespec& out) const noexcept THREAD_ANNOTATION_REQUIRES(*this)
+    {
+        out = m_ctime;
+    }
 
-    void get_birthtime(fuse_timespec& out) const noexcept { out = m_birthtime; }
+    void get_birthtime(fuse_timespec& out) const noexcept THREAD_ANNOTATION_REQUIRES(*this)
+    {
+        out = m_birthtime;
+    }
 
-    void set_atime(const fuse_timespec& in) noexcept
+    void set_atime(const fuse_timespec& in) noexcept THREAD_ANNOTATION_REQUIRES(*this)
     {
         m_atime = in;
         m_dirty = true;
     }
 
-    void set_mtime(const fuse_timespec& in) noexcept
+    void set_mtime(const fuse_timespec& in) noexcept THREAD_ANNOTATION_REQUIRES(*this)
     {
         m_mtime = in;
         m_dirty = true;
     }
 
-    void set_ctime(const fuse_timespec& in) noexcept
+    void set_ctime(const fuse_timespec& in) noexcept THREAD_ANNOTATION_REQUIRES(*this)
     {
         m_ctime = in;
         m_dirty = true;
     }
 
-    void update_atime_helper()
+    void update_atime_helper() THREAD_ANNOTATION_REQUIRES(*this)
     {
         if (m_store_time && (m_atime.tv_sec < m_mtime.tv_sec || m_atime.tv_sec < m_ctime.tv_sec))
         {
@@ -216,7 +241,7 @@ public:
         }
     }
 
-    void update_mtime_helper()
+    void update_mtime_helper() THREAD_ANNOTATION_REQUIRES(*this)
     {
         if (m_store_time)
         {
@@ -226,7 +251,7 @@ public:
         }
     }
 
-    void update_ctime_helper()
+    void update_ctime_helper() THREAD_ANNOTATION_REQUIRES(*this)
     {
         if (m_store_time)
         {
@@ -253,32 +278,32 @@ public:
 
     bool is_unlinked() const noexcept { return get_nlink() <= 0; }
 
-    void unlink()
+    void unlink() THREAD_ANNOTATION_REQUIRES(*this)
     {
-        auto nlink = get_nlink();
-        --nlink;
-        set_nlink(nlink);
+        --m_flags[3];
+        m_dirty = true;
     }
 
-    void flush();
+    void flush() THREAD_ANNOTATION_REQUIRES(*this);
 
-    void fsync()
+    void fsync() THREAD_ANNOTATION_REQUIRES(*this)
     {
         m_data_stream->fsync();
         m_meta_stream->fsync();
     }
 
-    void utimens(const struct fuse_timespec ts[2]);
+    void utimens(const struct fuse_timespec ts[2]) THREAD_ANNOTATION_REQUIRES(*this);
 
-    void stat(struct fuse_stat* st);
+    void stat(struct fuse_stat* st) THREAD_ANNOTATION_REQUIRES(*this);
 
-    ssize_t listxattr(char* buffer, size_t size);
+    ssize_t listxattr(char* buffer, size_t size) THREAD_ANNOTATION_REQUIRES(*this);
 
-    ssize_t getxattr(const char* name, char* value, size_t size);
+    ssize_t getxattr(const char* name, char* value, size_t size) THREAD_ANNOTATION_REQUIRES(*this);
 
-    void setxattr(const char* name, const char* value, size_t size, int flags);
+    void setxattr(const char* name, const char* value, size_t size, int flags)
+        THREAD_ANNOTATION_REQUIRES(*this);
 
-    void removexattr(const char* name);
+    void removexattr(const char* name) THREAD_ANNOTATION_REQUIRES(*this);
 
     template <class T>
     T* cast_as()
@@ -305,20 +330,22 @@ public:
     int type() const noexcept override { return class_type(); }
 
     length_type read(void* output, offset_type off, length_type len)
+        THREAD_ANNOTATION_REQUIRES(*this)
     {
         update_atime_helper();
         return this->m_stream->read(output, off, len);
     }
 
     void write(const void* input, offset_type off, length_type len)
+        THREAD_ANNOTATION_REQUIRES(*this)
     {
         update_mtime_helper();
         return this->m_stream->write(input, off, len);
     }
 
-    length_type size() const noexcept { return m_stream->size(); }
+    length_type size() const noexcept THREAD_ANNOTATION_REQUIRES(*this) { return m_stream->size(); }
 
-    void truncate(length_type new_size)
+    void truncate(length_type new_size) THREAD_ANNOTATION_REQUIRES(*this)
     {
         update_mtime_helper();
         return m_stream->resize(new_size);
@@ -337,7 +364,7 @@ public:
 
     int type() const noexcept override { return class_type(); }
 
-    std::string get()
+    std::string get() THREAD_ANNOTATION_REQUIRES(*this)
     {
         std::string result(m_stream->size(), 0);
         auto rc = m_stream->read(&result[0], 0, result.size());
@@ -346,7 +373,10 @@ public:
         return result;
     }
 
-    void set(const std::string& path) { m_stream->write(path.data(), 0, path.size()); }
+    void set(const std::string& path) THREAD_ANNOTATION_REQUIRES(*this)
+    {
+        m_stream->write(path.data(), 0, path.size());
+    }
 };
 
 class Directory : public FileBase
@@ -368,12 +398,14 @@ public:
     typedef std::function<bool(const std::string&, const id_type&, int)> callback;
 
     bool get_entry(const std::string& name, id_type& id, int& type)
+        THREAD_ANNOTATION_REQUIRES(*this)
     {
         update_atime_helper();
         return get_entry_impl(name, id, type);
     }
 
     bool add_entry(const std::string& name, const id_type& id, int type)
+        THREAD_ANNOTATION_REQUIRES(*this)
     {
         update_mtime_helper();
         return add_entry_impl(name, id, type);
@@ -384,6 +416,7 @@ public:
      * Returns false when the entry is not found.
      */
     bool remove_entry(const std::string& name, id_type& id, int& type)
+        THREAD_ANNOTATION_REQUIRES(*this)
     {
         update_mtime_helper();
         return remove_entry_impl(name, id, type);
@@ -392,13 +425,13 @@ public:
     /**
      * When callback returns false, the iteration will be terminated
      */
-    void iterate_over_entries(const callback& cb)
+    void iterate_over_entries(const callback& cb) THREAD_ANNOTATION_REQUIRES(*this)
     {
         update_atime_helper();
         return iterate_over_entries_impl(cb);
     }
 
-    virtual bool empty() = 0;
+    virtual bool empty() THREAD_ANNOTATION_REQUIRES(*this) = 0;
 
 protected:
     virtual bool get_entry_impl(const std::string& name, id_type& id, int& type) = 0;
@@ -417,14 +450,14 @@ protected:
     virtual void iterate_over_entries_impl(const callback& cb) = 0;
 };
 
-class SimpleDirectory : public Directory
+class SimpleDirectory final : public Directory
 {
 private:
     std::unordered_map<std::string, std::pair<id_type, int>> m_table;
     bool m_dirty;
 
 private:
-    void initialize();
+    void initialize() THREAD_ANNOTATION_REQUIRES(*this);
 
 public:
     template <class... Args>
@@ -439,7 +472,7 @@ public:
 
     bool remove_entry_impl(const std::string& name, id_type& id, int& type) override;
 
-    void subflush() override;
+    void subflush() override THREAD_ANNOTATION_REQUIRES(*this);
 
     void iterate_over_entries_impl(const callback& cb) override
     {
@@ -454,4 +487,73 @@ public:
 
     ~SimpleDirectory();
 };
+
+class THREAD_ANNOTATION_SCOPED_CAPABILITY FileLockGuard
+{
+private:
+    std::lock_guard<FileBase> m_lg;
+
+public:
+    explicit FileLockGuard(FileBase& fb) THREAD_ANNOTATION_ACQUIRE(fb)
+        THREAD_ANNOTATION_ACQUIRE(fb.cast_as<RegularFile>())
+            THREAD_ANNOTATION_ACQUIRE(fb.cast_as<Directory>())
+                THREAD_ANNOTATION_ACQUIRE(fb.cast_as<Symlink>())
+        : m_lg(fb)
+    {
+    }
+    ~FileLockGuard() THREAD_ANNOTATION_RELEASE() {}
+};
+
+class THREAD_ANNOTATION_SCOPED_CAPABILITY SpinFileLockGuard
+{
+private:
+    std::unique_lock<FileBase> m_ul;
+
+public:
+    explicit SpinFileLockGuard(FileBase& fb) THREAD_ANNOTATION_ACQUIRE(fb)
+        THREAD_ANNOTATION_ACQUIRE(fb.cast_as<RegularFile>())
+            THREAD_ANNOTATION_ACQUIRE(fb.cast_as<Directory>())
+                THREAD_ANNOTATION_ACQUIRE(fb.cast_as<Symlink>())
+        : m_ul(fb, std::defer_lock)
+    {
+        for (int i = 0; i < 100; ++i)
+        {
+            if (m_ul.try_lock())
+            {
+                return;
+            }
+            std::this_thread::sleep_for(std::chrono::milliseconds(10));
+        }
+        throwVFSException(EBUSY);
+    }
+    ~SpinFileLockGuard() THREAD_ANNOTATION_RELEASE() {}
+};
+
+class THREAD_ANNOTATION_SCOPED_CAPABILITY DoubleFileLockGuard
+{
+private:
+    std::unique_lock<FileBase> m1, m2;
+
+public:
+    explicit DoubleFileLockGuard(FileBase& f1, FileBase& f2) THREAD_ANNOTATION_ACQUIRE(f1)
+        THREAD_ANNOTATION_ACQUIRE(f1.cast_as<RegularFile>())
+            THREAD_ANNOTATION_ACQUIRE(f1.cast_as<Directory>())
+                THREAD_ANNOTATION_ACQUIRE(f1.cast_as<Symlink>()) THREAD_ANNOTATION_ACQUIRE(f2)
+                    THREAD_ANNOTATION_ACQUIRE(f2.cast_as<RegularFile>())
+                        THREAD_ANNOTATION_ACQUIRE(f2.cast_as<Directory>())
+                            THREAD_ANNOTATION_ACQUIRE(f2.cast_as<Symlink>())
+    {
+        if (&f1 == &f2)
+        {
+            m1 = std::unique_lock<FileBase>{f1};
+        }
+        else
+        {
+            std::lock(f1, f2);
+            m1 = {f1, std::adopt_lock};
+            m2 = {f2, std::adopt_lock};
+        }
+    }
+    ~DoubleFileLockGuard() THREAD_ANNOTATION_RELEASE() {}
+};
 }    // namespace securefs
diff -pruN 0.11.1+ds-4/sources/file_table.cpp 0.13.1+ds-1/sources/file_table.cpp
--- 0.11.1+ds-4/sources/file_table.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/file_table.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -1,15 +1,19 @@
 #include "file_table.h"
 #include "btree_dir.h"
 #include "exceptions.h"
+#include "lock_guard.h"
 #include "logger.h"
 #include "myutils.h"
 #include "platform.h"
 
 #include <algorithm>
+#include <cmath>
+#include <cstdlib>
 #include <limits>
 #include <queue>
 #include <string.h>
 #include <string>
+#include <thread>
 #include <utility>
 #include <vector>
 
@@ -143,13 +147,18 @@ public:
     }
 };
 
-FileTable::FileTable(int version,
-                     std::shared_ptr<const OSService> root,
-                     const key_type& master_key,
-                     uint32_t flags,
-                     unsigned block_size,
-                     unsigned iv_size)
-    : m_flags(flags), m_block_size(block_size), m_iv_size(iv_size), m_root(root)
+FileTableImpl::FileTableImpl(int version,
+                             std::shared_ptr<const OSService> root,
+                             const key_type& master_key,
+                             uint32_t flags,
+                             unsigned block_size,
+                             unsigned iv_size,
+                             unsigned max_padding_size)
+    : m_flags(flags)
+    , m_block_size(block_size)
+    , m_iv_size(iv_size)
+    , m_max_padding_size(max_padding_size)
+    , m_root(root)
 {
     memcpy(m_master_key.data(), master_key.data(), master_key.size());
     switch (version)
@@ -166,14 +175,15 @@ FileTable::FileTable(int version,
     }
 }
 
-FileTable::~FileTable()
+FileTableImpl::~FileTableImpl()
 {
     for (auto&& pair : m_files)
         finalize(pair.second);
 }
 
-FileBase* FileTable::open_as(const id_type& id, int type)
+FileBase* FileTableImpl::open_as(const id_type& id, int type)
 {
+    LockGuard<Mutex> lg(m_lock);
     auto it = m_files.find(id);
     if (it != m_files.end())
     {
@@ -201,6 +211,7 @@ FileBase* FileTable::open_as(const id_ty
                                         is_auth_enabled(),
                                         m_block_size,
                                         m_iv_size,
+                                        m_max_padding_size,
                                         is_time_stored());
     fb->setref(1);
     auto result = fb.get();
@@ -208,10 +219,12 @@ FileBase* FileTable::open_as(const id_ty
     return result;
 }
 
-FileBase* FileTable::create_as(const id_type& id, int type)
+FileBase* FileTableImpl::create_as(const id_type& id, int type)
 {
     if (is_readonly())
         throwVFSException(EROFS);
+
+    LockGuard<Mutex> lg(m_lock);
     if (m_files.find(id) != m_files.end())
         throwVFSException(EEXIST);
 
@@ -225,6 +238,7 @@ FileBase* FileTable::create_as(const id_
                                         is_auth_enabled(),
                                         m_block_size,
                                         m_iv_size,
+                                        m_max_padding_size,
                                         is_time_stored());
     fb->setref(1);
     auto result = fb.get();
@@ -232,11 +246,12 @@ FileBase* FileTable::create_as(const id_
     return result;
 }
 
-void FileTable::close(FileBase* fb)
+void FileTableImpl::close(FileBase* fb)
 {
     if (!fb)
         throwVFSException(EFAULT);
 
+    LockGuard<Mutex> lg(m_lock);
     auto iter = m_files.find(fb->get_id());
     if (iter == m_files.end() || iter->second.get() != fb)
         throwInvalidArgumentException("ID does not match the table");
@@ -261,7 +276,7 @@ void FileTable::close(FileBase* fb)
     }
 }
 
-void FileTable::eject()
+void FileTableImpl::eject()
 {
     auto num_eject = std::min<size_t>(NUM_EJECT, m_closed_ids.size());
     for (size_t i = 0; i < num_eject; ++i)
@@ -272,7 +287,7 @@ void FileTable::eject()
     m_closed_ids.erase(m_closed_ids.begin(), m_closed_ids.begin() + num_eject);
 }
 
-void FileTable::finalize(std::unique_ptr<FileBase>& fb)
+void FileTableImpl::finalize(std::unique_ptr<FileBase>& fb)
 {
     if (!fb)
         return;
@@ -285,13 +300,66 @@ void FileTable::finalize(std::unique_ptr
     }
     else
     {
+        LockGuard<FileBase> lg(*fb);
         fb->flush();
     }
 }
 
-void FileTable::gc()
+void FileTableImpl::gc()
 {
     if (m_closed_ids.size() >= MAX_NUM_CLOSED)
         eject();
 }
+
+FileTable::~FileTable() {}
+
+ShardedFileTableImpl::ShardedFileTableImpl(int version,
+                                           std::shared_ptr<const OSService> root,
+                                           const key_type& master_key,
+                                           uint32_t flags,
+                                           unsigned block_size,
+                                           unsigned iv_size,
+                                           unsigned max_padding_size)
+{
+    unsigned num_shards = 4;
+    const char* env_shards = std::getenv("SECUREFS_NUM_FILE_TABLE_SHARDS");
+    if (env_shards)
+    {
+        num_shards = std::max(2ul, std::strtoul(env_shards, nullptr, 0));
+    }
+    TRACE_LOG("Use %u shards of FileTableImpls.", num_shards);
+
+    m_shards.resize(num_shards);
+    for (unsigned i = 0; i < num_shards; ++i)
+    {
+        m_shards[i].reset(new FileTableImpl(
+            version, root, master_key, flags, block_size, iv_size, max_padding_size));
+    }
+}
+
+ShardedFileTableImpl::~ShardedFileTableImpl() {}
+
+FileBase* ShardedFileTableImpl::open_as(const id_type& id, int type)
+{
+    return get_shard_by_id(id)->open_as(id, type);
+}
+
+FileBase* ShardedFileTableImpl::create_as(const id_type& id, int type)
+{
+    return get_shard_by_id(id)->create_as(id, type);
+}
+
+void ShardedFileTableImpl::close(FileBase* fb)
+{
+    if (!fb)
+    {
+        return;
+    }
+    get_shard_by_id(fb->get_id())->close(fb);
+}
+
+FileTableImpl* ShardedFileTableImpl::get_shard_by_id(const id_type& id) noexcept
+{
+    return m_shards[static_cast<size_t>(id.data()[0]) % m_shards.size()].get();
+}
 }    // namespace securefs
diff -pruN 0.11.1+ds-4/sources/file_table.h 0.13.1+ds-1/sources/file_table.h
--- 0.11.1+ds-4/sources/file_table.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/file_table.h	2023-01-27 02:25:50.000000000 +0000
@@ -5,6 +5,7 @@
 #include "myutils.h"
 #include "platform.h"
 #include "streams.h"
+#include "thread_safety_annotations.hpp"
 
 #include <memory>
 #include <string.h>
@@ -19,8 +20,22 @@ class AutoClosedFileBase;
 
 class FileTable
 {
-    DISABLE_COPY_MOVE(FileTable)
+public:
+    FileTable() {}
+    virtual ~FileTable();
+
+    virtual FileBase* open_as(const id_type& id, int type) = 0;
+    virtual FileBase* create_as(const id_type& id, int type) = 0;
+    virtual void close(FileBase*) = 0;
+    virtual bool is_readonly() const noexcept = 0;
+    virtual bool is_auth_enabled() const noexcept = 0;
+    virtual bool is_time_stored() const noexcept = 0;
+    virtual void statfs(struct fuse_statvfs* fs_info) = 0;
+    virtual bool has_padding() const noexcept = 0;
+};
 
+class FileTableImpl final : public FileTable
+{
 private:
     typedef std::unordered_map<id_type, std::unique_ptr<FileBase>, id_hash> table_type;
 
@@ -28,34 +43,66 @@ private:
     static const int MAX_NUM_CLOSED = 101, NUM_EJECT = 8;
 
 private:
+    securefs::Mutex m_lock;
     key_type m_master_key;
-    table_type m_files;
-    std::vector<id_type> m_closed_ids;
-    std::unique_ptr<FileTableIO> m_fio;
+    table_type m_files THREAD_ANNOTATION_GUARDED_BY(m_lock);
+    std::vector<id_type> m_closed_ids THREAD_ANNOTATION_GUARDED_BY(m_lock);
+    std::unique_ptr<FileTableIO> m_fio THREAD_ANNOTATION_GUARDED_BY(m_lock);
     uint32_t m_flags;
-    unsigned m_block_size, m_iv_size;
+    unsigned m_block_size, m_iv_size, m_max_padding_size;
     std::shared_ptr<const OSService> m_root;
 
 private:
-    void eject();
-    void finalize(std::unique_ptr<FileBase>&);
+    void eject() THREAD_ANNOTATION_REQUIRES(m_lock);
+    void finalize(std::unique_ptr<FileBase>&) THREAD_ANNOTATION_REQUIRES(m_lock);
+    void gc() THREAD_ANNOTATION_REQUIRES(m_lock);
+
+public:
+    explicit FileTableImpl(int version,
+                           std::shared_ptr<const OSService> root,
+                           const key_type& master_key,
+                           uint32_t flags,
+                           unsigned block_size,
+                           unsigned iv_size,
+                           unsigned max_padding_size);
+    ~FileTableImpl();
+    FileBase* open_as(const id_type& id, int type) override;
+    FileBase* create_as(const id_type& id, int type) override;
+    void close(FileBase*) override;
+    bool is_readonly() const noexcept override { return (m_flags & kOptionReadOnly) != 0; }
+    bool is_auth_enabled() const noexcept override
+    {
+        return (m_flags & kOptionNoAuthentication) == 0;
+    }
+    bool is_time_stored() const noexcept override { return (m_flags & kOptionStoreTime) != 0; }
+    void statfs(struct fuse_statvfs* fs_info) override { m_root->statfs(fs_info); }
+    bool has_padding() const noexcept override { return m_max_padding_size > 0; }
+};
+
+class ShardedFileTableImpl final : public FileTable
+{
+private:
+    std::vector<std::unique_ptr<FileTableImpl>> m_shards;
+
+    FileTableImpl* get_shard_by_id(const id_type& id) noexcept;
 
 public:
-    explicit FileTable(int version,
-                       std::shared_ptr<const OSService> root,
-                       const key_type& master_key,
-                       uint32_t flags,
-                       unsigned block_size,
-                       unsigned iv_size);
-    ~FileTable();
-    FileBase* open_as(const id_type& id, int type);
-    FileBase* create_as(const id_type& id, int type);
-    void close(FileBase*);
-    bool is_readonly() const noexcept { return (m_flags & kOptionReadOnly) != 0; }
-    bool is_auth_enabled() const noexcept { return (m_flags & kOptionNoAuthentication) == 0; }
-    bool is_time_stored() const noexcept { return (m_flags & kOptionStoreTime) != 0; }
-    void gc();
-    void statfs(struct fuse_statvfs* fs_info) { m_root->statfs(fs_info); }
+    explicit ShardedFileTableImpl(int version,
+                                  std::shared_ptr<const OSService> root,
+                                  const key_type& master_key,
+                                  uint32_t flags,
+                                  unsigned block_size,
+                                  unsigned iv_size,
+                                  unsigned max_padding_size);
+    ~ShardedFileTableImpl();
+    FileBase* open_as(const id_type& id, int type) override;
+    FileBase* create_as(const id_type& id, int type) override;
+    void close(FileBase* fb) override;
+    bool is_readonly() const noexcept override { return m_shards.back()->is_readonly(); }
+    bool is_auth_enabled() const noexcept override { return m_shards.back()->is_auth_enabled(); }
+    bool is_time_stored() const noexcept override { return m_shards.back()->is_time_stored(); }
+    void statfs(struct fuse_statvfs* fs_info) { return m_shards.back()->statfs(fs_info); }
+    bool has_padding() const noexcept override { return m_shards.back()->has_padding(); }
 };
 
 class AutoClosedFileBase
diff -pruN 0.11.1+ds-4/sources/fuse_tracer.cpp 0.13.1+ds-1/sources/fuse_tracer.cpp
--- 0.11.1+ds-4/sources/fuse_tracer.cpp	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/sources/fuse_tracer.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,314 @@
+#include "fuse_tracer.h"
+
+#include <cctype>
+#include <ctime>
+
+namespace securefs
+{
+namespace details
+{
+    namespace
+    {
+
+        template <typename StatClass>
+        auto get_atim_helper(const StatClass* st, int) -> decltype(&st->st_atim)
+        {
+            return &st->st_atim;
+        }
+
+        template <typename StatClass>
+        auto get_atim_helper(const StatClass* st, double) -> decltype(&st->st_atimespec)
+        {
+            return &st->st_atimespec;
+        }
+
+        template <typename StatClass>
+        const struct fuse_timespec* get_atim_helper(const StatClass*, ...)
+        {
+            return nullptr;
+        }
+
+        template <typename StatClass>
+        auto get_mtim_helper(const StatClass* st, int) -> decltype(&st->st_mtim)
+        {
+            return &st->st_mtim;
+        }
+
+        template <typename StatClass>
+        auto get_mtim_helper(const StatClass* st, double) -> decltype(&st->st_mtimespec)
+        {
+            return &st->st_mtimespec;
+        }
+
+        template <typename StatClass>
+        const struct fuse_timespec* get_mtim_helper(const StatClass*, ...)
+        {
+            return nullptr;
+        }
+
+        template <typename StatClass>
+        auto get_ctim_helper(const StatClass* st, int) -> decltype(&st->st_ctim)
+        {
+            return &st->st_ctim;
+        }
+
+        template <typename StatClass>
+        auto get_ctim_helper(const StatClass* st, double) -> decltype(&st->st_ctimespec)
+        {
+            return &st->st_ctimespec;
+        }
+
+        template <typename StatClass>
+        const struct fuse_timespec* get_ctim_helper(const StatClass*, ...)
+        {
+            return nullptr;
+        }
+
+        template <typename StatClass>
+        auto get_birthtim_helper(const StatClass* st, int) -> decltype(&st->st_birthtim)
+        {
+            return &st->st_birthtim;
+        }
+
+        template <typename StatClass>
+        auto get_birthtim_helper(const StatClass* st, double) -> decltype(&st->st_birthtimespec)
+        {
+            return &st->st_birthtimespec;
+        }
+
+        template <typename StatClass>
+        const struct fuse_timespec* get_birthtim_helper(const StatClass*, ...)
+        {
+            return nullptr;
+        }
+
+        void print(FILE* fp, const int* v) { fprintf(fp, "%d", *v); }
+        void print(FILE* fp, const unsigned* v) { fprintf(fp, "%u", *v); }
+        void print(FILE* fp, const long* v) { fprintf(fp, "%ld", *v); }
+        void print(FILE* fp, const unsigned long* v) { fprintf(fp, "%lu", *v); }
+        void print(FILE* fp, const long long* v) { fprintf(fp, "%lld", *v); }
+        void print(FILE* fp, const unsigned long long* v) { fprintf(fp, "%llu", *v); }
+
+        void print(FILE* fp, const struct fuse_timespec* v)
+        {
+            std::tm tm;
+#ifdef _WIN32
+            if (gmtime_s(&tm, &v->tv_sec))
+                return;
+#else
+            if (!gmtime_r(&v->tv_sec, &tm))
+                return;
+#endif
+            char buffer[256] = {};
+            std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm);
+            fprintf(fp, "%s.%09d UTC", buffer, static_cast<int>(v->tv_nsec));
+        }
+
+        void print(FILE* fp, const char* v)
+        {
+            fputc('\"', fp);
+            while (*v)
+            {
+                int ch = *v;
+                switch (ch)
+                {
+                case '\"':
+                    fputs("\\\"", fp);
+                    break;
+                case '\'':
+                    fputs("\\\'", fp);
+                    break;
+                case '\\':
+                    fputs("\\\\", fp);
+                    break;
+                case '\a':
+                    fputs("\\a", fp);
+                    break;
+                case '\b':
+                    fputs("\\b", fp);
+                    break;
+                case '\n':
+                    fputs("\\n", fp);
+                    break;
+                case '\t':
+                    fputs("\\t", fp);
+                    break;
+                case '\f':
+                    fputs("\\f", fp);
+                    break;
+                default:
+                    if (ch > 0 && std::iscntrl(ch))
+                        fprintf(fp, "\\x%02x", ch);
+                    else
+                        fputc(ch, fp);
+                }
+                ++v;
+            }
+            fputc('\"', fp);
+        }
+
+        void print(FILE* fp, const struct fuse_stat* v)
+        {
+            fprintf(fp,
+                    "{st_size=%lld, st_mode=%#o, st_nlink=%lld, st_uid=%lld, st_gid=%lld, "
+                    "st_blksize=%lld, st_blocks=%lld",
+                    static_cast<long long>(v->st_size),
+                    static_cast<unsigned>(v->st_mode),
+                    static_cast<long long>(v->st_nlink),
+                    static_cast<long long>(v->st_uid),
+                    static_cast<long long>(v->st_gid),
+                    static_cast<long long>(v->st_blksize),
+                    static_cast<long long>(v->st_blocks));
+
+            auto atim = get_atim_helper(v, 0);
+            if (atim)
+            {
+                fputs(", st_atim=", fp);
+                ::securefs::details::print(fp, atim);
+            }
+            auto mtim = get_mtim_helper(v, 0);
+            if (mtim)
+            {
+                fputs(", st_mtim=", fp);
+                ::securefs::details::print(fp, mtim);
+            }
+            auto ctim = get_ctim_helper(v, 0);
+            if (ctim)
+            {
+                fputs(", st_ctim=", fp);
+                ::securefs::details::print(fp, ctim);
+            }
+            auto birthtim = get_birthtim_helper(v, 0);
+            if (birthtim)
+            {
+                fputs(", st_birthtim=", fp);
+                ::securefs::details::print(fp, birthtim);
+            }
+            fputc('}', fp);
+        }
+
+        void print(FILE* fp, const struct fuse_file_info* v)
+        {
+            fprintf(fp, "{fh=0x%p, flags=%#o}", (const void*)(v->fh), v->flags);
+        }
+
+        void print(FILE* fp, const struct fuse_statvfs* v)
+        {
+            fprintf(fp,
+                    "{f_bsize=%lld, f_frsize=%lld, f_blocks=%lld, f_bfree=%lld, f_bavail=%lld, "
+                    "f_files=%lld, f_ffree=%lld, f_favail=%lld, f_fsid=%lld, f_flag=%lld, "
+                    "f_namemax=%lld}",
+                    static_cast<long long>(v->f_bsize),
+                    static_cast<long long>(v->f_frsize),
+                    static_cast<long long>(v->f_blocks),
+                    static_cast<long long>(v->f_bfree),
+                    static_cast<long long>(v->f_bavail),
+                    static_cast<long long>(v->f_files),
+                    static_cast<long long>(v->f_ffree),
+                    static_cast<long long>(v->f_favail),
+                    static_cast<long long>(v->f_fsid),
+                    static_cast<long long>(v->f_flag),
+                    static_cast<long long>(v->f_namemax));
+        }
+    }    // namespace
+}    // namespace details
+void FuseTracer::print(FILE* fp, const WrappedFuseArg& arg)
+{
+    if (!arg.value)
+    {
+        fputs("null", fp);
+        return;
+    }
+#define SECUREFS_DISPATCH(type)                                                                    \
+    else if (arg.type_index == std::type_index(typeid(type)))                                      \
+    {                                                                                              \
+        ::securefs::details::print(fp, static_cast<const type*>(arg.value));                       \
+    }
+
+    if (0)
+    {
+    }
+    SECUREFS_DISPATCH(char)
+    SECUREFS_DISPATCH(struct fuse_stat)
+    SECUREFS_DISPATCH(int)
+    SECUREFS_DISPATCH(unsigned)
+    SECUREFS_DISPATCH(long)
+    SECUREFS_DISPATCH(unsigned long)
+    SECUREFS_DISPATCH(long long)
+    SECUREFS_DISPATCH(unsigned long long)
+    SECUREFS_DISPATCH(struct fuse_file_info)
+    SECUREFS_DISPATCH(struct fuse_statvfs)
+    SECUREFS_DISPATCH(struct fuse_timespec)
+    else { fprintf(fp, "0x%p", arg.value); }
+#undef SECUREFS_DISPATCH
+}
+
+void FuseTracer::print(FILE* fp, const WrappedFuseArg* args, size_t arg_size)
+{
+    fputc('(', fp);
+    for (size_t i = 0; i < arg_size; ++i)
+    {
+        if (i)
+        {
+            fputs(", ", fp);
+        }
+        print(fp, args[i]);
+    }
+    fputc(')', fp);
+}
+
+void FuseTracer::print_function_starts(
+    Logger* logger, const char* funcsig, int lineno, const WrappedFuseArg* args, size_t arg_size)
+{
+    if (logger && logger->get_level() <= LoggingLevel::kLogTrace)
+    {
+        logger->prelog(LoggingLevel::kLogTrace, funcsig, lineno);
+        DEFER(logger->postlog(LoggingLevel::kLogTrace));
+
+        fputs("Function starts with arguments ", logger->m_fp);
+        print(logger->m_fp, args, arg_size);
+    }
+}
+
+void FuseTracer::print_function_returns(Logger* logger,
+                                        const char* funcsig,
+                                        int lineno,
+                                        const WrappedFuseArg* args,
+                                        size_t arg_size,
+                                        long long rc)
+{
+    if (logger && logger->get_level() <= LoggingLevel::kLogTrace)
+    {
+        logger->prelog(LoggingLevel::kLogTrace, funcsig, lineno);
+        DEFER(logger->postlog(LoggingLevel::kLogTrace));
+
+        fputs("Function ends with arguments ", logger->m_fp);
+        print(logger->m_fp, args, arg_size);
+        fprintf(logger->m_fp, " and return code %lld", rc);
+    }
+}
+
+void FuseTracer::print_function_exception(Logger* logger,
+                                          const char* funcsig,
+                                          int lineno,
+                                          const WrappedFuseArg* args,
+                                          size_t arg_size,
+                                          const std::exception& e,
+                                          int rc)
+{
+    if (logger && logger->get_level() <= LoggingLevel::kLogError)
+    {
+        logger->prelog(LoggingLevel::kLogError, funcsig, lineno);
+        DEFER(logger->postlog(LoggingLevel::kLogError));
+
+        fputs("Function fails with arguments ", logger->m_fp);
+        print(logger->m_fp, args, arg_size);
+        fprintf(logger->m_fp,
+                " with return code %d because it encounters exception %s: %s",
+                rc,
+                get_type_name(e).get(),
+                e.what());
+    }
+}
+
+}    // namespace securefs
diff -pruN 0.11.1+ds-4/sources/fuse_tracer.h 0.13.1+ds-1/sources/fuse_tracer.h
--- 0.11.1+ds-4/sources/fuse_tracer.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/sources/fuse_tracer.h	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,85 @@
+#pragma once
+#include "logger.h"
+#include "platform.h"
+
+#include <cstdio>
+#include <type_traits>
+#include <typeindex>
+#include <typeinfo>
+
+namespace securefs
+{
+struct WrappedFuseArg
+{
+    std::type_index type_index;
+    const void* value;
+
+    template <class T>
+    WrappedFuseArg(T* value) : type_index(typeid(T)), value(value)
+    {
+    }
+};
+
+class FuseTracer
+{
+private:
+    static void print(FILE* fp, const WrappedFuseArg& arg);
+    static void print(FILE* fp, const WrappedFuseArg* args, size_t arg_size);
+
+    static void print_function_starts(Logger* logger,
+                                      const char* funcsig,
+                                      int lineno,
+                                      const WrappedFuseArg* args,
+                                      size_t arg_size);
+
+    static void print_function_returns(Logger* logger,
+                                       const char* funcsig,
+                                       int lineno,
+                                       const WrappedFuseArg* args,
+                                       size_t arg_size,
+                                       long long rc);
+
+    static void print_function_exception(Logger* logger,
+                                         const char* funcsig,
+                                         int lineno,
+                                         const WrappedFuseArg* args,
+                                         size_t arg_size,
+                                         const std::exception& e,
+                                         int rc);
+
+public:
+    template <class ActualFunction>
+    static inline auto traced_call(ActualFunction&& func,
+                                   const char* funcsig,
+                                   int lineno,
+                                   const std::initializer_list<WrappedFuseArg>& args,
+                                   Logger* logger = global_logger) -> decltype(func())
+    {
+        print_function_starts(logger, funcsig, lineno, args.begin(), args.size());
+        try
+        {
+            auto rc = func();
+            print_function_returns(logger, funcsig, lineno, args.begin(), args.size(), rc);
+            return rc;
+        }
+        catch (const VFSException& e)
+        {
+            int rc = -e.error_number();
+            print_function_returns(logger, funcsig, lineno, args.begin(), args.size(), rc);
+            return rc;
+        }
+        catch (const ExceptionBase& e)
+        {
+            int rc = -e.error_number();
+            print_function_exception(logger, funcsig, lineno, args.begin(), args.size(), e, rc);
+            return rc;
+        }
+        catch (const std::exception& e)
+        {
+            int rc = -EPERM;
+            print_function_exception(logger, funcsig, lineno, args.begin(), args.size(), e, rc);
+            return rc;
+        }
+    }
+};
+}    // namespace securefs
diff -pruN 0.11.1+ds-4/sources/lite_fs.cpp 0.13.1+ds-1/sources/lite_fs.cpp
--- 0.11.1+ds-4/sources/lite_fs.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/lite_fs.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -12,16 +12,6 @@ namespace securefs
 {
 namespace lite
 {
-    File::File(std::shared_ptr<securefs::FileStream> file_stream,
-               const key_type& master_key,
-               unsigned block_size,
-               unsigned iv_size,
-               bool check)
-        : m_file_stream(file_stream)
-    {
-        LockGuard<FileStream> lock_guard(*m_file_stream, true);
-        m_crypt_stream.emplace(file_stream, master_key, block_size, iv_size, check);
-    }
 
     File::~File() {}
 
@@ -36,14 +26,18 @@ namespace lite
                            const key_type& name_key,
                            const key_type& content_key,
                            const key_type& xattr_key,
+                           const key_type& padding_key,
                            unsigned block_size,
                            unsigned iv_size,
+                           unsigned max_padding_size,
                            unsigned flags)
-        : m_name_encryptor(name_key.data(), name_key.size())
+        : m_name_encryptor(std::make_shared<AES_SIV>(name_key.data(), name_key.size()))
         , m_content_key(content_key)
+        , m_padding_aes(padding_key.data(), padding_key.size())
         , m_root(std::move(root))
         , m_block_size(block_size)
         , m_iv_size(iv_size)
+        , m_max_padding_size(max_padding_size)
         , m_flags(flags)
     {
         byte null_iv[12] = {0};
@@ -150,7 +144,7 @@ namespace lite
         else
         {
             std::string str = lite::encrypt_path(
-                m_name_encryptor,
+                *m_name_encryptor,
                 transform(path, m_flags & kOptionCaseFoldFileName, m_flags & kOptionNFCFileName)
                     .get());
             if (!preserve_leading_slash && !str.empty() && str[0] == '/')
@@ -186,7 +180,9 @@ namespace lite
                                    m_content_key,
                                    m_block_size,
                                    m_iv_size,
-                                   (m_flags & kOptionNoAuthentication) == 0));
+                                   (m_flags & kOptionNoAuthentication) == 0,
+                                   m_max_padding_size,
+                                   &m_padding_aes));
         if (flags & O_TRUNC)
         {
             LockGuard<File> lock_guard(*fp, true);
@@ -219,15 +215,43 @@ namespace lite
             // Resize to actual size
             buffer.resize(static_cast<size_t>(link_size));
 
-            auto resolved = decrypt_path(m_name_encryptor, buffer);
+            auto resolved = decrypt_path(*m_name_encryptor, buffer);
             buf->st_size = resolved.size();
             break;
         }
         case S_IFDIR:
             break;
         case S_IFREG:
-            buf->st_size
-                = AESGCMCryptStream::calculate_real_size(buf->st_size, m_block_size, m_iv_size);
+            if (buf->st_size > 0)
+            {
+                if (m_max_padding_size <= 0)
+                {
+                    buf->st_size = AESGCMCryptStream::calculate_real_size(
+                        buf->st_size, m_block_size, m_iv_size);
+                }
+                else
+                {
+                    try
+                    {
+                        auto fs = m_root->open_file_stream(enc_path, O_RDONLY, 0);
+                        AESGCMCryptStream stream(std::move(fs),
+                                                 m_content_key,
+                                                 m_block_size,
+                                                 m_iv_size,
+                                                 (m_flags & kOptionNoAuthentication) == 0,
+                                                 m_max_padding_size,
+                                                 &m_padding_aes);
+                        buf->st_size = stream.size();
+                    }
+                    catch (const std::exception& e)
+                    {
+                        ERROR_LOG("Encountered exception %s when opening file %s for read: %s",
+                                  get_type_name(e).get(),
+                                  path.c_str(),
+                                  e.what());
+                    }
+                }
+            }
             break;
         default:
             throwVFSException(ENOTSUP);
@@ -276,7 +300,7 @@ namespace lite
         auto underbuf = securefs::make_unique_array<char>(max_size);
         memset(underbuf.get(), 0, max_size);
         m_root->readlink(translate_path(path, false), underbuf.get(), max_size - 1);
-        std::string resolved = decrypt_path(m_name_encryptor, underbuf.get());
+        std::string resolved = decrypt_path(*m_name_encryptor, underbuf.get());
         size_t copy_size = std::min(resolved.size(), size - 1);
         memcpy(buf, resolved.data(), copy_size);
         buf[copy_size] = '\0';
@@ -303,29 +327,38 @@ namespace lite
 
     void FileSystem::statvfs(struct fuse_statvfs* buf) { m_root->statfs(buf); }
 
-    class LiteDirectoryTraverser : public DirectoryTraverser
+    class THREAD_ANNOTATION_CAPABILITY("mutex") LiteDirectory final : public Directory
     {
     private:
-        std::unique_ptr<DirectoryTraverser> m_underlying_traverser;
-        AES_SIV m_name_encryptor;
+        std::string m_path;
+        std::unique_ptr<DirectoryTraverser>
+            m_underlying_traverser THREAD_ANNOTATION_GUARDED_BY(*this);
+        std::shared_ptr<AES_SIV> m_name_encryptor;
         unsigned m_block_size, m_iv_size;
 
     public:
-        explicit LiteDirectoryTraverser(std::unique_ptr<DirectoryTraverser> underlying_traverser,
-                                        const AES_SIV& name_encryptor,
-                                        unsigned block_size,
-                                        unsigned iv_size)
-            : m_underlying_traverser(std::move(underlying_traverser))
-            , m_name_encryptor(name_encryptor)
+        explicit LiteDirectory(std::string path,
+                               std::unique_ptr<DirectoryTraverser> underlying_traverser,
+                               std::shared_ptr<AES_SIV> name_encryptor,
+                               unsigned block_size,
+                               unsigned iv_size)
+            : m_path(std::move(path))
+            , m_underlying_traverser(std::move(underlying_traverser))
+            , m_name_encryptor(std::move(name_encryptor))
             , m_block_size(block_size)
             , m_iv_size(iv_size)
         {
         }
-        ~LiteDirectoryTraverser() {}
 
-        void rewind() override { m_underlying_traverser->rewind(); }
+        StringRef path() const override { return m_path; }
+
+        void rewind() override THREAD_ANNOTATION_REQUIRES(*this)
+        {
+            m_underlying_traverser->rewind();
+        }
 
         bool next(std::string* name, struct fuse_stat* stbuf) override
+            THREAD_ANNOTATION_REQUIRES(*this)
         {
             std::string under_name, decoded_bytes;
 
@@ -356,12 +389,12 @@ namespace lite
                     }
                     name->assign(decoded_bytes.size() - AES_SIV::IV_SIZE, '\0');
                     bool success
-                        = m_name_encryptor.decrypt_and_verify(&decoded_bytes[AES_SIV::IV_SIZE],
-                                                              name->size(),
-                                                              nullptr,
-                                                              0,
-                                                              &(*name)[0],
-                                                              &decoded_bytes[0]);
+                        = m_name_encryptor->decrypt_and_verify(&decoded_bytes[AES_SIV::IV_SIZE],
+                                                               name->size(),
+                                                               nullptr,
+                                                               0,
+                                                               &(*name)[0],
+                                                               &decoded_bytes[0]);
                     if (!success)
                     {
                         WARN_LOG("Skipping filename %s (decrypted to %s) since it fails "
@@ -386,30 +419,42 @@ namespace lite
         }
     };
 
-    std::unique_ptr<DirectoryTraverser> FileSystem::create_traverser(StringRef path)
+    std::unique_ptr<Directory> FileSystem::opendir(StringRef path)
     {
         if (path.empty())
             throwVFSException(EINVAL);
-        return securefs::make_unique<LiteDirectoryTraverser>(
+        return securefs::make_unique<LiteDirectory>(
+            path.to_string(),
             m_root->create_traverser(translate_path(path, false)),
             this->m_name_encryptor,
             m_block_size,
             m_iv_size);
     }
 
+    Base::~Base() {}
+
 #ifdef __APPLE__
     ssize_t
     FileSystem::getxattr(const char* path, const char* name, void* buf, size_t size) noexcept
     {
+        auto iv_size = m_iv_size;
+        auto mac_size = AESGCMCryptStream::get_mac_size();
         if (!buf)
         {
-            return m_root->getxattr(translate_path(path, false).c_str(), name, nullptr, 0);
+            auto rc = m_root->getxattr(translate_path(path, false).c_str(), name, nullptr, 0);
+            if (rc < 0)
+            {
+                return rc;
+            }
+            if (rc <= iv_size + mac_size)
+            {
+                return 0;
+            }
+            return rc - iv_size - mac_size;
         }
 
         try
         {
-            auto iv_size = m_iv_size;
-            auto mac_size = AESGCMCryptStream::get_mac_size();
             auto underbuf = securefs::make_unique_array<byte>(size + iv_size + mac_size);
             ssize_t readlen = m_root->getxattr(translate_path(path, false).c_str(),
                                                name,
@@ -482,6 +527,7 @@ namespace lite
             return -EIO;
         }
     }
+
 #endif
 }    // namespace lite
 }    // namespace securefs
diff -pruN 0.11.1+ds-4/sources/lite_fs.h 0.13.1+ds-1/sources/lite_fs.h
--- 0.11.1+ds-4/sources/lite_fs.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/lite_fs.h	2023-01-27 02:25:50.000000000 +0000
@@ -1,7 +1,9 @@
 #pragma once
 
+#include "constants.h"
 #include "crypto.h"
 #include "lite_stream.h"
+#include "lock_guard.h"
 #include "mystring.h"
 #include "myutils.h"
 #include "platform.h"
@@ -20,7 +22,38 @@ namespace securefs
 {
 namespace lite
 {
-    class THREAD_ANNOTATION_CAPABILITY("mutex") File
+    class File;
+    class Directory;
+
+    class Base
+    {
+    public:
+        Base() {}
+        virtual ~Base() = 0;
+        virtual File* as_file() noexcept { return nullptr; }
+        virtual Directory* as_dir() noexcept { return nullptr; }
+    };
+
+    class THREAD_ANNOTATION_CAPABILITY("mutex") Directory : public Base, public DirectoryTraverser
+    {
+    private:
+        securefs::Mutex m_lock;
+
+    public:
+        void lock() THREAD_ANNOTATION_ACQUIRE() { m_lock.lock(); }
+        void unlock() noexcept THREAD_ANNOTATION_RELEASE() { m_lock.unlock(); }
+        Directory* as_dir() noexcept { return this; }
+
+        // Obtains the (virtual) path of the directory.
+        virtual StringRef path() const = 0;
+
+        // Redeclare the methods in `DirectoryTraverser` to add thread safe annotations.
+        virtual bool next(std::string* name, struct fuse_stat* st) THREAD_ANNOTATION_REQUIRES(*this)
+            = 0;
+        virtual void rewind() THREAD_ANNOTATION_REQUIRES(*this) = 0;
+    };
+
+    class THREAD_ANNOTATION_CAPABILITY("mutex") File final : public Base
     {
         DISABLE_COPY_MOVE(File)
 
@@ -28,14 +61,17 @@ namespace lite
         securefs::optional<lite::AESGCMCryptStream>
             m_crypt_stream THREAD_ANNOTATION_GUARDED_BY(*this);
         std::shared_ptr<securefs::FileStream> m_file_stream THREAD_ANNOTATION_GUARDED_BY(*this);
-        std::mutex m_lock;
+        securefs::Mutex m_lock;
 
     public:
-        explicit File(std::shared_ptr<securefs::FileStream> file_stream,
-                      const key_type& master_key,
-                      unsigned block_size,
-                      unsigned iv_size,
-                      bool check);
+        template <typename... Args>
+        File(std::shared_ptr<securefs::FileStream> file_stream, Args&&... args)
+            : m_file_stream(file_stream)
+        {
+            LockGuard<FileStream> lock_guard(*m_file_stream, true);
+            m_crypt_stream.emplace(file_stream, std::forward<Args>(args)...);
+        }
+
         ~File();
 
         length_type size() const THREAD_ANNOTATION_REQUIRES(*this)
@@ -85,6 +121,7 @@ namespace lite
             m_file_stream->unlock();
             m_lock.unlock();
         }
+        File* as_file() noexcept override { return this; }
     };
 
     class FileSystem;
@@ -112,12 +149,13 @@ namespace lite
         DISABLE_COPY_MOVE(FileSystem)
 
     private:
-        AES_SIV m_name_encryptor;
+        std::shared_ptr<AES_SIV> m_name_encryptor;
         key_type m_content_key;
         CryptoPP::GCM<CryptoPP::AES>::Encryption m_xattr_enc;
         CryptoPP::GCM<CryptoPP::AES>::Decryption m_xattr_dec;
+        CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption m_padding_aes;
         std::shared_ptr<const securefs::OSService> m_root;
-        unsigned m_block_size, m_iv_size;
+        unsigned m_block_size, m_iv_size, m_max_padding_size;
         unsigned m_flags;
 
     private:
@@ -128,8 +166,10 @@ namespace lite
                    const key_type& name_key,
                    const key_type& content_key,
                    const key_type& xattr_key,
+                   const key_type& padding_key,
                    unsigned block_size,
                    unsigned iv_size,
+                   unsigned max_padding_size,
                    unsigned flags);
 
         ~FileSystem();
@@ -147,7 +187,10 @@ namespace lite
         size_t readlink(StringRef path, char* buf, size_t size);
         void utimens(StringRef path, const fuse_timespec tm[2]);
         void statvfs(struct fuse_statvfs* buf);
-        std::unique_ptr<DirectoryTraverser> create_traverser(StringRef path);
+        std::unique_ptr<Directory> opendir(StringRef path);
+
+        bool has_padding() const noexcept { return m_max_padding_size > 0; }
+        bool skip_dot_dot() const noexcept { return m_flags & kOptionSkipDotDot; }
 
 #ifdef __APPLE__
         // These APIs, unlike all others, report errors through negative error numbers as defined in
diff -pruN 0.11.1+ds-4/sources/lite_operations.cpp 0.13.1+ds-1/sources/lite_operations.cpp
--- 0.11.1+ds-4/sources/lite_operations.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/lite_operations.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -1,5 +1,6 @@
 #include "lite_operations.h"
 #include "apple_xattr_workaround.h"
+#include "fuse_tracer.h"
 #include "lite_fs.h"
 #include "lite_stream.h"
 #include "lock_guard.h"
@@ -8,90 +9,104 @@
 #include "operations.h"
 #include "platform.h"
 
-#include <securefs_config.h>
-
-#include <math.h>
-
-#if !HAS_THREAD_LOCAL
-#include <pthread.h>
-#endif
-
 namespace securefs
 {
 namespace lite
 {
-    struct BundledContext
+    namespace
     {
-        ::securefs::operations::MountOptions* opt;
-#if !HAS_THREAD_LOCAL
-        ::pthread_key_t key;
-#endif
-    };
+        struct BundledContext
+        {
+            ::securefs::operations::MountOptions* opt;
+        };
 
-#if HAS_THREAD_LOCAL
-    static thread_local optional<FileSystem> opt_fs;
-#endif
+        FileSystem* get_local_filesystem()
+        {
+            static thread_local optional<FileSystem> opt_fs;
 
-    FileSystem* get_local_filesystem(void)
-    {
-#if HAS_THREAD_LOCAL
-        if (opt_fs)
-            return &(*opt_fs);
-#endif
+            auto& local_opt_fs = opt_fs;
+            if (local_opt_fs)
+                return &(*local_opt_fs);
+            auto ctx = static_cast<BundledContext*>(fuse_get_context()->private_data);
 
-        auto ctx = static_cast<BundledContext*>(fuse_get_context()->private_data);
+            if (ctx->opt->version.value() != 4)
+                throwInvalidArgumentException("This function only supports filesystem format 4");
 
-#if !HAS_THREAD_LOCAL
-        auto fs = static_cast<FileSystem*>(::pthread_getspecific(ctx->key));
-        if (fs)
-            return fs;
-#endif
+            const auto& master_key = ctx->opt->master_key;
 
-        if (ctx->opt->version.value() != 4)
-            throwInvalidArgumentException("This function only supports filesystem format 4");
+            key_type name_key, content_key, xattr_key, padding_key;
+            if (master_key.size() != 3 * KEY_LENGTH && master_key.size() != 4 * KEY_LENGTH)
+                throwInvalidArgumentException("Master key has wrong length");
 
-        key_type name_key, content_key, xattr_key;
-        if (ctx->opt->master_key.size() != 3 * KEY_LENGTH)
-            throwInvalidArgumentException("Master key has wrong length");
-
-        memcpy(name_key.data(), ctx->opt->master_key.data(), KEY_LENGTH);
-        memcpy(content_key.data(), ctx->opt->master_key.data() + KEY_LENGTH, KEY_LENGTH);
-        memcpy(xattr_key.data(), ctx->opt->master_key.data() + 2 * KEY_LENGTH, KEY_LENGTH);
-
-        warn_if_key_not_random(name_key, __FILE__, __LINE__);
-        warn_if_key_not_random(content_key, __FILE__, __LINE__);
-        warn_if_key_not_random(xattr_key, __FILE__, __LINE__);
-
-#if HAS_THREAD_LOCAL
-        opt_fs.emplace(ctx->opt->root,
-                       name_key,
-                       content_key,
-                       xattr_key,
-                       ctx->opt->block_size.value(),
-                       ctx->opt->iv_size.value(),
-                       ctx->opt->flags.value());
-        return &(*opt_fs);
-#else
-        std::unique_ptr<FileSystem> guard(new FileSystem(ctx->opt->root,
-                                                         name_key,
-                                                         content_key,
-                                                         xattr_key,
-                                                         ctx->opt->block_size.value(),
-                                                         ctx->opt->iv_size.value(),
-                                                         ctx->opt->flags.value()));
-        int rc = ::pthread_setspecific(ctx->key, guard.get());
-        if (rc)
-            THROW_POSIX_EXCEPTION(rc, "pthread_setspecific");
-        return guard.release();
-#endif
-    }
+            memcpy(name_key.data(), master_key.data(), KEY_LENGTH);
+            memcpy(content_key.data(), master_key.data() + KEY_LENGTH, KEY_LENGTH);
+            memcpy(xattr_key.data(), master_key.data() + 2 * KEY_LENGTH, KEY_LENGTH);
+
+            warn_if_key_not_random(name_key, __FILE__, __LINE__);
+            warn_if_key_not_random(content_key, __FILE__, __LINE__);
+            warn_if_key_not_random(xattr_key, __FILE__, __LINE__);
+            if (master_key.size() >= 4 * KEY_LENGTH)
+            {
+                memcpy(padding_key.data(), master_key.data() + 3 * KEY_LENGTH, KEY_LENGTH);
+            }
+            if (ctx->opt->max_padding_size > 0)
+            {
+                warn_if_key_not_random(padding_key, __FILE__, __LINE__);
+            }
+
+            TRACE_LOG("\nname_key: %s\ncontent_key: %s\nxattr_key: %s\npadding_key: %s",
+                      hexify(name_key).c_str(),
+                      hexify(content_key).c_str(),
+                      hexify(xattr_key).c_str(),
+                      hexify(padding_key).c_str());
+
+            local_opt_fs.emplace(ctx->opt->root,
+                                 name_key,
+                                 content_key,
+                                 xattr_key,
+                                 padding_key,
+                                 ctx->opt->block_size.value(),
+                                 ctx->opt->iv_size.value(),
+                                 ctx->opt->max_padding_size,
+                                 ctx->opt->flags.value());
+            return &(*local_opt_fs);
+        }
+
+        void set_file_handle(struct fuse_file_info* info, securefs::lite::Base* base)
+        {
+            info->fh = reinterpret_cast<uintptr_t>(base);
+        }
+
+        Base* get_base_handle(const struct fuse_file_info* info)
+        {
+            if (!info->fh)
+            {
+                throwVFSException(EFAULT);
+            }
+            return reinterpret_cast<Base*>(static_cast<uintptr_t>(info->fh));
+        }
 
-#define SINGLE_COMMON_PROLOGUE                                                                     \
-    auto filesystem = get_local_filesystem();                                                      \
-    OPT_TRACE_WITH_PATH;
+        File* get_handle_as_file_checked(const struct fuse_file_info* info)
+        {
+            auto fp = get_base_handle(info)->as_file();
+            if (!fp)
+            {
+                throwVFSException(EISDIR);
+            }
+            return fp;
+        }
 
-#define SINGLE_COMMON_EPILOGUE OPT_CATCH_WITH_PATH
+        Directory* get_handle_as_dir_checked(const struct fuse_file_info* info)
+        {
+            auto fp = get_base_handle(info)->as_dir();
+            if (!fp)
+            {
+                throwVFSException(ENOTDIR);
+            }
+            return fp;
+        }
 
+    }    // namespace
     void* init(struct fuse_conn_info* fsinfo)
     {
         (void)fsinfo;
@@ -102,13 +117,6 @@ namespace lite
         INFO_LOG("init");
         auto ctx = new BundledContext;
         ctx->opt = static_cast<operations::MountOptions*>(args);
-
-#if !HAS_THREAD_LOCAL
-        int rc = ::pthread_key_create(&ctx->key,
-                                      [](void* p) { delete static_cast<lite::FileSystem*>(p); });
-        if (rc)
-            THROW_POSIX_EXCEPTION(rc, "pthread_key_create");
-#endif
         return ctx;
     }
 
@@ -120,72 +128,92 @@ namespace lite
 
     int statfs(const char* path, struct fuse_statvfs* buf)
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
             if (!buf)
                 return -EFAULT;
+            auto filesystem = get_local_filesystem();
             filesystem->statvfs(buf);
             // Due to the Base32 encoding and the extra 16 bytes of synthesized IV
             buf->f_namemax = buf->f_namemax * 5 / 8 - 16;
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {buf}});
     }
 
     int getattr(const char* path, struct fuse_stat* st)
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             if (!filesystem->stat(path, st))
                 return -ENOENT;
-            TRACE_LOG("stat (%s): mode=0%o, uid=%u, gid=%u, size=%zu",
-                      path,
-                      st->st_mode,
-                      (unsigned)st->st_uid,
-                      (unsigned)st->st_gid,
-                      (size_t)st->st_size);
+
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {st}});
+    }
+
+    int fgetattr(const char* path, struct fuse_stat* st, struct fuse_file_info* info)
+    {
+        auto func = [=]()
+        {
+            auto base = get_base_handle(info);
+            auto file = base->as_file();
+            if (file)
+            {
+                LockGuard<File> lock_guard(*file, false);
+                file->fstat(st);
+                return 0;
+            }
+            auto dir = base->as_dir();
+            if (dir)
+            {
+                auto filesystem = get_local_filesystem();
+                if (!filesystem->stat(dir->path(), st))
+                    return -ENOENT;
+                return 0;
+            }
+            throwInvalidArgumentException("Neither file nor dir");
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {st}, {info}});
     }
 
     int opendir(const char* path, struct fuse_file_info* info)
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
-            auto traverser = filesystem->create_traverser(path);
-            info->fh = reinterpret_cast<uintptr_t>(traverser.release());
+            auto filesystem = get_local_filesystem();
+            auto traverser = filesystem->opendir(path);
+            set_file_handle(info, traverser.release());
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {info}});
     }
 
     int releasedir(const char* path, struct fuse_file_info* info)
     {
-        TRACE_LOG("%s %s", __func__, path);
-        try
+        auto func = [=]()
         {
-            delete reinterpret_cast<DirectoryTraverser*>(info->fh);
+            delete get_base_handle(info);
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {info}});
     }
 
     int readdir(const char* path,
                 void* buf,
                 fuse_fill_dir_t filler,
-                fuse_off_t,
+                fuse_off_t off,
                 struct fuse_file_info* info)
     {
-        OPT_TRACE_WITH_PATH;
-        try
+        auto func = [=]()
         {
-            auto traverser = reinterpret_cast<DirectoryTraverser*>(info->fh);
+            auto fs = get_local_filesystem();
+            auto traverser = get_handle_as_dir_checked(info);
             if (!traverser)
                 return -EFAULT;
+            LockGuard<Directory> lock_guard(*traverser);
             traverser->rewind();
             std::string name;
             struct fuse_stat stbuf;
@@ -193,70 +221,74 @@ namespace lite
 
             while (traverser->next(&name, &stbuf))
             {
-#ifndef _WIN32
-                if (name == "." || name == "..")
+                if (fs->skip_dot_dot() && (name == "." || name == ".."))
                 {
                     continue;
                 }
-#endif
-                int rc = filler(buf, name.c_str(), &stbuf, 0);
+                int rc =
+                    // When random padding is enabled, we cannot obtain accurate size information
+                    fs->has_padding() && (stbuf.st_mode & S_IFMT) == S_IFREG
+                    ? filler(buf, name.c_str(), nullptr, 0)
+                    : filler(buf, name.c_str(), &stbuf, 0);
                 if (rc != 0)
                     return -abs(rc);
             }
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func,
+                                       FULL_FUNCTION_NAME,
+                                       __LINE__,
+                                       {{path}, {buf}, {(const void*)filler}, {&off}, {info}});
     }
 
     int create(const char* path, fuse_mode_t mode, struct fuse_file_info* info)
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             AutoClosedFile file = filesystem->open(path, O_RDWR | O_CREAT | O_EXCL, mode);
-            info->fh = reinterpret_cast<uintptr_t>(file.release());
+            set_file_handle(info, file.release());
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&mode}, {info}});
     }
 
     int open(const char* path, struct fuse_file_info* info)
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             AutoClosedFile file = filesystem->open(path, info->flags, 0644);
-            info->fh = reinterpret_cast<uintptr_t>(file.release());
+            set_file_handle(info, file.release());
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {info}});
     }
 
     int release(const char* path, struct fuse_file_info* info)
     {
-        TRACE_LOG("%s %s", __func__, path);
-        try
+        auto func = [=]()
         {
-            delete reinterpret_cast<File*>(info->fh);
+            delete get_base_handle(info);
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {info}});
     }
 
     int
     read(const char* path, char* buf, size_t size, fuse_off_t offset, struct fuse_file_info* info)
     {
-        OPT_TRACE_WITH_PATH_OFF_LEN(offset, size);
-        auto fp = reinterpret_cast<File*>(info->fh);
-        if (!fp)
-            return -EFAULT;
-
-        try
+        auto func = [=]()
         {
+            auto fp = get_handle_as_file_checked(info);
             LockGuard<File> lock_guard(*fp, false);
             return static_cast<int>(fp->read(buf, offset, size));
-        }
-        OPT_CATCH_WITH_PATH_OFF_LEN(offset, size)
+        };
+        return FuseTracer::traced_call(func,
+                                       FULL_FUNCTION_NAME,
+                                       __LINE__,
+                                       {{path}, {(const void*)buf}, {&size}, {&offset}, {info}});
     }
 
     int write(const char* path,
@@ -265,253 +297,231 @@ namespace lite
               fuse_off_t offset,
               struct fuse_file_info* info)
     {
-        OPT_TRACE_WITH_PATH_OFF_LEN(offset, size);
-        auto fp = reinterpret_cast<File*>(info->fh);
-        if (!fp)
-            return -EFAULT;
-
-        try
+        auto func = [=]()
         {
+            auto fp = get_handle_as_file_checked(info);
             LockGuard<File> lock_guard(*fp, true);
             fp->write(buf, offset, size);
             return static_cast<int>(size);
-        }
-        OPT_CATCH_WITH_PATH_OFF_LEN(offset, size)
+        };
+        return FuseTracer::traced_call(func,
+                                       FULL_FUNCTION_NAME,
+                                       __LINE__,
+                                       {{path}, {(const void*)buf}, {&size}, {&offset}, {info}});
     }
 
     int flush(const char* path, struct fuse_file_info* info)
     {
-        TRACE_LOG("%s %s", __func__, path);
-        auto fp = reinterpret_cast<File*>(info->fh);
-        if (!fp)
-            return -EFAULT;
-
-        try
+        auto func = [=]()
         {
+            auto fp = get_handle_as_file_checked(info);
             LockGuard<File> lock_guard(*fp, true);
             fp->flush();
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {info}});
     }
 
     int ftruncate(const char* path, fuse_off_t len, struct fuse_file_info* info)
     {
-        TRACE_LOG("%s %s with length=%lld", __func__, path, static_cast<long long>(len));
-        auto fp = reinterpret_cast<File*>(info->fh);
-        if (!fp)
-            return -EFAULT;
-
-        try
+        auto func = [=]()
         {
+            auto fp = get_handle_as_file_checked(info);
             LockGuard<File> lock_guard(*fp, true);
             fp->resize(len);
             return 0;
-        }
-        catch (const std::exception& e)
-        {
-            auto ebase = dynamic_cast<const ExceptionBase*>(&e);
-            auto code = ebase ? ebase->error_number() : EPERM;
-            ERROR_LOG("%s %s (length=%lld) encounters exception %s (code=%d): %s",
-                      __func__,
-                      path,
-                      static_cast<long long>(len),
-                      get_type_name(e).get(),
-                      code,
-                      e.what());
-            return -code;
-        }
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&len}, {info}});
     }
 
     int unlink(const char* path)
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             filesystem->unlink(path);
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}});
     }
 
     int mkdir(const char* path, fuse_mode_t mode)
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
-            filesystem->mkdir(path, mode);
-            return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+            try
+            {
+                auto filesystem = get_local_filesystem();
+                filesystem->mkdir(path, mode);
+                return 0;
+            }
+            catch (const ExceptionBase& e)
+            {
+                if (e.error_number() == EEXIST)
+                {
+                    // This occurs frequently and is not worth logging.
+                    return -EEXIST;
+                }
+                throw;
+            }
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&mode}});
     }
 
     int rmdir(const char* path)
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             filesystem->rmdir(path);
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}});
     }
 
     int chmod(const char* path, fuse_mode_t mode)
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             filesystem->chmod(path, mode);
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&mode}});
     }
 
     int chown(const char* path, fuse_uid_t uid, fuse_gid_t gid)
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             filesystem->chown(path, uid, gid);
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&uid}, {&gid}});
     }
 
     int symlink(const char* to, const char* from)
     {
-        auto filesystem = get_local_filesystem();
-        OPT_TRACE_WITH_TWO_PATHS(to, from);
-
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             filesystem->symlink(to, from);
             return 0;
-        }
-        OPT_CATCH_WITH_TWO_PATHS(to, from)
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{to}, {from}});
     }
 
     int link(const char* src, const char* dest)
     {
-        auto filesystem = get_local_filesystem();
-        OPT_TRACE_WITH_TWO_PATHS(src, dest);
-
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             filesystem->link(src, dest);
             return 0;
-        }
-        OPT_CATCH_WITH_TWO_PATHS(src, dest)
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{src}, {dest}});
     }
 
     int readlink(const char* path, char* buf, size_t size)
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             (void)filesystem->readlink(path, buf, size);
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {(const void*)buf}, {&size}});
     }
 
     int rename(const char* from, const char* to)
     {
-        auto filesystem = get_local_filesystem();
-        OPT_TRACE_WITH_TWO_PATHS(from, to);
-
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             filesystem->rename(from, to);
             return 0;
-        }
-        OPT_CATCH_WITH_TWO_PATHS(from, to)
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{from}, {to}});
     }
 
-    int fsync(const char* path, int, struct fuse_file_info* info)
+    int fsync(const char* path, int datasync, struct fuse_file_info* info)
     {
-        TRACE_LOG("%s %s", __func__, path);
-        auto fp = reinterpret_cast<File*>(info->fh);
-        if (!fp)
-            return -EFAULT;
-
-        try
+        auto func = [=]()
         {
+            auto fp = get_handle_as_file_checked(info);
             LockGuard<File> lock_guard(*fp, true);
             fp->fsync();
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&datasync}, {info}});
     }
 
     int truncate(const char* path, fuse_off_t len)
     {
-        if (len < 0)
-            return -EINVAL;
-
-        TRACE_LOG("%s %s (len=%lld)", __func__, path, static_cast<long long>(len));
-        auto filesystem = get_local_filesystem();
-
-        try
+        auto func = [=]()
         {
+            if (len < 0)
+                return -EINVAL;
+            auto filesystem = get_local_filesystem();
+
             AutoClosedFile fp = filesystem->open(path, O_RDWR, 0644);
             LockGuard<File> lock_guard(*fp, true);
             fp->resize(static_cast<size_t>(len));
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&len}});
     }
 
     int utimens(const char* path, const struct fuse_timespec ts[2])
     {
-        SINGLE_COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
+            auto filesystem = get_local_filesystem();
             filesystem->utimens(path, ts);
             return 0;
-        }
-        SINGLE_COMMON_EPILOGUE
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {ts}, {ts ? ts + 1 : ts}});
     }
 
 #ifdef __APPLE__
     int listxattr(const char* path, char* list, size_t size)
     {
-        TRACE_LOG("%s %s", __func__, path);
-        auto filesystem = get_local_filesystem();
-        int rc = static_cast<int>(filesystem->listxattr(path, list, size));
-        transform_listxattr_result(list, size);
-        if (rc < 0)
-        {
-            TRACE_LOG("%s %s encountered error: %d (%s)",
-                      __func__,
-                      path,
-                      -rc,
-                      OSService::stringify_system_error(-rc).c_str());
-        }
-        return rc;
+        auto func = [=]()
+        {
+            auto filesystem = get_local_filesystem();
+            int rc = static_cast<int>(filesystem->listxattr(path, list, size));
+            transform_listxattr_result(list, size);
+            return rc;
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {(const void*)list}, {&size}});
     }
 
     int getxattr(const char* path, const char* name, char* value, size_t size, uint32_t position)
     {
-        TRACE_LOG("%s %s with position=%u, name=%s", __func__, path, position, name);
-        if (position != 0)
-            return -EINVAL;
-        int rc = precheck_getxattr(&name);
-        if (rc <= 0)
-            return rc;
+        auto func = [&]()
+        {
+            if (position != 0)
+                return -EINVAL;
+            int rc = precheck_getxattr(&name);
+            if (rc <= 0)
+                return rc;
 
-        auto filesystem = get_local_filesystem();
-        rc = static_cast<int>(filesystem->getxattr(path, name, value, size));
-        if (rc < 0)
-        {
-            TRACE_LOG("%s %s with name=%s encountered error: %d (%s)",
-                      __func__,
-                      path,
-                      name,
-                      -rc,
-                      OSService::stringify_system_error(-rc).c_str());
-        }
-        return rc;
+            auto filesystem = get_local_filesystem();
+            rc = static_cast<int>(filesystem->getxattr(path, name, value, size));
+            return rc;
+        };
+        return FuseTracer::traced_call(
+            func,
+            FULL_FUNCTION_NAME,
+            __LINE__,
+            {{path}, {name}, {(const void*)value}, {&size}, {&position}});
     }
 
     int setxattr(const char* path,
@@ -521,51 +531,38 @@ namespace lite
                  int flags,
                  uint32_t position)
     {
-        TRACE_LOG("%s %s with position=%u, name=%s, value=%s",
-                  __func__,
-                  path,
-                  position,
-                  name,
-                  escape_nonprintable(value, size).c_str());
-        if (position != 0)
-            return -EINVAL;
-        int rc = precheck_setxattr(&name, &flags);
-        if (rc <= 0)
-            return rc;
-        if (!value || size == 0)
-            return 0;
+        auto func = [&]()
+        {
+            if (position != 0)
+                return -EINVAL;
+            int rc = precheck_setxattr(&name, &flags);
+            if (rc <= 0)
+                return rc;
+            if (!value || size == 0)
+                return 0;
 
-        auto filesystem = get_local_filesystem();
-        rc = filesystem->setxattr(path, name, const_cast<char*>(value), size, flags);
-        if (rc < 0)
-        {
-            TRACE_LOG("%s %s with name=%s encountered error: %d (%s)",
-                      __func__,
-                      path,
-                      name,
-                      -rc,
-                      OSService::stringify_system_error(-rc).c_str());
-        }
-        return rc;
+            auto filesystem = get_local_filesystem();
+            rc = filesystem->setxattr(path, name, const_cast<char*>(value), size, flags);
+            return rc;
+        };
+        return FuseTracer::traced_call(
+            func,
+            FULL_FUNCTION_NAME,
+            __LINE__,
+            {{path}, {name}, {(const void*)value}, {&size}, {&flags}, {&position}});
     }
     int removexattr(const char* path, const char* name)
     {
-        TRACE_LOG("%s %s with name=%s", __func__, path, name);
-        int rc = precheck_removexattr(&name);
-        if (rc <= 0)
+        auto func = [&]()
+        {
+            int rc = precheck_removexattr(&name);
+            if (rc <= 0)
+                return rc;
+            auto filesystem = get_local_filesystem();
+            rc = filesystem->removexattr(path, name);
             return rc;
-        auto filesystem = get_local_filesystem();
-        rc = filesystem->removexattr(path, name);
-        if (rc < 0)
-        {
-            TRACE_LOG("%s %s with name=%s encountered error: %d (%s)",
-                      __func__,
-                      path,
-                      name,
-                      -rc,
-                      OSService::stringify_system_error(-rc).c_str());
-        }
-        return rc;
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {name}});
     }
 #endif
 
@@ -573,10 +570,14 @@ namespace lite
     {
         memset(opt, 0, sizeof(*opt));
 
+        opt->flag_nopath = true;
+        opt->flag_nullpath_ok = true;
+
         opt->init = &::securefs::lite::init;
         opt->destroy = &::securefs::lite::destroy;
         opt->statfs = &::securefs::lite::statfs;
         opt->getattr = &::securefs::lite::getattr;
+        opt->fgetattr = &::securefs::lite::fgetattr;
         opt->opendir = &::securefs::lite::opendir;
         opt->releasedir = &::securefs::lite::releasedir;
         opt->readdir = &::securefs::lite::readdir;
diff -pruN 0.11.1+ds-4/sources/lite_operations.h 0.13.1+ds-1/sources/lite_operations.h
--- 0.11.1+ds-4/sources/lite_operations.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/lite_operations.h	2023-01-27 02:25:50.000000000 +0000
@@ -21,6 +21,8 @@ namespace lite
 
     int getattr(const char*, struct fuse_stat*);
 
+    int fgetattr(const char*, struct fuse_stat*, struct fuse_file_info*);
+
     int opendir(const char*, struct fuse_file_info*);
 
     int releasedir(const char*, struct fuse_file_info*);
diff -pruN 0.11.1+ds-4/sources/lite_stream.cpp 0.13.1+ds-1/sources/lite_stream.cpp
--- 0.11.1+ds-4/sources/lite_stream.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/lite_stream.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -1,7 +1,9 @@
 #include "lite_stream.h"
 #include "crypto.h"
+#include "logger.h"
 
 #include <cryptopp/aes.h>
+#include <cryptopp/integer.h>
 #include <cryptopp/modes.h>
 #include <cryptopp/osrng.h>
 
@@ -9,18 +11,40 @@ namespace securefs
 {
 namespace lite
 {
+    namespace
+    {
+        const offset_type MAX_BLOCKS = (1ULL << 31) - 1;
+        unsigned compute_padding(unsigned max_padding,
+                                 CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption* padding_aes,
+                                 const byte* id,
+                                 size_t id_size)
+        {
+            if (!max_padding || !padding_aes)
+            {
+                return 0;
+            }
+            CryptoPP::FixedSizeAlignedSecBlock<byte, 16> transformed;
+            padding_aes->ProcessData(transformed.data(), id, id_size);
+            CryptoPP::Integer integer(transformed.data(),
+                                      transformed.size(),
+                                      CryptoPP::Integer::UNSIGNED,
+                                      CryptoPP::BIG_ENDIAN_ORDER);
+            return static_cast<unsigned>(integer.Modulo(max_padding + 1));
+        }
+    }    // namespace
     std::string CorruptedStreamException::message() const { return "Stream is corrupted"; }
 
-    static const offset_type MAX_BLOCKS = (1ULL << 31) - 1;
-
     AESGCMCryptStream::AESGCMCryptStream(std::shared_ptr<StreamBase> stream,
                                          const key_type& master_key,
-                                         unsigned int block_size,
+                                         unsigned block_size,
                                          unsigned iv_size,
-                                         bool check)
+                                         bool check,
+                                         unsigned max_padding_size,
+                                         CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption* padding_aes)
         : BlockBasedStream(block_size)
         , m_stream(std::move(stream))
         , m_iv_size(iv_size)
+        , m_padding_size(0)
         , m_check(check)
     {
         if (m_iv_size < 12 || m_iv_size > 32)
@@ -32,21 +56,44 @@ namespace lite
 
         warn_if_key_not_random(master_key, __FILE__, __LINE__);
 
-        CryptoPP::FixedSizeAlignedSecBlock<byte, get_header_size()> header, session_key;
-        auto rc = m_stream->read(header.data(), 0, header.size());
+        CryptoPP::FixedSizeAlignedSecBlock<byte, get_id_size()> id, session_key;
+        auto rc = m_stream->read(id.data(), 0, id.size());
 
         if (rc == 0)
         {
-            generate_random(header.data(), header.size());
-            m_stream->write(header.data(), 0, header.size());
+            generate_random(id.data(), id.size());
+            m_stream->write(id.data(), 0, id.size());
+            m_padding_size = compute_padding(max_padding_size, padding_aes, id.data(), id.size());
+            m_auxiliary.reset(new byte[sizeof(std::uint32_t) + m_padding_size]);
+            if (m_padding_size)
+            {
+                generate_random(m_auxiliary.get(), sizeof(std::uint32_t) + m_padding_size);
+                m_stream->write(
+                    m_auxiliary.get() + sizeof(std::uint32_t), id.size(), m_padding_size);
+            }
+        }
+        else if (rc != id.size())
+        {
+            throwInvalidArgumentException("Underlying stream has invalid ID size");
         }
-        else if (rc != header.size())
+        else
         {
-            throwInvalidArgumentException("Underlying stream has invalid header size");
+            m_padding_size = compute_padding(max_padding_size, padding_aes, id.data(), id.size());
+            m_auxiliary.reset(new byte[sizeof(std::uint32_t) + m_padding_size]);
+            if (m_padding_size
+                && m_stream->read(
+                       m_auxiliary.get() + sizeof(std::uint32_t), id.size(), m_padding_size)
+                    != m_padding_size)
+                throwInvalidArgumentException("Invalid padding in the underlying file");
+        }
+
+        if (max_padding_size > 0)
+        {
+            TRACE_LOG("Stream padded with %u bytes", m_padding_size);
         }
 
         CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption ecenc(master_key.data(), master_key.size());
-        ecenc.ProcessData(session_key.data(), header.data(), get_header_size());
+        ecenc.ProcessData(session_key.data(), id.data(), id.size());
 
         m_buffer.reset(new byte[get_underlying_block_size()]);
 
@@ -56,9 +103,6 @@ namespace lite
             session_key.data(), session_key.size(), null_iv, array_length(null_iv));
         m_decryptor.SetKeyWithIV(
             session_key.data(), session_key.size(), null_iv, array_length(null_iv));
-
-        warn_if_key_not_random(header, __FILE__, __LINE__);
-        warn_if_key_not_random(session_key, __FILE__, __LINE__);
     }
 
     AESGCMCryptStream::~AESGCMCryptStream() {}
@@ -91,16 +135,15 @@ namespace lite
             return out_size;
         }
 
-        byte auxiliary[sizeof(std::uint32_t)];
-        to_little_endian(static_cast<std::uint32_t>(block_number), auxiliary);
+        to_little_endian(static_cast<std::uint32_t>(block_number), m_auxiliary.get());
 
         bool success = m_decryptor.DecryptAndVerify(static_cast<byte*>(output),
                                                     m_buffer.get() + rc - get_mac_size(),
                                                     get_mac_size(),
                                                     m_buffer.get(),
                                                     static_cast<int>(get_iv_size()),
-                                                    auxiliary,
-                                                    sizeof(auxiliary),
+                                                    m_auxiliary.get(),
+                                                    sizeof(std::uint32_t) + m_padding_size,
                                                     m_buffer.get() + get_iv_size(),
                                                     out_size);
 
@@ -127,8 +170,7 @@ namespace lite
             return;
         }
 
-        byte auxiliary[sizeof(std::uint32_t)];
-        to_little_endian(static_cast<std::uint32_t>(block_number), auxiliary);
+        to_little_endian(static_cast<std::uint32_t>(block_number), m_auxiliary.get());
 
         do
         {
@@ -140,8 +182,8 @@ namespace lite
                                            get_mac_size(),
                                            m_buffer.get(),
                                            static_cast<int>(get_iv_size()),
-                                           auxiliary,
-                                           sizeof(auxiliary),
+                                           m_auxiliary.get(),
+                                           sizeof(std::uint32_t) + m_padding_size,
                                            static_cast<const byte*>(input),
                                            size);
 
@@ -150,7 +192,10 @@ namespace lite
 
     length_type AESGCMCryptStream::size() const
     {
-        return calculate_real_size(m_stream->size(), get_block_size(), get_iv_size());
+        auto underlying_size = m_stream->size();
+        return underlying_size <= get_header_size()
+            ? 0
+            : calculate_real_size(underlying_size - m_padding_size, m_block_size, m_iv_size);
     }
 
     void AESGCMCryptStream::adjust_logical_size(length_type length)
@@ -165,11 +210,11 @@ namespace lite
                                                        length_type block_size,
                                                        length_type iv_size) noexcept
     {
-        auto header_size = get_header_size();
+        auto id_size = get_id_size();
         auto underlying_block_size = block_size + iv_size + get_mac_size();
-        if (underlying_size <= header_size)
+        if (underlying_size <= id_size)
             return 0;
-        underlying_size -= header_size;
+        underlying_size -= id_size;
         auto num_blocks = underlying_size / underlying_block_size;
         auto residue = underlying_size % underlying_block_size;
         return num_blocks * block_size
diff -pruN 0.11.1+ds-4/sources/lite_stream.h 0.13.1+ds-1/sources/lite_stream.h
--- 0.11.1+ds-4/sources/lite_stream.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/lite_stream.h	2023-01-27 02:25:50.000000000 +0000
@@ -24,8 +24,8 @@ namespace lite
         CryptoPP::GCM<CryptoPP::AES>::Encryption m_encryptor;
         CryptoPP::GCM<CryptoPP::AES>::Decryption m_decryptor;
         std::shared_ptr<StreamBase> m_stream;
-        std::unique_ptr<byte[]> m_buffer;
-        unsigned m_iv_size;
+        std::unique_ptr<byte[]> m_buffer, m_auxiliary;
+        unsigned m_iv_size, m_padding_size;
         bool m_check;
 
     public:
@@ -35,13 +35,17 @@ namespace lite
 
         static constexpr unsigned get_mac_size() noexcept { return 16; }
 
-        static constexpr length_type get_header_size() noexcept { return 16; }
+        static constexpr length_type get_id_size() noexcept { return 16; }
+
+        length_type get_header_size() const noexcept { return get_id_size() + get_padding_size(); }
 
         length_type get_underlying_block_size() const noexcept
         {
             return get_block_size() + get_iv_size() + get_mac_size();
         }
 
+        unsigned get_padding_size() const noexcept { return m_padding_size; }
+
     protected:
         length_type read_block(offset_type block_number, void* output) override;
 
@@ -54,7 +58,10 @@ namespace lite
                                    const key_type& master_key,
                                    unsigned block_size = 4096,
                                    unsigned iv_size = 12,
-                                   bool check = true);
+                                   bool check = true,
+                                   unsigned max_padding_size = 0,
+                                   CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption* padding_aes
+                                   = nullptr);
 
         ~AESGCMCryptStream();
 
@@ -64,6 +71,8 @@ namespace lite
 
         virtual bool is_sparse() const noexcept override;
 
+        // Calculates the size of `AESGCMCryptStream` based on its underlying stream size. This only
+        // works when padding is not enabled.
         static length_type calculate_real_size(length_type underlying_size,
                                                length_type block_size,
                                                length_type iv_size) noexcept;
diff -pruN 0.11.1+ds-4/sources/lock_guard.h 0.13.1+ds-1/sources/lock_guard.h
--- 0.11.1+ds-4/sources/lock_guard.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/lock_guard.h	2023-01-27 02:25:50.000000000 +0000
@@ -15,6 +15,10 @@ public:
     {
         lock.lock(exclusive);
     }
+    explicit LockGuard(Lockable& lock) THREAD_ANNOTATION_ACQUIRE(lock) : m_lock(&lock)
+    {
+        lock.lock();
+    }
     ~LockGuard() THREAD_ANNOTATION_RELEASE() { m_lock->unlock(); }
     LockGuard(LockGuard&&) = delete;
     LockGuard(const LockGuard&) = delete;
diff -pruN 0.11.1+ds-4/sources/logger.cpp 0.13.1+ds-1/sources/logger.cpp
--- 0.11.1+ds-4/sources/logger.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/logger.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -28,14 +28,40 @@ void Logger::vlog(
 {
     if (!m_fp || level < this->get_level())
         return;
+    prelog(level, funcsig, lineno);
+    DEFER(postlog(level));
+
+    vfprintf(m_fp, format, args);
+}
+
+void Logger::log(
+    LoggingLevel level, const char* funcsig, int lineno, const char* format, ...) noexcept
+{
+    if (!m_fp || level < this->get_level())
+        return;
+    va_list args;
+    va_start(args, format);
+    DEFER(va_end(args));
+
+    vlog(level, funcsig, lineno, format, args);
+}
+
+Logger::Logger(FILE* fp, bool close_on_exit)
+    : m_level(kLogInfo), m_fp(fp), m_close_on_exit(close_on_exit)
+{
+    m_console_color = ConsoleColourSetter::create_setter(m_fp);
+}
+
+void Logger::prelog(LoggingLevel level, const char* funcsig, int lineno) noexcept
+{
+    if (!m_fp || level < this->get_level())
+        return;
 
     struct tm now;
     int now_ns = 0;
     OSService::get_current_time_in_tm(&now, &now_ns);
 
     flockfile(m_fp);
-    DEFER(funlockfile(m_fp));
-
     if (m_console_color)
     {
         switch (level)
@@ -64,8 +90,10 @@ void Logger::vlog(
             now_ns,
             funcsig,
             lineno);
-    vfprintf(m_fp, format, args);
+}
 
+void Logger::postlog(LoggingLevel level) noexcept
+{
     if (m_console_color && (level == kLogWarning || level == kLogError))
     {
         m_console_color->use(Colour::Default);
@@ -73,23 +101,7 @@ void Logger::vlog(
 
     putc('\n', m_fp);
     fflush(m_fp);
-}
-
-void Logger::log(
-    LoggingLevel level, const char* funcsig, int lineno, const char* format, ...) noexcept
-{
-    if (!m_fp || level < this->get_level())
-        return;
-    va_list args;
-    va_start(args, format);
-    vlog(level, funcsig, lineno, format, args);
-    va_end(args);
-}
-
-Logger::Logger(FILE* fp, bool close_on_exit)
-    : m_level(kLogInfo), m_fp(fp), m_close_on_exit(close_on_exit)
-{
-    m_console_color = ConsoleColourSetter::create_setter(m_fp);
+    funlockfile(m_fp);
 }
 
 Logger::~Logger()
diff -pruN 0.11.1+ds-4/sources/logger.h 0.13.1+ds-1/sources/logger.h
--- 0.11.1+ds-4/sources/logger.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/logger.h	2023-01-27 02:25:50.000000000 +0000
@@ -36,9 +36,12 @@ inline const char* stringify(LoggingLeve
     return "UNKNOWN";
 }
 
+class FuseTracer;
+
 class Logger
 {
     DISABLE_COPY_MOVE(Logger)
+    friend class FuseTracer;
 
 private:
     LoggingLevel m_level;
@@ -48,6 +51,9 @@ private:
 
     explicit Logger(FILE* fp, bool close_on_exit);
 
+    void prelog(LoggingLevel level, const char* funcsig, int lineno) noexcept;
+    void postlog(LoggingLevel level) noexcept;
+
 public:
     static Logger* create_stderr_logger();
     static Logger* create_file_logger(const std::string& path);
diff -pruN 0.11.1+ds-4/sources/mystring.h 0.13.1+ds-1/sources/mystring.h
--- 0.11.1+ds-4/sources/mystring.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/mystring.h	2023-01-27 02:25:50.000000000 +0000
@@ -124,7 +124,7 @@ typedef BasicStringRef<char> StringRef;
 typedef BasicStringRef<wchar_t> WideStringRef;
 
 std::string strprintf(const char* format, ...)
-#ifndef WIN32
+#ifndef _MSC_VER
     __attribute__((format(printf, 1, 2)))
 #endif
     ;
diff -pruN 0.11.1+ds-4/sources/operations.cpp 0.13.1+ds-1/sources/operations.cpp
--- 0.11.1+ds-4/sources/operations.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/operations.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -2,6 +2,7 @@
 #include "apple_xattr_workaround.h"
 #include "constants.h"
 #include "crypto.h"
+#include "fuse_tracer.h"
 #include "platform.h"
 
 #include <algorithm>
@@ -32,17 +33,27 @@ namespace operations
                 from_cryptopp_key(opt.master_key),
                 opt.flags.value(),
                 opt.block_size.value(),
-                opt.iv_size.value())
+                opt.iv_size.value(),
+                opt.max_padding_size)
         , root(opt.root)
         , root_id()
         , flags(opt.flags.value())
+        , lock_stream(opt.lock_stream)
     {
         if (opt.version.value() > 3)
             throwInvalidArgumentException("This context object only works with format 1,2,3");
         block_size = opt.block_size.value();
     }
 
-    FileSystemContext::~FileSystemContext() {}
+    FileSystemContext::~FileSystemContext()
+    {
+        if (!lock_stream)
+        {
+            return;
+        }
+        lock_stream->close();
+        root->remove_file_nothrow(LOCK_FILENAME);
+    }
 }    // namespace operations
 }    // namespace securefs
 
@@ -77,11 +88,15 @@ namespace internal
 
         for (size_t i = 0; i + 1 < components.size(); ++i)
         {
-            bool exists = result.get_as<Directory>()->get_entry(components[i], id, type);
-            if (!exists)
-                throwVFSException(ENOENT);
-            if (type != FileBase::DIRECTORY)
-                throwVFSException(ENOTDIR);
+            auto& dir = *result;
+            {
+                FileLockGuard lg(dir);
+                bool exists = dir.cast_as<Directory>()->get_entry(components[i], id, type);
+                if (!exists)
+                    throwVFSException(ENOENT);
+                if (type != FileBase::DIRECTORY)
+                    throwVFSException(ENOTDIR);
+            }
             result.reset(fs->table.open_as(id, type));
         }
         last_component = components.back();
@@ -91,33 +106,41 @@ namespace internal
     FileGuard open_all(FileSystemContext* fs, const char* path)
     {
         std::string last_component;
-        auto fg = open_base_dir(fs, path, last_component);
+        auto auto_closed_file = open_base_dir(fs, path, last_component);
         if (last_component.empty())
-            return fg;
+            return auto_closed_file;
         id_type id;
         int type;
-        bool exists = fg.get_as<Directory>()->get_entry(last_component, id, type);
-        if (!exists)
-            throwVFSException(ENOENT);
-        fg.reset(fs->table.open_as(id, type));
-        return fg;
+        {
+            auto& dir = *auto_closed_file;
+            FileLockGuard file_lock_guard(dir);
+            bool exists = dir.cast_as<Directory>()->get_entry(last_component, id, type);
+            if (!exists)
+                throwVFSException(ENOENT);
+        }
+        auto_closed_file.reset(fs->table.open_as(id, type));
+        return auto_closed_file;
     }
 
     // Specialization of `open_all` since `VFSException(ENOENT)` occurs too frequently
-    bool open_all(FileSystemContext* fs, const char* path, FileGuard& fg)
+    bool open_all(FileSystemContext* fs, const char* path, FileGuard& auto_closed_file)
     {
         std::string last_component;
-        fg = open_base_dir(fs, path, last_component);
+        auto_closed_file = open_base_dir(fs, path, last_component);
         if (last_component.empty())
             return true;
         id_type id;
         int type;
-        bool exists = fg.get_as<Directory>()->get_entry(last_component, id, type);
-        if (!exists)
         {
-            return false;
+            auto& dir = *auto_closed_file;
+            FileLockGuard file_lock_guard(dir);
+            bool exists = dir.cast_as<Directory>()->get_entry(last_component, id, type);
+            if (!exists)
+            {
+                return false;
+            }
         }
-        fg.reset(fs->table.open_as(id, type));
+        auto_closed_file.reset(fs->table.open_as(id, type));
         return true;
     }
 
@@ -134,17 +157,26 @@ namespace internal
         generate_random(id.data(), id.size());
 
         FileGuard result(&fs->table, fs->table.create_as(id, type));
-        result->initialize_empty(mode, uid, gid);
+
+        {
+            auto& fp = *result;
+            FileLockGuard file_lock_guard(fp);
+            fp.initialize_empty(mode, uid, gid);
+        }
 
         try
         {
-            bool success = dir.get_as<Directory>()->add_entry(last_component, id, type);
+            auto& dirfp = *dir;
+            FileLockGuard file_lock_guard(dirfp);
+            bool success = dirfp.cast_as<Directory>()->add_entry(last_component, id, type);
             if (!success)
                 throwVFSException(EEXIST);
         }
         catch (...)
         {
-            result->unlink();
+            auto& fp = *result;
+            FileLockGuard file_lock_guard(fp);
+            fp.unlink();
             throw;
         }
         return result;
@@ -155,7 +187,9 @@ namespace internal
         try
         {
             FileGuard to_be_removed(&fs->table, fs->table.open_as(id, type));
-            to_be_removed->unlink();
+            auto& fp = *to_be_removed;
+            FileLockGuard file_lock_guard(fp);
+            fp.unlink();
         }
         catch (...)
         {
@@ -173,16 +207,22 @@ namespace internal
             throwVFSException(EPERM);
         id_type id;
         int type;
-        if (!dir->get_entry(last_component, id, type))
-            throwVFSException(ENOENT);
+
+        {
+            FileLockGuard file_lock_guard(*dir);
+            if (!dir->get_entry(last_component, id, type))
+                throwVFSException(ENOENT);
+        }
 
         FileGuard inner_guard = open_as(fs->table, id, type);
         auto inner_fb = inner_guard.get();
+        DoubleFileLockGuard double_file_lock_guard(*dir, *inner_fb);
         if (inner_fb->type() == FileBase::DIRECTORY && !static_cast<Directory*>(inner_fb)->empty())
         {
             std::string contents;
             static_cast<Directory*>(inner_fb)->iterate_over_entries(
-                [&contents](const std::string& str, const id_type&, int) -> bool {
+                [&contents](const std::string& str, const id_type&, int) -> bool
+                {
                     contents.push_back('\n');
                     contents += str;
                     return true;
@@ -207,15 +247,12 @@ namespace operations
     (void)fs;                                                                                      \
     OPT_TRACE_WITH_PATH;
 
-#define COMMON_CATCH_BLOCK OPT_CATCH_WITH_PATH
-
     void* init(struct fuse_conn_info* fsinfo)
     {
         (void)fsinfo;
         auto args = static_cast<MountOptions*>(fuse_get_context()->private_data);
         auto fs = new FileSystemContext(*args);
         TRACE_LOG("%s", __FUNCTION__);
-        fputs("Filesystem mounted successfully\n", stderr);
         return fs;
     }
 
@@ -224,54 +261,70 @@ namespace operations
         auto fs = static_cast<FileSystemContext*>(data);
         TRACE_LOG("%s", __FUNCTION__);
         delete fs;
-        fputs("Filesystem unmounted successfully\n", stderr);
     }
 
     int statfs(const char* path, struct fuse_statvfs* fs_info)
     {
-        COMMON_PROLOGUE
-        try
+        auto func = [=]()
         {
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
             fs->table.statfs(fs_info);
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {fs_info}});
     }
 
     int getattr(const char* path, struct fuse_stat* st)
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
             if (!st)
                 return -EINVAL;
 
-            internal::FileGuard fg(nullptr, nullptr);
-            if (!internal::open_all(fs, path, fg))
+            internal::FileGuard auto_closed_file(nullptr, nullptr);
+            if (!internal::open_all(fs, path, auto_closed_file))
                 return -ENOENT;
-            fg->stat(st);
+            auto& fp = *auto_closed_file;
+            FileLockGuard file_lock_guard(fp);
+            fp.stat(st);
             st->st_uid = OSService::getuid();
             st->st_gid = OSService::getgid();
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {st}});
     }
 
-    int opendir(const char* path, struct fuse_file_info* info)
+    int fgetattr(const char* path, struct fuse_stat* st, struct fuse_file_info* info)
     {
-        COMMON_PROLOGUE
+        auto func = [=]()
+        {
+            auto fb = reinterpret_cast<FileBase*>(info->fh);
+            if (!fb)
+                return -EFAULT;
+            FileLockGuard file_lock_guard(*fb);
+            fb->stat(st);
+            return 0;
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {st}, {info}});
+    }
 
-        try
+    int opendir(const char* path, struct fuse_file_info* info)
+    {
+        auto func = [=]()
         {
-            auto fg = internal::open_all(fs, path);
-            if (fg->type() != FileBase::DIRECTORY)
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            auto auto_closed_file = internal::open_all(fs, path);
+            if (auto_closed_file->type() != FileBase::DIRECTORY)
                 return -ENOTDIR;
-            info->fh = reinterpret_cast<uintptr_t>(fg.release());
+            info->fh = reinterpret_cast<uintptr_t>(auto_closed_file.release());
 
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {info}});
     }
 
     int releasedir(const char* path, struct fuse_file_info* info)
@@ -282,24 +335,50 @@ namespace operations
     int readdir(const char* path,
                 void* buffer,
                 fuse_fill_dir_t filler,
-                fuse_off_t,
+                fuse_off_t off,
                 struct fuse_file_info* info)
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            bool has_padding = fs->table.has_padding();
             auto fb = reinterpret_cast<FileBase*>(info->fh);
             if (!fb)
                 return -EFAULT;
             if (fb->type() != FileBase::DIRECTORY)
                 return -ENOTDIR;
+
             struct fuse_stat st;
             memset(&st, 0, sizeof(st));
-            auto actions
-                = [&st, filler, buffer](const std::string& name, const id_type&, int type) -> bool {
+
+            FileLockGuard file_lock_guard(*fb);
+            if (!(fs->flags & kOptionSkipDotDot))
+            {
+#ifdef _WIN32
+                // Only Windows, `st` contains the full information, so we need to call `stat` here.
+                fb->stat(&st);
+                filler(buffer, ".", &st, 0);
+                filler(buffer, "..", nullptr, 0);
+#else
+                // On Unix, only information stored in `st` is the file mode. So we do not need to
+                // stat "." and "..".
+                st.st_mode = S_IFDIR;
+                filler(buffer, ".", &st, 0);
+                filler(buffer, "..", &st, 0);
+#endif
+            }
+            auto actions = [&st, filler, buffer, has_padding](
+                               const std::string& name, const id_type&, int type) -> bool
+            {
                 st.st_mode = FileBase::mode_for_type(type);
-                bool success = filler(buffer, name.c_str(), &st, 0) == 0;
+                bool success = filler(buffer,
+                                      name.c_str(),
+                                      // When random padding is enabled, we cannot obtain accurate
+                                      // size information
+                                      has_padding && type == FileBase::REGULAR_FILE ? nullptr : &st,
+                                      0)
+                    == 0;
                 if (!success)
                 {
                     WARN_LOG("Filling directory buffer failed");
@@ -308,85 +387,96 @@ namespace operations
             };
             fb->cast_as<Directory>()->iterate_over_entries(actions);
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func,
+                                       FULL_FUNCTION_NAME,
+                                       __LINE__,
+                                       {{path}, {buffer}, {(const void*)filler}, {&off}, {info}});
     }
 
     int create(const char* path, fuse_mode_t mode, struct fuse_file_info* info)
     {
-        COMMON_PROLOGUE
-
-        mode &= ~static_cast<uint32_t>(S_IFMT);
-        mode |= S_IFREG;
-        try
+        auto func = [&]()
         {
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            mode &= ~static_cast<uint32_t>(S_IFMT);
+            mode |= S_IFREG;
+
             if (internal::is_readonly(ctx))
                 return -EROFS;
-            auto fg = internal::create(fs, path, FileBase::REGULAR_FILE, mode, ctx->uid, ctx->gid);
-            fg->cast_as<RegularFile>();
-            info->fh = reinterpret_cast<uintptr_t>(fg.release());
+            auto auto_closed_file
+                = internal::create(fs, path, FileBase::REGULAR_FILE, mode, ctx->uid, ctx->gid);
+            auto_closed_file->cast_as<RegularFile>();
+            info->fh = reinterpret_cast<uintptr_t>(auto_closed_file.release());
 
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&mode}, {info}});
     }
 
     int open(const char* path, struct fuse_file_info* info)
     {
-        COMMON_PROLOGUE
-
-        int rdwr = info->flags & O_RDWR;
-        int wronly = info->flags & O_WRONLY;
-        int append = info->flags & O_APPEND;
-        int require_write = wronly | append | rdwr;
-
-        try
+        auto func = [=]()
         {
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            int rdwr = info->flags & O_RDWR;
+            int wronly = info->flags & O_WRONLY;
+            int append = info->flags & O_APPEND;
+            int require_write = wronly | append | rdwr;
+
             if (require_write && internal::is_readonly(ctx))
                 return -EROFS;
-            auto fg = internal::open_all(fs, path);
-            RegularFile* file = fg->cast_as<RegularFile>();
+            auto auto_closed_file = internal::open_all(fs, path);
+            RegularFile* file = auto_closed_file->cast_as<RegularFile>();
             if (info->flags & O_TRUNC)
             {
+                FileLockGuard file_lock_guard(*file);
                 file->truncate(0);
             }
-            info->fh = reinterpret_cast<uintptr_t>(fg.release());
+            info->fh = reinterpret_cast<uintptr_t>(auto_closed_file.release());
 
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {info}});
     }
 
     int release(const char* path, struct fuse_file_info* info)
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
+            auto ctx = fuse_get_context();
             auto fb = reinterpret_cast<FileBase*>(info->fh);
             if (!fb)
                 return -EINVAL;
-            fb->flush();
-            internal::FileGuard fg(&internal::get_fs(ctx)->table, fb);
-            fg.reset(nullptr);
+            {
+                FileLockGuard file_lock_guard(*fb);
+                fb->flush();
+            }
+            internal::FileGuard auto_closed_file(&internal::get_fs(ctx)->table, fb);
+            auto_closed_file.reset(nullptr);
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {info}});
     }
 
     int
     read(const char* path, char* buffer, size_t len, fuse_off_t off, struct fuse_file_info* info)
     {
-        OPT_TRACE_WITH_PATH_OFF_LEN(off, len);
-
-        try
+        auto func = [=]()
         {
             auto fb = reinterpret_cast<FileBase*>(info->fh);
             if (!fb)
                 return -EFAULT;
+            FileLockGuard file_lock_guard(*fb);
             return static_cast<int>(fb->cast_as<RegularFile>()->read(buffer, off, len));
-        }
-        OPT_CATCH_WITH_PATH_OFF_LEN(off, len)
+        };
+        return FuseTracer::traced_call(func,
+                                       FULL_FUNCTION_NAME,
+                                       __LINE__,
+                                       {{path}, {(const void*)buffer}, {&len}, {&off}, {info}});
     }
 
     int write(const char* path,
@@ -395,177 +485,194 @@ namespace operations
               fuse_off_t off,
               struct fuse_file_info* info)
     {
-        OPT_TRACE_WITH_PATH_OFF_LEN(off, len);
-        try
+        auto func = [=]()
         {
             auto fb = reinterpret_cast<FileBase*>(info->fh);
             if (!fb)
                 return -EFAULT;
+            FileLockGuard file_lock_guard(*fb);
             fb->cast_as<RegularFile>()->write(buffer, off, len);
             return static_cast<int>(len);
-        }
-        OPT_CATCH_WITH_PATH_OFF_LEN(off, len)
+        };
+        return FuseTracer::traced_call(func,
+                                       FULL_FUNCTION_NAME,
+                                       __LINE__,
+                                       {{path}, {(const void*)buffer}, {&len}, {&off}, {info}});
     }
 
     int flush(const char* path, struct fuse_file_info* info)
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
             auto fb = reinterpret_cast<FileBase*>(info->fh);
             if (!fb)
                 return -EFAULT;
+            FileLockGuard file_lock_guard(*fb);
             fb->cast_as<RegularFile>()->flush();
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {info}});
     }
 
     int truncate(const char* path, fuse_off_t size)
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
-            auto fg = internal::open_all(fs, path);
-            fg.get_as<RegularFile>()->truncate(size);
-            fg->flush();
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            auto auto_closed_file = internal::open_all(fs, path);
+            auto& fp = *auto_closed_file;
+            FileLockGuard file_lock_guard(fp);
+            fp.cast_as<RegularFile>()->truncate(size);
+            fp.flush();
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&size}});
     }
 
     int ftruncate(const char* path, fuse_off_t size, struct fuse_file_info* info)
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
             auto fb = reinterpret_cast<FileBase*>(info->fh);
             if (!fb)
                 return -EFAULT;
+            FileLockGuard file_lock_guard(*fb);
             fb->cast_as<RegularFile>()->truncate(size);
             fb->flush();
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&size}, {info}});
     }
 
     int unlink(const char* path)
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
             if (internal::is_readonly(ctx))
                 return -EROFS;
             internal::remove(fs, path);
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}});
     }
 
     int mkdir(const char* path, fuse_mode_t mode)
     {
-        COMMON_PROLOGUE
-
-        mode &= ~static_cast<uint32_t>(S_IFMT);
-        mode |= S_IFDIR;
-        try
+        auto func = [&]()
         {
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+
+            mode &= ~static_cast<uint32_t>(S_IFMT);
+            mode |= S_IFDIR;
+
             if (internal::is_readonly(ctx))
                 return -EROFS;
-            auto fg = internal::create(fs, path, FileBase::DIRECTORY, mode, ctx->uid, ctx->gid);
-            fg->cast_as<Directory>();
+            auto auto_closed_file
+                = internal::create(fs, path, FileBase::DIRECTORY, mode, ctx->uid, ctx->gid);
+            auto_closed_file->cast_as<Directory>();
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&mode}});
     }
 
     int rmdir(const char* path) { return ::securefs::operations::unlink(path); }
 
     int chmod(const char* path, fuse_mode_t mode)
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [&]()
         {
-            auto fg = internal::open_all(fs, path);
-            auto original_mode = fg->get_mode();
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            auto auto_closed_file = internal::open_all(fs, path);
+            auto& fp = *auto_closed_file;
+            FileLockGuard file_lock_guard(fp);
+            auto original_mode = fp.get_mode();
             mode &= 0777;
             mode |= original_mode & S_IFMT;
-            fg->set_mode(mode);
-            fg->flush();
+            fp.set_mode(mode);
+            fp.flush();
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&mode}});
     }
 
     int chown(const char* path, fuse_uid_t uid, fuse_gid_t gid)
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
-            auto fg = internal::open_all(fs, path);
-            fg->set_uid(uid);
-            fg->set_gid(gid);
-            fg->flush();
-            return 0;
-        }
-        COMMON_CATCH_BLOCK
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            auto auto_closed_file = internal::open_all(fs, path);
+            auto& fp = *auto_closed_file;
+            FileLockGuard file_lock_guard(fp);
+
+            fp.set_uid(uid);
+            fp.set_gid(gid);
+            fp.flush();
+            return 0;
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&uid}, {&gid}});
     }
 
     int symlink(const char* to, const char* from)
     {
-        auto ctx = fuse_get_context();
-        auto fs = internal::get_fs(ctx);
-        OPT_TRACE_WITH_TWO_PATHS(to, from);
-
-        try
+        auto func = [=]()
         {
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+
             if (internal::is_readonly(ctx))
                 return -EROFS;
-            auto fg
+            auto auto_closed_file
                 = internal::create(fs, from, FileBase::SYMLINK, S_IFLNK | 0755, ctx->uid, ctx->gid);
-            fg.get_as<Symlink>()->set(to);
+            auto& fp = *auto_closed_file;
+            FileLockGuard file_lock_guard(fp);
+            fp.cast_as<Symlink>()->set(to);
             return 0;
-        }
-        OPT_CATCH_WITH_TWO_PATHS(to, from)
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{to}, {from}});
     }
 
     int readlink(const char* path, char* buf, size_t size)
     {
         if (size == 0)
             return -EINVAL;
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
-            auto fg = internal::open_all(fs, path);
-            auto destination = fg.get_as<Symlink>()->get();
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            auto auto_closed_file = internal::open_all(fs, path);
+            auto& fp = *auto_closed_file;
+            FileLockGuard file_lock_guard(fp);
+            auto destination = fp.cast_as<Symlink>()->get();
             memset(buf, 0, size);
             memcpy(buf, destination.data(), std::min(destination.size(), size - 1));
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {(const void*)buf}, {&size}});
     }
 
     int rename(const char* src, const char* dst)
     {
-        auto ctx = fuse_get_context();
-        auto fs = internal::get_fs(ctx);
-        OPT_TRACE_WITH_TWO_PATHS(src, dst);
-
-        try
+        auto func = [=]()
         {
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
             std::string src_filename, dst_filename;
             auto src_dir_guard = internal::open_base_dir(fs, src, src_filename);
             auto dst_dir_guard = internal::open_base_dir(fs, dst, dst_filename);
             auto src_dir = src_dir_guard.get_as<Directory>();
             auto dst_dir = dst_dir_guard.get_as<Directory>();
 
+            DoubleFileLockGuard double_file_lock_guard(*src_dir, *dst_dir);
+
             id_type src_id, dst_id;
             int src_type, dst_type;
 
@@ -589,18 +696,16 @@ namespace operations
             if (dst_exists)
                 internal::remove(fs, dst_id, dst_type);
             return 0;
-        }
-        OPT_CATCH_WITH_TWO_PATHS(src, dst)
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{src}, {dst}});
     }
 
     int link(const char* src, const char* dst)
     {
-        auto ctx = fuse_get_context();
-        auto fs = internal::get_fs(ctx);
-        OPT_TRACE_WITH_TWO_PATHS(src, dst);
-
-        try
+        auto func = [=]()
         {
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
             std::string src_filename, dst_filename;
             auto src_dir_guard = internal::open_base_dir(fs, src, src_filename);
             auto dst_dir_guard = internal::open_base_dir(fs, dst, dst_filename);
@@ -610,6 +715,8 @@ namespace operations
             id_type src_id, dst_id;
             int src_type, dst_type;
 
+            DoubleFileLockGuard double_file_lock_guard(*src_dir, *dst_dir);
+
             bool src_exists = src_dir->get_entry(src_filename, src_id, src_type);
             if (!src_exists)
                 return -ENOENT;
@@ -623,27 +730,29 @@ namespace operations
             if (guard->type() != FileBase::REGULAR_FILE)
                 return -EPERM;
 
-            guard->set_nlink(guard->get_nlink() + 1);
+            auto& fp = *guard;
+            SpinFileLockGuard sflg(fp);
+            fp.set_nlink(fp.get_nlink() + 1);
             dst_dir->add_entry(dst_filename, src_id, src_type);
             return 0;
-        }
-        OPT_CATCH_WITH_TWO_PATHS(src, dst)
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{src}, {dst}});
     }
 
-    int fsync(const char* path, int, struct fuse_file_info* fi)
+    int fsync(const char* path, int dataysnc, struct fuse_file_info* fi)
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
             auto fb = reinterpret_cast<FileBase*>(fi->fh);
             if (!fb)
                 return -EFAULT;
+            FileLockGuard file_lock_guard(*fb);
             fb->flush();
             fb->fsync();
             return 0;
-        }
-        COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {&dataysnc}, {fi}});
     }
 
     int fsyncdir(const char* path, int isdatasync, struct fuse_file_info* fi)
@@ -653,70 +762,64 @@ namespace operations
 
     int utimens(const char* path, const struct fuse_timespec ts[2])
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
-            auto fg = internal::open_all(fs, path);
-            fg->utimens(ts);
-            return 0;
-        }
-        COMMON_CATCH_BLOCK
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            auto auto_closed_file = internal::open_all(fs, path);
+            auto& fp = *auto_closed_file;
+            FileLockGuard file_lock_guard(fp);
+            fp.utimens(ts);
+            return 0;
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {ts}, {ts ? ts + 1 : ts}});
     }
 
 #ifdef __APPLE__
 
     int listxattr(const char* path, char* list, size_t size)
     {
-        COMMON_PROLOGUE
-
-        try
+        auto func = [=]()
         {
-            auto fg = internal::open_all(fs, path);
-            int rc = static_cast<int>(fg->listxattr(list, size));
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            auto auto_closed_file = internal::open_all(fs, path);
+            auto& fp = *auto_closed_file;
+            int rc = -1;
+            {
+                FileLockGuard file_lock_guard(fp);
+                rc = static_cast<int>(fp.listxattr(list, size));
+            }
             transform_listxattr_result(list, size);
             return rc;
-        }
-        COMMON_CATCH_BLOCK
-    }
-
-#define XATTR_COMMON_PROLOGUE                                                                      \
-    auto ctx = fuse_get_context();                                                                 \
-    auto fs = internal::get_fs(ctx);                                                               \
-    TRACE_LOG("%s (path=%s, name=%s)", __func__, path, name);
-
-#define XATTR_COMMON_CATCH_BLOCK                                                                   \
-    catch (const std::exception& e)                                                                \
-    {                                                                                              \
-        auto ebase = dynamic_cast<const ExceptionBase*>(&e);                                       \
-        int errc = ebase ? ebase->error_number() : EPERM;                                          \
-        if (errc != ENOATTR) /* Attribute not found is very common and normal; no need to log it   \
-                                as an error */                                                     \
-            ERROR_LOG("%s (path=%s, name=%s) encounters %s: %s",                                   \
-                      __FUNCTION__,                                                                \
-                      path,                                                                        \
-                      name,                                                                        \
-                      get_type_name(e).get(),                                                      \
-                      e.what());                                                                   \
-        return -errc;                                                                              \
+        };
+        return FuseTracer::traced_call(
+            func, FULL_FUNCTION_NAME, __LINE__, {{path}, {(const void*)list}, {&size}});
     }
 
     int getxattr(const char* path, const char* name, char* value, size_t size, uint32_t position)
     {
-        XATTR_COMMON_PROLOGUE
-
-        if (position != 0)
-            return -EINVAL;
-        int rc = precheck_getxattr(&name);
-        if (rc <= 0)
-            return rc;
-
-        try
+        auto func = [&]()
         {
-            auto fg = internal::open_all(fs, path);
-            return static_cast<int>(fg->getxattr(name, value, size));
-        }
-        XATTR_COMMON_CATCH_BLOCK
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            if (position != 0)
+                return -EINVAL;
+            int rc = precheck_getxattr(&name);
+            if (rc <= 0)
+                return rc;
+
+            auto auto_closed_file = internal::open_all(fs, path);
+            auto& fp = *auto_closed_file;
+            FileLockGuard file_lock_guard(fp);
+            return static_cast<int>(fp.getxattr(name, value, size));
+        };
+        return FuseTracer::traced_call(
+            func,
+            FULL_FUNCTION_NAME,
+            __LINE__,
+            {{path}, {name}, {(const void*)value}, {&size}, {&position}});
     }
 
     int setxattr(const char* path,
@@ -726,45 +829,61 @@ namespace operations
                  int flags,
                  uint32_t position)
     {
-        XATTR_COMMON_PROLOGUE
-
-        if (position != 0)
-            return -EINVAL;
-        int rc = precheck_setxattr(&name, &flags);
-        if (rc <= 0)
-            return rc;
-
-        flags &= XATTR_CREATE | XATTR_REPLACE;
-        try
+        auto func = [&]()
         {
-            auto fg = internal::open_all(fs, path);
-            fg->setxattr(name, value, size, flags);
-            return 0;
-        }
-        XATTR_COMMON_CATCH_BLOCK
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            if (position != 0)
+                return -EINVAL;
+            int rc = precheck_setxattr(&name, &flags);
+            if (rc <= 0)
+                return rc;
+
+            flags &= XATTR_CREATE | XATTR_REPLACE;
+
+            auto auto_closed_file = internal::open_all(fs, path);
+            auto& fp = *auto_closed_file;
+            FileLockGuard file_lock_guard(fp);
+            fp.setxattr(name, value, size, flags);
+            return 0;
+        };
+        return FuseTracer::traced_call(
+            func,
+            FULL_FUNCTION_NAME,
+            __LINE__,
+            {{path}, {name}, {(const void*)value}, {&size}, {&flags}, {&position}});
     }
 
     int removexattr(const char* path, const char* name)
     {
-        XATTR_COMMON_PROLOGUE
-        int rc = precheck_removexattr(&name);
-        if (rc <= 0)
-            return rc;
-
-        try
+        auto func = [&]()
         {
-            auto fg = internal::open_all(fs, path);
-            fg->removexattr(name);
+            auto ctx = fuse_get_context();
+            auto fs = internal::get_fs(ctx);
+            int rc = precheck_removexattr(&name);
+            if (rc <= 0)
+                return rc;
+
+            auto auto_closed_file = internal::open_all(fs, path);
+            auto& fp = *auto_closed_file;
+            FileLockGuard file_lock_guard(fp);
+            fp.removexattr(name);
             return 0;
-        }
-        XATTR_COMMON_CATCH_BLOCK
+        };
+        return FuseTracer::traced_call(func, FULL_FUNCTION_NAME, __LINE__, {{path}, {name}});
     }
 #endif
 
     void init_fuse_operations(struct fuse_operations* opt, bool xattr)
     {
         memset(opt, 0, sizeof(*opt));
+
+        opt->flag_nopath = true;
+        opt->flag_nullpath_ok = true;
+        opt->flag_utime_omit_ok = true;
+
         opt->getattr = &securefs::operations::getattr;
+        opt->fgetattr = &securefs::operations::fgetattr;
         opt->init = &securefs::operations::init;
         opt->destroy = &securefs::operations::destroy;
         opt->opendir = &securefs::operations::opendir;
diff -pruN 0.11.1+ds-4/sources/operations.h 0.13.1+ds-1/sources/operations.h
--- 0.11.1+ds-4/sources/operations.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/operations.h	2023-01-27 02:25:50.000000000 +0000
@@ -6,63 +6,6 @@
 
 #include <fuse.h>
 
-#define OPT_TRACE_WITH_PATH TRACE_LOG("%s path=%s", __func__, path)
-#define OPT_TRACE_WITH_PATH_OFF_LEN(off, len)                                                      \
-    TRACE_LOG("%s path=%s offset=%lld length=%zu",                                                 \
-              __func__,                                                                            \
-              path,                                                                                \
-              static_cast<long long>(off),                                                         \
-              static_cast<size_t>(len))
-#define OPT_TRACE_WITH_TWO_PATHS(path1, path2)                                                     \
-    TRACE_LOG("%s %s=%s %s=%s", __func__, #path1, path1, #path2, path2)
-
-#define OPT_CATCH_WITH_PATH                                                                        \
-    catch (const std::exception& e)                                                                \
-    {                                                                                              \
-        auto ebase = dynamic_cast<const ExceptionBase*>(&e);                                       \
-        auto code = ebase ? ebase->error_number() : EPERM;                                         \
-        ERROR_LOG("%s path=%s encounters exception %s (code=%d): %s",                              \
-                  __func__,                                                                        \
-                  path,                                                                            \
-                  get_type_name(e).get(),                                                          \
-                  code,                                                                            \
-                  e.what());                                                                       \
-        return -code;                                                                              \
-    }
-
-#define OPT_CATCH_WITH_PATH_OFF_LEN(off, len)                                                      \
-    catch (const std::exception& e)                                                                \
-    {                                                                                              \
-        auto ebase = dynamic_cast<const ExceptionBase*>(&e);                                       \
-        auto code = ebase ? ebase->error_number() : EPERM;                                         \
-        ERROR_LOG("%s path=%s offset=%lld length=%zu encounters exception %s (code=%d): %s",       \
-                  __func__,                                                                        \
-                  path,                                                                            \
-                  static_cast<long long>(off),                                                     \
-                  static_cast<size_t>(len),                                                        \
-                  get_type_name(e).get(),                                                          \
-                  code,                                                                            \
-                  e.what());                                                                       \
-        return -code;                                                                              \
-    }
-
-#define OPT_CATCH_WITH_TWO_PATHS(path1, path2)                                                     \
-    catch (const std::exception& e)                                                                \
-    {                                                                                              \
-        auto ebase = dynamic_cast<const ExceptionBase*>(&e);                                       \
-        auto code = ebase ? ebase->error_number() : EPERM;                                         \
-        ERROR_LOG("%s %s=%s %s=%s encounters exception %s (code=%d): %s",                          \
-                  __func__,                                                                        \
-                  #path1,                                                                          \
-                  path1,                                                                           \
-                  #path2,                                                                          \
-                  path2,                                                                           \
-                  get_type_name(e).get(),                                                          \
-                  code,                                                                            \
-                  e.what());                                                                       \
-        return -code;                                                                              \
-    }
-
 namespace securefs
 {
 class FileStream;
@@ -78,6 +21,8 @@ namespace operations
         optional<uint32_t> flags;
         optional<unsigned> block_size;
         optional<unsigned> iv_size;
+        unsigned max_padding_size = 0;
+        std::shared_ptr<FileStream> lock_stream;
 
         MountOptions();
         ~MountOptions();
@@ -96,13 +41,14 @@ namespace operations
         }
 
     public:
-        FileTable table;
+        ShardedFileTableImpl table;
         std::shared_ptr<const OSService> root;
         id_type root_id;
         unsigned block_size;
         optional<fuse_uid_t> uid_override;
         optional<fuse_gid_t> gid_override;
         uint32_t flags;
+        std::shared_ptr<FileStream> lock_stream;
 
         explicit FileSystemContext(const MountOptions& opt);
 
@@ -119,6 +65,8 @@ namespace operations
 
     int getattr(const char*, struct fuse_stat*);
 
+    int fgetattr(const char*, struct fuse_stat*, struct fuse_file_info*);
+
     int opendir(const char*, struct fuse_file_info*);
 
     int releasedir(const char*, struct fuse_file_info*);
diff -pruN 0.11.1+ds-4/sources/platform.h 0.13.1+ds-1/sources/platform.h
--- 0.11.1+ds-4/sources/platform.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/platform.h	2023-01-27 02:25:50.000000000 +0000
@@ -4,9 +4,11 @@
 #include "mystring.h"
 #include "myutils.h"
 #include "streams.h"
+#include "thread_safety_annotations.hpp"
 
 #include <functional>
 #include <memory>
+#include <mutex>
 #include <stddef.h>
 #include <stdint.h>
 #include <string>
@@ -194,14 +196,14 @@ public:
     // <errno.h>
     ssize_t listxattr(const char* path, char* buf, size_t size) const noexcept;
     ssize_t getxattr(const char* path, const char* name, void* buf, size_t size) const noexcept;
-    int setxattr(const char* path, const char* name, void* buf, size_t size, int flags) const
-        noexcept;
+    int
+    setxattr(const char* path, const char* name, void* buf, size_t size, int flags) const noexcept;
     int removexattr(const char* path, const char* name) const noexcept;
 #endif
 public:
     static uint32_t getuid() noexcept;
     static uint32_t getgid() noexcept;
-    static int raise_fd_limit();
+    static int64_t raise_fd_limit() noexcept;
 
     static std::string temp_name(StringRef prefix, StringRef suffix);
     static const OSService& get_default();
@@ -266,4 +268,36 @@ public:
     // Returns null if fp is not connected to console/tty
     static std::unique_ptr<ConsoleColourSetter> create_setter(FILE* fp);
 };
+
+class POSIXColourSetter final : public ConsoleColourSetter
+{
+public:
+    explicit POSIXColourSetter(FILE* fp) : m_fp(fp) {}
+
+    void use(Colour::Code _colourCode) noexcept override;
+
+private:
+    FILE* m_fp;
+    void setColour(const char* _escapeCode) noexcept;
+};
+
+class THREAD_ANNOTATION_CAPABILITY("mutex") Mutex
+{
+public:
+    Mutex();
+    ~Mutex();
+    void lock() THREAD_ANNOTATION_ACQUIRE();
+    void unlock() noexcept THREAD_ANNOTATION_RELEASE();
+    bool try_lock() THREAD_ANNOTATION_TRY_ACQUIRE(true);
+
+private:
+#ifdef _WIN32
+    // MSVC implementation of std::mutex is too slow.
+    // So we reimplment it.
+    CRITICAL_SECTION m_cs;
+#else
+    std::mutex m_std;
+#endif
+};
+
 }    // namespace securefs
diff -pruN 0.11.1+ds-4/sources/scrypt.cpp 0.13.1+ds-1/sources/scrypt.cpp
--- 0.11.1+ds-4/sources/scrypt.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/scrypt.cpp	1970-01-01 00:00:00.000000000 +0000
@@ -1,371 +0,0 @@
-/*-
- * Copyright 2009 Colin Percival
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- *
- * This file was originally written by Colin Percival as part of the Tarsnap
- * online backup system.
- */
-
-#include "crypto.h"
-#include "exceptions.h"
-
-#include <sys/types.h>
-#ifndef _WIN32
-#include <sys/mman.h>
-#endif
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef _WIN32
-static int posix_memalign(void** p, size_t alignment, size_t size)
-{
-    ((*(p)) = _aligned_malloc((size), (alignment)));
-    return *(p) ? 0 : errno;
-}
-static void posix_memalign_free(void* p) { _aligned_free(p); }
-
-#else
-static void posix_memalign_free(void* p) { free(p); }
-#endif
-
-namespace securefs
-{
-static void blkcpy(void* dest, const void* src, size_t len)
-{
-    auto D = static_cast<size_t*>(dest);
-    auto S = static_cast<const size_t*>(src);
-    size_t L = len / sizeof(size_t);
-    size_t i;
-
-    for (i = 0; i < L; i++)
-        D[i] = S[i];
-}
-
-static void blkxor(void* dest, const void* src, size_t len)
-{
-    auto D = static_cast<size_t*>(dest);
-    auto S = static_cast<const size_t*>(src);
-    size_t L = len / sizeof(size_t);
-    size_t i;
-
-    for (i = 0; i < L; i++)
-        D[i] ^= S[i];
-}
-
-/**
- * salsa20_8(B):
- * Apply the salsa20/8 core to the provided block.
- */
-static void salsa20_8(uint32_t B[16])
-{
-    uint32_t x[16];
-    size_t i;
-
-    blkcpy(x, B, 64);
-    for (i = 0; i < 8; i += 2)
-    {
-#define R(a, b) (((a) << (b)) | ((a) >> (32 - (b))))
-        /* Operate on columns. */
-        x[4] ^= R(x[0] + x[12], 7);
-        x[8] ^= R(x[4] + x[0], 9);
-        x[12] ^= R(x[8] + x[4], 13);
-        x[0] ^= R(x[12] + x[8], 18);
-
-        x[9] ^= R(x[5] + x[1], 7);
-        x[13] ^= R(x[9] + x[5], 9);
-        x[1] ^= R(x[13] + x[9], 13);
-        x[5] ^= R(x[1] + x[13], 18);
-
-        x[14] ^= R(x[10] + x[6], 7);
-        x[2] ^= R(x[14] + x[10], 9);
-        x[6] ^= R(x[2] + x[14], 13);
-        x[10] ^= R(x[6] + x[2], 18);
-
-        x[3] ^= R(x[15] + x[11], 7);
-        x[7] ^= R(x[3] + x[15], 9);
-        x[11] ^= R(x[7] + x[3], 13);
-        x[15] ^= R(x[11] + x[7], 18);
-
-        /* Operate on rows. */
-        x[1] ^= R(x[0] + x[3], 7);
-        x[2] ^= R(x[1] + x[0], 9);
-        x[3] ^= R(x[2] + x[1], 13);
-        x[0] ^= R(x[3] + x[2], 18);
-
-        x[6] ^= R(x[5] + x[4], 7);
-        x[7] ^= R(x[6] + x[5], 9);
-        x[4] ^= R(x[7] + x[6], 13);
-        x[5] ^= R(x[4] + x[7], 18);
-
-        x[11] ^= R(x[10] + x[9], 7);
-        x[8] ^= R(x[11] + x[10], 9);
-        x[9] ^= R(x[8] + x[11], 13);
-        x[10] ^= R(x[9] + x[8], 18);
-
-        x[12] ^= R(x[15] + x[14], 7);
-        x[13] ^= R(x[12] + x[15], 9);
-        x[14] ^= R(x[13] + x[12], 13);
-        x[15] ^= R(x[14] + x[13], 18);
-#undef R
-    }
-    for (i = 0; i < 16; i++)
-        B[i] += x[i];
-}
-
-/**
- * blockmix_salsa8(Bin, Bout, X, r):
- * Compute Bout = BlockMix_{salsa20/8, r}(Bin).  The input Bin must be 128r
- * bytes in length; the output Bout must also be the same size.  The
- * temporary space X must be 64 bytes.
- */
-static void blockmix_salsa8(const uint32_t* Bin, uint32_t* Bout, uint32_t* X, size_t r)
-{
-    size_t i;
-
-    /* 1: X <-- B_{2r - 1} */
-    blkcpy(X, &Bin[(2 * r - 1) * 16], 64);
-
-    /* 2: for i = 0 to 2r - 1 do */
-    for (i = 0; i < 2 * r; i += 2)
-    {
-        /* 3: X <-- H(X \xor B_i) */
-        blkxor(X, &Bin[i * 16], 64);
-        salsa20_8(X);
-
-        /* 4: Y_i <-- X */
-        /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
-        blkcpy(&Bout[i * 8], X, 64);
-
-        /* 3: X <-- H(X \xor B_i) */
-        blkxor(X, &Bin[i * 16 + 16], 64);
-        salsa20_8(X);
-
-        /* 4: Y_i <-- X */
-        /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
-        blkcpy(&Bout[i * 8 + r * 16], X, 64);
-    }
-}
-
-/**
- * integerify(B, r):
- * Return the result of parsing B_{2r-1} as a little-endian integer.
- */
-static uint64_t integerify(const void* B, size_t r)
-{
-    auto X = reinterpret_cast<uint32_t*>((uintptr_t)(B) + (2 * r - 1) * 64);
-
-    return (((uint64_t)(X[1]) << 32) + X[0]);
-}
-
-static inline uint32_t le32dec(const void* pp)
-{
-    const uint8_t* p = (uint8_t const*)pp;
-
-    return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + ((uint32_t)(p[2]) << 16)
-            + ((uint32_t)(p[3]) << 24));
-}
-
-static inline void le32enc(void* pp, uint32_t x)
-{
-    uint8_t* p = (uint8_t*)pp;
-
-    p[0] = x & 0xff;
-    p[1] = (x >> 8) & 0xff;
-    p[2] = (x >> 16) & 0xff;
-    p[3] = (x >> 24) & 0xff;
-}
-
-/**
- * smix(B, r, N, V, XY):
- * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length;
- * the temporary storage V must be 128rN bytes in length; the temporary
- * storage XY must be 256r + 64 bytes in length.  The value N must be a
- * power of 2 greater than 1.  The arrays B, V, and XY must be aligned to a
- * multiple of 64 bytes.
- */
-static void smix(uint8_t* B, size_t r, uint64_t N, uint32_t* V, uint32_t* XY)
-{
-    uint32_t* X = XY;
-    uint32_t* Y = &XY[32 * r];
-    uint32_t* Z = &XY[64 * r];
-    uint64_t i;
-    uint64_t j;
-    size_t k;
-
-    /* 1: X <-- B */
-    for (k = 0; k < 32 * r; k++)
-        X[k] = le32dec(&B[4 * k]);
-
-    /* 2: for i = 0 to N - 1 do */
-    for (i = 0; i < N; i += 2)
-    {
-        /* 3: V_i <-- X */
-        blkcpy(&V[i * (32 * r)], X, 128 * r);
-
-        /* 4: X <-- H(X) */
-        blockmix_salsa8(X, Y, Z, r);
-
-        /* 3: V_i <-- X */
-        blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r);
-
-        /* 4: X <-- H(X) */
-        blockmix_salsa8(Y, X, Z, r);
-    }
-
-    /* 6: for i = 0 to N - 1 do */
-    for (i = 0; i < N; i += 2)
-    {
-        /* 7: j <-- Integerify(X) mod N */
-        j = integerify(X, r) & (N - 1);
-
-        /* 8: X <-- H(X \xor V_j) */
-        blkxor(X, &V[j * (32 * r)], 128 * r);
-        blockmix_salsa8(X, Y, Z, r);
-
-        /* 7: j <-- Integerify(X) mod N */
-        j = integerify(Y, r) & (N - 1);
-
-        /* 8: X <-- H(X \xor V_j) */
-        blkxor(Y, &V[j * (32 * r)], 128 * r);
-        blockmix_salsa8(Y, X, Z, r);
-    }
-
-    /* 10: B' <-- X */
-    for (k = 0; k < 32 * r; k++)
-        le32enc(&B[4 * k], X[k]);
-}
-
-static void libscrypt_PBKDF2_SHA256(const uint8_t* passwd,
-                                    size_t passwdlen,
-                                    const uint8_t* salt,
-                                    size_t saltlen,
-                                    uint64_t c,
-                                    uint8_t* buf,
-                                    size_t dkLen)
-{
-    securefs::pbkdf_hmac_sha256(passwd, passwdlen, salt, saltlen, c, 0, buf, dkLen);
-}
-
-/**
- * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
- * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
- * p, buflen) and write the result into buf.  The parameters r, p, and buflen
- * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N
- * must be a power of 2 greater than 1.
- *
- * throws exception on error
- */
-void libscrypt_scrypt(const uint8_t* passwd,
-                      size_t passwdlen,
-                      const uint8_t* salt,
-                      size_t saltlen,
-                      uint64_t N,
-                      uint32_t r,
-                      uint32_t p,
-                      uint8_t* buf,
-                      size_t buflen)
-{
-    void *B0, *V0, *XY0;
-    uint8_t* B;
-    uint32_t* V;
-    uint32_t* XY;
-    uint32_t i;
-
-/* Sanity-check parameters. */
-#if SIZE_MAX > UINT32_MAX
-    if (buflen > (((uint64_t)(1) << 32) - 1) * 32)
-    {
-        throwInvalidArgumentException("buffer too big");
-    }
-#endif
-    if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30))
-    {
-        throwInvalidArgumentException("r and p are too big");
-    }
-    if (r == 0 || p == 0)
-    {
-        securefs::throwInvalidArgumentException("r and p must not be zero");
-    }
-    if (((N & (N - 1)) != 0) || (N < 2))
-    {
-        throwInvalidArgumentException("N is not a power of 2");
-    }
-    if ((r > SIZE_MAX / 128 / p) ||
-#if SIZE_MAX / 256 <= UINT32_MAX
-        (r > SIZE_MAX / 256) ||
-#endif
-        (N > SIZE_MAX / 128 / r))
-    {
-        throwInvalidArgumentException("Would require too much memory");
-    }
-
-    /* Allocate memory. */
-    int rc;
-    if ((rc = posix_memalign(&B0, 64, 128 * r * p)) != 0)
-        THROW_POSIX_EXCEPTION(rc, "posix_memalign");
-    DEFER(posix_memalign_free(B0));
-    B = (uint8_t*)(B0);
-    if ((rc = posix_memalign(&XY0, 64, 256 * r + 64)) != 0)
-        THROW_POSIX_EXCEPTION(rc, "posix_memalign");
-    DEFER(posix_memalign_free(XY0));
-    XY = (uint32_t*)(XY0);
-#ifndef MAP_ANON
-    if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0)
-        THROW_POSIX_EXCEPTION(rc, "posix_memalign");
-    DEFER(posix_memalign_free(V0));
-    V = (uint32_t*)(V0);
-#endif
-#ifdef MAP_ANON
-    if ((V0 = mmap(NULL,
-                   128 * r * N,
-                   PROT_READ | PROT_WRITE,
-#ifdef MAP_NOCORE
-                   MAP_ANON | MAP_PRIVATE | MAP_NOCORE,
-#else
-                   MAP_ANON | MAP_PRIVATE,
-#endif
-                   -1,
-                   0))
-        == MAP_FAILED)
-        THROW_POSIX_EXCEPTION(errno, "mmap");
-    DEFER(munmap(V0, 128 * r * N));
-    V = (uint32_t*)(V0);
-#endif
-
-    /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
-    libscrypt_PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);
-
-    /* 2: for i = 0 to p - 1 do */
-    for (i = 0; i < p; i++)
-    {
-        /* 3: B_i <-- MF(B_i, N) */
-        smix(&B[i * 128 * r], r, N, V, XY);
-    }
-
-    /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
-    libscrypt_PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);
-}
-}    // namespace securefs
diff -pruN 0.11.1+ds-4/sources/securefs_config.in 0.13.1+ds-1/sources/securefs_config.in
--- 0.11.1+ds-4/sources/securefs_config.in	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/securefs_config.in	1970-01-01 00:00:00.000000000 +0000
@@ -1,5 +0,0 @@
-#pragma once
-#cmakedefine01 HAS_THREAD_LOCAL
-#cmakedefine01 HAS_CLOCK_GETTIME
-#cmakedefine01 HAS_FUTIMENS
-#cmakedefine01 HAS_UTIMENSAT
diff -pruN 0.11.1+ds-4/sources/streams.cpp 0.13.1+ds-1/sources/streams.cpp
--- 0.11.1+ds-4/sources/streams.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/streams.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -239,6 +239,10 @@ length_type BlockBasedStream::read(void*
 
 void BlockBasedStream::write(const void* input, offset_type offset, length_type length)
 {
+    if (length <= 0)
+    {
+        return;
+    }
     auto current_size = this->size();
     if (offset > current_size)
         unchecked_resize(current_size, offset);
@@ -563,4 +567,17 @@ make_cryptstream_aes_gcm(std::shared_ptr
                                                                 header_size);
     return {stream, stream};
 }
+
+PaddedStream::PaddedStream(std::shared_ptr<StreamBase> delegate, unsigned padding_size)
+    : m_delegate(std::move(delegate)), m_padding_size(padding_size)
+{
+    if (m_delegate->size() < padding_size)
+    {
+        auto buffer = make_unique_array<byte>(padding_size);
+        generate_random(buffer.get(), padding_size);
+        m_delegate->write(buffer.get(), 0, padding_size);
+    }
+}
+
+PaddedStream::~PaddedStream() {}
 }    // namespace securefs
diff -pruN 0.11.1+ds-4/sources/streams.h 0.13.1+ds-1/sources/streams.h
--- 0.11.1+ds-4/sources/streams.h	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/streams.h	2023-01-27 02:25:50.000000000 +0000
@@ -175,4 +175,44 @@ make_cryptstream_aes_gcm(std::shared_ptr
                          unsigned block_size,
                          unsigned iv_size,
                          unsigned header_size = 32);
+
+class PaddedStream final: public StreamBase
+{
+public:
+    explicit PaddedStream(std::shared_ptr<StreamBase> delegate, unsigned padding_size);
+    ~PaddedStream();
+
+    length_type read(void* output, offset_type offset, length_type length) override
+    {
+        return m_delegate->read(output, offset + m_padding_size, length);
+    }
+
+    void write(const void* input, offset_type offset, length_type length) override
+    {
+        return m_delegate->write(input, offset + m_padding_size, length);
+    }
+
+    length_type size() const override
+    {
+        auto dsize = m_delegate->size();
+        return dsize > m_padding_size ? dsize - m_padding_size : 0;
+    }
+
+    void flush() override { return m_delegate->flush(); }
+
+    void resize(length_type size) override { return m_delegate->resize(size + m_padding_size); }
+
+    bool is_sparse() const noexcept override { return m_delegate->is_sparse(); }
+
+    length_type optimal_block_size() const noexcept override
+    {
+        return m_delegate->optimal_block_size();
+    }
+
+    unsigned padding_size() const noexcept { return m_padding_size; }
+
+private:
+    std::shared_ptr<StreamBase> m_delegate;
+    unsigned m_padding_size;
+};
 }    // namespace securefs
diff -pruN 0.11.1+ds-4/sources/unix.cpp 0.13.1+ds-1/sources/unix.cpp
--- 0.11.1+ds-4/sources/unix.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/unix.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -6,8 +6,6 @@
 #include "platform.h"
 #include "streams.h"
 
-#include <securefs_config.h>
-
 #include <algorithm>
 #include <locale.h>
 #include <vector>
@@ -149,28 +147,9 @@ public:
 
     void utimens(const struct fuse_timespec ts[2]) override
     {
-#if HAS_FUTIMENS
         int rc = ::futimens(m_fd, ts);
         if (rc < 0)
             THROW_POSIX_EXCEPTION(errno, "utimens");
-#else
-        int rc;
-        if (!ts)
-            rc = ::futimes(m_fd, nullptr);
-        else
-        {
-            struct timeval time_values[2];
-            for (size_t i = 0; i < 2; ++i)
-            {
-                time_values[i].tv_sec = ts[i].tv_sec;
-                time_values[i].tv_usec
-                    = static_cast<decltype(time_values[i].tv_usec)>(ts[i].tv_nsec / 1000);
-            }
-            rc = ::futimes(m_fd, time_values);
-        }
-        if (rc < 0)
-            THROW_POSIX_EXCEPTION(errno, "futimes");
-#endif
     }
 
 #ifdef __APPLE__
@@ -423,29 +402,9 @@ ssize_t OSService::readlink(StringRef pa
 
 void OSService::utimens(StringRef path, const fuse_timespec* ts) const
 {
-    int rc;
-#if HAS_UTIMENSAT
-    rc = ::utimensat(m_dir_fd, path.c_str(), ts, AT_SYMLINK_NOFOLLOW);
+    int rc = ::utimensat(m_dir_fd, path.c_str(), ts, AT_SYMLINK_NOFOLLOW);
     if (rc < 0)
         THROW_POSIX_EXCEPTION(errno, "utimensat");
-#else
-    // When controls flows to here, the stub function has been called
-    if (!ts)
-    {
-        rc = ::lutimes(norm_path(path).c_str(), nullptr);
-    }
-    else
-    {
-        struct timeval tv[2];
-        tv[0].tv_sec = ts[0].tv_sec;
-        tv[0].tv_usec = ts[0].tv_nsec / 1000;
-        tv[1].tv_sec = ts[1].tv_sec;
-        tv[1].tv_usec = ts[1].tv_nsec / 1000;
-        rc = ::lutimes(norm_path(path).c_str(), tv);
-    }
-    if (rc < 0)
-        THROW_POSIX_EXCEPTION(errno, "lutimes");
-#endif
 }
 
 std::unique_ptr<DirectoryTraverser> OSService::create_traverser(StringRef dir) const
@@ -456,43 +415,35 @@ std::unique_ptr<DirectoryTraverser> OSSe
 uint32_t OSService::getuid() noexcept { return ::getuid(); }
 uint32_t OSService::getgid() noexcept { return ::getgid(); }
 
-int OSService::raise_fd_limit()
+int64_t OSService::raise_fd_limit() noexcept
 {
     struct rlimit rl;
     int rc = ::getrlimit(RLIMIT_NOFILE, &rl);
     if (rc < 0)
-        THROW_POSIX_EXCEPTION(errno, "getrlimit");
+    {
+        WARN_LOG("Failed to query limit of file descriptors. Error code: %d.", errno);
+        return 1024;
+    }
 
-    rl.rlim_cur = 10240 * 16;
-    do
+    if (rl.rlim_cur >= rl.rlim_max)
     {
-        rl.rlim_cur /= 2;
-        rc = ::setrlimit(RLIMIT_NOFILE, &rl);
-    } while (rc < 0 && rl.rlim_cur >= 1024);
+        return rl.rlim_cur;
+    }
 
+    auto current_limit = rl.rlim_cur;
+    rl.rlim_cur = rl.rlim_max;
+    rc = ::setrlimit(RLIMIT_NOFILE, &rl);
     if (rc < 0)
-        THROW_POSIX_EXCEPTION(errno, "setrlimit");
-
-    for (auto lim = rl.rlim_cur * 2 - 1, bound = rl.rlim_cur; lim >= bound; --lim)
     {
-        rl.rlim_cur = lim;
-        rc = ::setrlimit(RLIMIT_NOFILE, &rl);
-        if (rc == 0)
-            return static_cast<int>(lim);
+        WARN_LOG("Failed to set limit of file descriptors. Error code: %d.", errno);
+        return current_limit;
     }
-    THROW_POSIX_EXCEPTION(errno, "setrlimit");
+    return rl.rlim_cur;
 }
 
 void OSService::get_current_time(fuse_timespec& current_time)
 {
-#if HAS_CLOCK_GETTIME
     clock_gettime(CLOCK_REALTIME, &current_time);
-#else
-    timeval tv;
-    gettimeofday(&tv, nullptr);
-    current_time.tv_sec = tv.tv_sec;
-    current_time.tv_nsec = tv.tv_usec * 1000;
-#endif
 }
 
 #ifdef __APPLE__
@@ -502,15 +453,15 @@ ssize_t OSService::listxattr(const char*
     return rc < 0 ? -errno : rc;
 }
 
-ssize_t OSService::getxattr(const char* path, const char* name, void* buf, size_t size) const
-    noexcept
+ssize_t
+OSService::getxattr(const char* path, const char* name, void* buf, size_t size) const noexcept
 {
     auto rc = ::getxattr(norm_path(path).c_str(), name, buf, size, 0, XATTR_NOFOLLOW);
     return rc < 0 ? -errno : rc;
 }
 
-int OSService::setxattr(const char* path, const char* name, void* buf, size_t size, int flags) const
-    noexcept
+int OSService::setxattr(
+    const char* path, const char* name, void* buf, size_t size, int flags) const noexcept
 {
     auto rc = ::setxattr(norm_path(path).c_str(), name, buf, size, 0, flags | XATTR_NOFOLLOW);
     return rc < 0 ? -errno : rc;
@@ -618,55 +569,6 @@ std::string OSService::stringify_system_
     return postprocess_strerror(strerror_r(errcode, buffer, array_length(buffer)), buffer, errcode);
 }
 
-class POSIXColourSetter : public ConsoleColourSetter
-{
-public:
-    explicit POSIXColourSetter(FILE* fp) : m_fp(fp) {}
-
-    void use(Colour::Code _colourCode) noexcept override
-    {
-        switch (_colourCode)
-        {
-        case Colour::Default:
-            return setColour("[0;39m");
-        case Colour::White:
-            return setColour("[0m");
-        case Colour::Red:
-            return setColour("[0;31m");
-        case Colour::Green:
-            return setColour("[0;32m");
-        case Colour::Blue:
-            return setColour("[0:34m");
-        case Colour::Cyan:
-            return setColour("[0;36m");
-        case Colour::Yellow:
-            return setColour("[0;33m");
-        case Colour::Grey:
-            return setColour("[1;30m");
-
-        case Colour::LightGrey:
-            return setColour("[0;37m");
-        case Colour::BrightRed:
-            return setColour("[1;31m");
-        case Colour::BrightGreen:
-            return setColour("[1;32m");
-        case Colour::BrightWhite:
-            return setColour("[1;37m");
-
-        default:
-            break;
-        }
-    }
-
-private:
-    FILE* m_fp;
-    void setColour(const char* _escapeCode) noexcept
-    {
-        putc('\033', m_fp);
-        fputs(_escapeCode, m_fp);
-    }
-};
-
 std::unique_ptr<ConsoleColourSetter> ConsoleColourSetter::create_setter(FILE* fp)
 {
     if (!fp || !::isatty(::fileno(fp)))
@@ -685,5 +587,24 @@ std::unique_ptr<const char, void (*)(con
 
 const char* PATH_SEPARATOR_STRING = "/";
 const char PATH_SEPARATOR_CHAR = '/';
+
+Mutex::Mutex() {}
+Mutex::~Mutex() {}
+
+void Mutex::lock() { m_std.lock(); }
+
+void Mutex::unlock() noexcept
+{
+    try
+    {
+        m_std.unlock();
+    }
+    catch (const std::exception& e)
+    {
+        ERROR_LOG("std::mutex::unlock() throws %s: %s", get_type_name(e).get(), e.what());
+    }
+}
+bool Mutex::try_lock() { return m_std.try_lock(); }
+
 }    // namespace securefs
 #endif
diff -pruN 0.11.1+ds-4/sources/win.cpp 0.13.1+ds-1/sources/win.cpp
--- 0.11.1+ds-4/sources/win.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/sources/win.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -2,6 +2,7 @@
 #include "lock_enabled.h"
 #include "logger.h"
 #include "platform.h"
+#include "win_get_proc.h"
 
 #include <winfsp/winfsp.h>
 
@@ -11,7 +12,6 @@
 #include <mutex>
 #include <stdint.h>
 #include <stdlib.h>
-#include <sys/stat.h>
 #include <sys/utime.h>
 #include <time.h>
 #include <typeinfo>
@@ -75,7 +75,6 @@ public:
     std::string message() const override
     {
         wchar_t system_buffer[2000];
-        wchar_t final_buffer[6000];
         if (!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
                             nullptr,
                             err,
@@ -96,10 +95,12 @@ public:
                 break;
         }
 
+        std::vector<wchar_t> final_buffer(path1.size() + path2.size() + wcslen(system_buffer)
+                                          + wcslen(funcname) + 100);
         if (!path1.empty() && !path2.empty())
         {
-            StringCchPrintfW(final_buffer,
-                             array_length(final_buffer),
+            StringCchPrintfW(final_buffer.data(),
+                             final_buffer.size(),
                              L"error %lu %s (%s(path1=%s, path2=%s))",
                              err,
                              system_buffer,
@@ -109,8 +110,8 @@ public:
         }
         else if (!path1.empty())
         {
-            StringCchPrintfW(final_buffer,
-                             array_length(final_buffer),
+            StringCchPrintfW(final_buffer.data(),
+                             final_buffer.size(),
                              L"error %lu %s (%s(path=%s))",
                              err,
                              system_buffer,
@@ -119,14 +120,14 @@ public:
         }
         else
         {
-            StringCchPrintfW(final_buffer,
-                             array_length(final_buffer),
+            StringCchPrintfW(final_buffer.data(),
+                             final_buffer.size(),
                              L"error %lu %s (%s)",
                              err,
                              system_buffer,
                              funcname);
         }
-        return narrow_string(final_buffer);
+        return narrow_string(final_buffer.data());
     }
     DWORD win32_code() const noexcept { return err; }
     int error_number() const noexcept override
@@ -465,7 +466,6 @@ class WindowsFileStream final : public F
 {
 private:
     HANDLE m_handle;
-    bool m_is_ntfs;
 
 private:
     void write32(const void* input, offset_type offset, DWORD length)
@@ -522,7 +522,7 @@ private:
 
 public:
     explicit WindowsFileStream(WideStringRef path, int flags, unsigned mode)
-        : m_handle(INVALID_HANDLE_VALUE), m_is_ntfs(false)
+        : m_handle(INVALID_HANDLE_VALUE)
     {
         DWORD access_flags = 0;
         switch (flags & O_ACCMODE)
@@ -545,6 +545,9 @@ public:
         {
             if (flags & O_EXCL)
                 create_flags = CREATE_NEW;
+            else if (flags & O_TRUNC)
+                throwInvalidArgumentException(
+                    "On Windows, O_TRUNC cannot be specified together with O_CREAT");
             else
                 create_flags = OPEN_ALWAYS;
         }
@@ -569,15 +572,6 @@ public:
             DWORD err = GetLastError();
             throw WindowsException(err, L"CreateFileW", path.to_string());
         }
-
-        wchar_t fsname[128];
-        if (!GetVolumeInformationByHandleW(
-                m_handle, nullptr, 0, nullptr, nullptr, 0, fsname, array_length(fsname)))
-            return;
-        m_is_ntfs = (CompareStringEx(
-                         LOCALE_NAME_INVARIANT, NORM_IGNORECASE, fsname, -1, L"NTFS", -1, 0, 0, 0)
-                     == CSTR_EQUAL);
-        TRACE_LOG("Opening file on a %s volume", narrow_string(fsname).c_str());
     }
 
     ~WindowsFileStream() { CloseHandle(m_handle); }
@@ -651,8 +645,6 @@ public:
 
     void write(const void* input, offset_type offset, length_type length) override
     {
-        if (offset > size())
-            resize(offset + length);    // Ensure that intervening data is zeroed
         while (length > MAX_SINGLE_BLOCK)
         {
             write32(input, offset, MAX_SINGLE_BLOCK);
@@ -685,20 +677,6 @@ public:
 
     void resize(length_type len) override
     {
-        if (!m_is_ntfs)
-        {
-            // For files on other filesystems, SetEndOfFile beyond end will leave intervening bytes
-            // uninitialized
-            // Manually zeroing ourselves
-            auto old_size = this->size();
-            if (old_size < len)
-            {
-                const char buffer[4096] = {0};
-                for (size_t sz = old_size; sz < len; sz += sizeof(buffer))
-                    write32(buffer, sz, std::min<size_t>(sizeof(buffer), len - sz));
-                return;
-            }
-        }
         LARGE_INTEGER llen;
         llen.QuadPart = len;
         CHECK_CALL(SetFilePointerEx(m_handle, llen, nullptr, FILE_BEGIN));
@@ -724,7 +702,7 @@ public:
         CHECK_CALL(SetFileTime(m_handle, nullptr, &access_time, &mod_time));
     }
     void fstat(struct fuse_stat* st) const override { stat_file_handle(m_handle, st); }
-    bool is_sparse() const noexcept override { return m_is_ntfs; }
+    bool is_sparse() const noexcept override { return true; }
 };
 
 OSService::OSService() : m_root_handle(INVALID_HANDLE_VALUE) {}
@@ -737,6 +715,90 @@ bool OSService::is_absolute(StringRef pa
         || (path.size() >= 2 && path[1] == ':');
 }
 
+namespace
+{
+    const StringRef LONG_PATH_PREFIX = R"(\\?\)";
+
+    bool is_canonical(StringRef path)
+    {
+        if (path.empty())
+        {
+            return true;
+        }
+        if (!path.starts_with(LONG_PATH_PREFIX))
+            return false;
+        size_t last_boundary = LONG_PATH_PREFIX.size();
+        for (size_t i = last_boundary; i <= path.size(); ++i)
+        {
+            bool is_boundary = i >= path.size() || path[i] == '\\';
+            if (!is_boundary)
+            {
+                continue;
+            }
+            if (i == last_boundary || i == last_boundary + 1)
+            {
+                return false;
+            }
+            if (i == last_boundary + 2 && path[last_boundary + 1] == '.')
+            {
+                return false;
+            }
+            if (i == last_boundary + 3 && path[last_boundary + 1] == '.'
+                && path[last_boundary + 2] == '.')
+            {
+                return false;
+            }
+            last_boundary = i;
+        }
+        return true;
+    }
+
+    // Convert forward slashes to back slashes, and remove "." and ".." from path components
+    void canonicalize(std::string& prepath)
+    {
+        for (char& c : prepath)
+        {
+            if (c == '/')
+                c = '\\';
+        }
+        if (is_canonical(prepath))
+        {
+            return;
+        }
+        std::vector<std::string> components = split(prepath, '\\');
+        std::vector<const std::string*> norm_components;
+        norm_components.reserve(components.size());
+        for (const std::string& name : components)
+        {
+            if (name.empty() || name == ".")
+                continue;
+            if (name == "..")
+            {
+                if (norm_components.size() > 0)
+                    norm_components.pop_back();
+                continue;
+            }
+            norm_components.push_back(&name);
+        }
+        bool is_already_universal = prepath.size() >= 2 && prepath[0] == '\\' && prepath[1] == '\\';
+
+        prepath.clear();
+        if (is_already_universal)
+        {
+            prepath.push_back('\\');
+        }
+        else
+        {
+            prepath.assign(("\\\\?"));
+        }
+        for (const std::string* name : norm_components)
+        {
+            prepath.push_back('\\');
+            prepath.append(*name);
+        }
+    }
+}    // namespace
+
 native_string_type OSService::concat_and_norm(StringRef base_dir, StringRef path)
 {
     if (base_dir.empty() || is_absolute(path))
@@ -748,55 +810,26 @@ native_string_type OSService::concat_and
         throwInvalidArgumentException("base_dir must be an absolute path, yet we received "
                                       + base_dir);
     }
-    std::string prepath = base_dir.to_string();
-    prepath.reserve(prepath.size() + 1 + path.size());
-    prepath.push_back('\\');
-    prepath.append(path.data(), path.size());
-    for (char& c : prepath)
-    {
-        if (c == '/')
-            c = '\\';
-    }
-    std::vector<std::string> components = split(prepath, '\\');
-    std::vector<const std::string*> norm_components;
-    norm_components.reserve(components.size());
-    for (const std::string& name : components)
-    {
-        if (name.empty() || name == ".")
-            continue;
-        if (name == "..")
-        {
-            if (norm_components.size() > 0)
-                norm_components.pop_back();
-            continue;
-        }
-        norm_components.push_back(&name);
-    }
-    std::string str;
-    str.reserve(prepath.size() + 8);
-    bool is_already_universal = prepath.size() >= 2 && prepath[0] == '\\' && prepath[1] == '\\';
-    if (is_already_universal)
+    std::string prepath;
+    if (path == ".")
     {
-        str.push_back('\\');
+        prepath = base_dir.to_string();
     }
     else
     {
-        str.assign(("\\\\?"));
-    }
-    for (const std::string* name : norm_components)
-    {
-        str.push_back('\\');
-        str.append(*name);
+        prepath.reserve(prepath.size() + 1 + path.size());
+        prepath.append(base_dir.c_str(), base_dir.size());
+        prepath.push_back('\\');
+        prepath.append(path.data(), path.size());
     }
-    return widen_string(str);
+    canonicalize(prepath);
+    return widen_string(prepath);
 }
 
 OSService::OSService(StringRef path)
 {
-    wchar_t resolved[4000];
-    CHECK_CALL(GetFullPathNameW(widen_string(path).c_str(), 4000, resolved, nullptr));
-    m_dir_name = narrow_string(resolved);
-    m_root_handle = CreateFileW(resolved,
+    auto wide_path = widen_string(path);
+    m_root_handle = CreateFileW(wide_path.c_str(),
                                 GENERIC_READ,
                                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                                 nullptr,
@@ -804,7 +837,15 @@ OSService::OSService(StringRef path)
                                 FILE_FLAG_BACKUP_SEMANTICS,
                                 nullptr);
     if (m_root_handle == INVALID_HANDLE_VALUE)
-        THROW_WINDOWS_EXCEPTION_WITH_PATH(GetLastError(), L"CreateFileW", resolved);
+        THROW_WINDOWS_EXCEPTION_WITH_PATH(GetLastError(), L"CreateFileW", wide_path);
+    std::wstring fullname(33000, 0);
+    DWORD size = GetFinalPathNameByHandleW(m_root_handle, &fullname[0], fullname.size(), 0);
+    if (size <= 0)
+    {
+        THROW_WINDOWS_EXCEPTION(GetLastError(), L"GetFinalPathNameByHandleW");
+    }
+    fullname.resize(size);
+    m_dir_name = narrow_string(fullname);
 }
 
 std::shared_ptr<FileStream>
@@ -939,10 +980,10 @@ void OSService::rename(StringRef a, Stri
         THROW_WINDOWS_EXCEPTION_WITH_TWO_PATHS(GetLastError(), L"MoveFileExW", wa, wb);
 }
 
-int OSService::raise_fd_limit()
+int64_t OSService::raise_fd_limit() noexcept
 {
-    return 65535;
     // The handle limit on Windows is high enough that no adjustments are necessary
+    return std::numeric_limits<int32_t>::max();
 }
 
 class WindowsDirectoryTraverser final : public DirectoryTraverser
@@ -1101,28 +1142,12 @@ std::string OSService::stringify_system_
     return buffer;
 }
 
-void windows_init(void)
+std::wstring widen_string(StringRef str)
 {
-    ::SetConsoleOutputCP(CP_UTF8);
-    // Use a large buffer to prevent Windows from chopping valid UTF-8 sequences.
-    setvbuf(stdout, nullptr, _IOFBF, 65535);
-    setvbuf(stderr, nullptr, _IOFBF, 65535);
-    if (::FspLoad(nullptr) != STATUS_SUCCESS)
+    if (str.empty())
     {
-        fputs("SecureFS cannot load WinFsp. Please make sure you have WinFsp properly installed.\n",
-              stderr);
-        abort();
+        return {};
     }
-
-    HMODULE hd = GetModuleHandleW(L"kernel32.dll");
-    best_get_time_func = reinterpret_cast<decltype(best_get_time_func)>(
-        GetProcAddress(hd, "GetSystemTimePreciseAsFileTime"));
-    if (best_get_time_func == nullptr)
-        best_get_time_func = &GetSystemTimeAsFileTime;
-}
-
-std::wstring widen_string(StringRef str)
-{
     if (str.size() >= std::numeric_limits<int>::max())
         throwInvalidArgumentException("String too long");
     int sz = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), static_cast<int>(str.size()), nullptr, 0);
@@ -1135,6 +1160,10 @@ std::wstring widen_string(StringRef str)
 
 std::string narrow_string(WideStringRef str)
 {
+    if (str.empty())
+    {
+        return {};
+    }
     if (str.size() >= std::numeric_limits<int>::max())
         throwInvalidArgumentException("String too long");
     int sz = WideCharToMultiByte(
@@ -1147,76 +1176,48 @@ std::string narrow_string(WideStringRef
     return result;
 }
 
-class WindowsColourSetter : public ConsoleColourSetter
+namespace
 {
-private:
-    HANDLE hd;
-    WORD originalForegroundAttributes;
-    WORD originalBackgroundAttributes;
-
-    void setTextAttribute(WORD _textAttribute) noexcept
+    struct ConsoleTestResult
     {
-        SetConsoleTextAttribute(hd, _textAttribute | originalBackgroundAttributes);
-    }
+        bool is_console = false;
+        HANDLE handle = INVALID_HANDLE_VALUE;
+        DWORD mode = 0;
+    };
 
-public:
-    explicit WindowsColourSetter(HANDLE hd) : hd(hd)
+    ConsoleTestResult test_console(FILE* fp)
     {
-        CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
-        GetConsoleScreenBufferInfo(hd, &csbiInfo);
-        originalForegroundAttributes = csbiInfo.wAttributes
-            & ~(BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
-        originalBackgroundAttributes = csbiInfo.wAttributes
-            & ~(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
-    }
-
-    void use(Colour::Code _colourCode) noexcept override
-    {
-        switch (_colourCode)
-        {
-        case Colour::Default:
-            return setTextAttribute(originalForegroundAttributes);
-        case Colour::White:
-            return setTextAttribute(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE);
-        case Colour::Red:
-            return setTextAttribute(FOREGROUND_RED);
-        case Colour::Green:
-            return setTextAttribute(FOREGROUND_GREEN);
-        case Colour::Blue:
-            return setTextAttribute(FOREGROUND_BLUE);
-        case Colour::Cyan:
-            return setTextAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN);
-        case Colour::Yellow:
-            return setTextAttribute(FOREGROUND_RED | FOREGROUND_GREEN);
-        case Colour::Grey:
-            return setTextAttribute(0);
-
-        case Colour::LightGrey:
-            return setTextAttribute(FOREGROUND_INTENSITY);
-        case Colour::BrightRed:
-            return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_RED);
-        case Colour::BrightGreen:
-            return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_GREEN);
-        case Colour::BrightWhite:
-            return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED
-                                    | FOREGROUND_BLUE);
-
-        default:
-            break;
+        if (!fp)
+        {
+            return {};
         }
+        int fd = _fileno(fp);
+        if (fd < 0)
+        {
+            return {};
+        }
+        auto h = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+        if (h == INVALID_HANDLE_VALUE)
+        {
+            return {};
+        }
+        ConsoleTestResult result;
+        result.handle = h;
+        result.is_console = GetConsoleMode(h, &result.mode);
+        return result;
     }
-};
+}    // namespace
 
 std::unique_ptr<ConsoleColourSetter> ConsoleColourSetter::create_setter(FILE* fp)
 {
-    if (!fp)
+    auto t = test_console(fp);
+    if (!t.is_console)
         return {};
-
-    auto hd = reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(fp)));
-    DWORD mode;
-    if (!GetConsoleMode(hd, &mode))
-        return {};    // Not a console
-    return securefs::make_unique<WindowsColourSetter>(hd);
+    if (!SetConsoleMode(t.handle, t.mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING))
+    {
+        return {};
+    }
+    return securefs::make_unique<POSIXColourSetter>(fp);
 }
 
 std::unique_ptr<const char, void (*)(const char*)> get_type_name(const std::exception& e) noexcept
@@ -1226,6 +1227,46 @@ std::unique_ptr<const char, void (*)(con
 
 const char* PATH_SEPARATOR_STRING = "\\";
 const char PATH_SEPARATOR_CHAR = '\\';
+
+void windows_init(void)
+{
+    static auto original_cp = ::GetConsoleOutputCP();
+    ::SetConsoleOutputCP(CP_UTF8);
+    atexit([]() { ::SetConsoleOutputCP(original_cp); });
+    _set_invalid_parameter_handler(
+        [](wchar_t const*, wchar_t const*, wchar_t const*, unsigned int, uintptr_t) {});
+
+    if (test_console(stdout).is_console)
+    {
+        setvbuf(stdout, nullptr, _IOLBF, 65536);
+    }
+    if (test_console(stderr).is_console)
+    {
+        setvbuf(stderr, nullptr, _IOLBF, 65536);
+    }
+    if (::FspLoad(nullptr) != STATUS_SUCCESS)
+    {
+        fputs("SecureFS cannot load WinFsp. Please make sure you have WinFsp properly installed.\n",
+              stderr);
+        abort();
+    }
+
+    HMODULE hd = GetModuleHandleW(L"kernel32.dll");
+
+    best_get_time_func
+        = get_proc_address<decltype(best_get_time_func)>(hd, "GetSystemTimePreciseAsFileTime");
+    if (best_get_time_func == nullptr)
+        best_get_time_func = &GetSystemTimeAsFileTime;
+}
+
+Mutex::Mutex() { ::InitializeCriticalSectionAndSpinCount(&m_cs, 4000); }
+Mutex::~Mutex() { ::DeleteCriticalSection(&m_cs); }
+
+void Mutex::lock() { ::EnterCriticalSection(&m_cs); }
+
+void Mutex::unlock() noexcept { ::LeaveCriticalSection(&m_cs); }
+
+bool Mutex::try_lock() { return ::TryEnterCriticalSection(&m_cs); }
 }    // namespace securefs
 
-#endif
\ No newline at end of file
+#endif
diff -pruN 0.11.1+ds-4/sources/win_get_proc.h 0.13.1+ds-1/sources/win_get_proc.h
--- 0.11.1+ds-4/sources/win_get_proc.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/sources/win_get_proc.h	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+#pragma once
+#ifdef _WIN32
+#include <Windows.h>
+
+namespace securefs
+{
+#pragma warning(push)
+#pragma warning(disable : 4191)
+template <class FuncPointer>
+inline FuncPointer get_proc_address(HMODULE h, const char* name) noexcept
+{
+    return reinterpret_cast<FuncPointer>(::GetProcAddress(h, name));
+}
+#pragma warning(pop)
+
+}    // namespace securefs
+#endif
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.argon2id.KEYFILE2.json 0.13.1+ds-1/test/reference/1/.securefs.argon2id.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1/.securefs.argon2id.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.argon2id.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"encrypted_key" : 
+	{
+		"IV" : "59d6eb6f796698889ae9b219501c468cfb569393def17df4868e2f7307016917",
+		"MAC" : "d827d1b0ab5a9c52174a0e7893054669",
+		"key" : "01ed274824b9f9c2e1d4e1ffa938010f82771a536e9d7e9a972e948865e56484"
+	},
+	"iterations" : 2,
+	"pbkdf" : "argon2id",
+	"salt" : "7f305c99aac6f1e5cf169ad0490c784b0d0dfa330183c6e1b91588b76ae8590a",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.argon2id.KEYFILE.json 0.13.1+ds-1/test/reference/1/.securefs.argon2id.KEYFILE.json
--- 0.11.1+ds-4/test/reference/1/.securefs.argon2id.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.argon2id.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"encrypted_key" : 
+	{
+		"IV" : "b7f3dc8622a8b847e8b083dcf2598885dff6f921755438c1d2dc4f5f7b7d2d1d",
+		"MAC" : "db93f06bda984ab90cd01badb482ec19",
+		"key" : "8e3e7f39b869a8a13de867d3df2afd28530d1bdbf0f848a2bdb5de4130402f2d"
+	},
+	"iterations" : 2,
+	"pbkdf" : "argon2id",
+	"salt" : "91a81dcea607fc87ae80d2ebf26b2c4a1d8850edd5e7674a0a7c0b08f1f1ae84",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.argon2id.PASSWORD.json 0.13.1+ds-1/test/reference/1/.securefs.argon2id.PASSWORD.json
--- 0.11.1+ds-4/test/reference/1/.securefs.argon2id.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.argon2id.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"encrypted_key" : 
+	{
+		"IV" : "6ed9637f706afc59ca4e4ff99aa40f65d3aef69e9e4b32bd4967b7fabca7b302",
+		"MAC" : "c187c7cdec11bd99feb8d0db21536535",
+		"key" : "aa827f794a411e23a776a009e1035710d1aedc354600122193dc4e86fd6a4ffd"
+	},
+	"iterations" : 2,
+	"pbkdf" : "argon2id",
+	"salt" : "a611dfa8531d37a77b9954a4b8bb391c2aa3114c4ca0cfefbc63e3cd125f0c64",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/1/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"encrypted_key" : 
+	{
+		"IV" : "0f51315e7db8318b6ab2462be266103e4c9d7a8611089e416e7c5c429315e615",
+		"MAC" : "b79df105e7431a3e1d5b78c8af9c114e",
+		"key" : "4d8b20118f6ac5dd0e10539e19463afd9e90305f42c00aa4a8708d852e796618"
+	},
+	"iterations" : 2,
+	"pbkdf" : "argon2id",
+	"salt" : "26dc7010a1c0977f82d4cb5a1ab0eedc66b4f5fcafc0ca9fb36b56cbfb22e31c",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/1/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/1/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"encrypted_key" : 
+	{
+		"IV" : "b35297fb6ff5402f8fac6819f9f0e8460a701d4af3a09e15220e529c4a29a08b",
+		"MAC" : "9b9981c57b606ccc1b6376d95db3b110",
+		"key" : "1b4601146360b33b138bcd984d508193e7d942b175e55d0c46c1f4879b216421"
+	},
+	"iterations" : 2,
+	"pbkdf" : "argon2id",
+	"salt" : "4871498bbd39140706470c9dcd6953d21047c063fc66033f7ec25506920c222e",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.json 0.13.1+ds-1/test/reference/1/.securefs.json
--- 0.11.1+ds-4/test/reference/1/.securefs.json	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.json	1970-01-01 00:00:00.000000000 +0000
@@ -1,14 +0,0 @@
-{
-	"encrypted_key" : 
-	{
-		"IV" : "96707fbb18971bc858dd8e440fb2f3f9b9ee3ca96681f347b59a6486b5fa341e",
-		"MAC" : "d08dbc139f5e4ce97519bfcaf0ca2487",
-		"key" : "9af7f99ea25f99d63b7d66d9b67bdde25fa642e1307b3f42c7dafb7ced9d2513"
-	},
-	"iterations" : 4,
-	"pbkdf" : "scrypt",
-	"salt" : "3c2308da67ebbd2243cc96fce261092153662781ddf8952eb3fea96ddbee6ca3",
-	"scrypt_p" : 1,
-	"scrypt_r" : 8,
-	"version" : 1
-}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json 0.13.1+ds-1/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,12 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "26e1fb1676d530e4b312cb014879e8490ebdc648c141f3bb4768b2ac51891fc1",
+		"MAC" : "a5fab68a856f02a638ba44ba9a11c4ed",
+		"key" : "ee4892ff486d4c8e2778dd57413779d90c6623a0b8ddf2102c530cefd8e53665"
+	},
+	"iterations" : 2,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "c65adc4a4a18ea272d93cc61d6978f744d01f786d97c62c24d7cf2a2a786f54f",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json 0.13.1+ds-1/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json
--- 0.11.1+ds-4/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,12 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "c79cbe3fc661354477ca23b9758f2e224c6ac27454cf3488a48c9aba754bf76b",
+		"MAC" : "6b7ef9fa88f34f2f27e5de131b255319",
+		"key" : "7425ef5479e03f2909884a0abe30145d9166229f78815391a79c1ad608003e98"
+	},
+	"iterations" : 2,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "84fd9f9019402af416954a31318f1cae718856870c890e7163784e0501eb98bf",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json 0.13.1+ds-1/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json
--- 0.11.1+ds-4/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,12 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "662242ec5cf7f44878de0f83508c7cefa3dee9347da3f50906d7c25ddea1aa10",
+		"MAC" : "865e12e73a9d09fb3efe0ebaf086680b",
+		"key" : "28198c5835eaa76a2cb629407abc74931de34fee90c12afc1668bc8f51d71250"
+	},
+	"iterations" : 2,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "ea16fed7af963accc32cce3921af7a0824481e56b462c7dacc25b46df24c1587",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,12 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "a9e10bf5d5fc936936b9d41e47283f13e2fcad58222e6c1947eccadb9696d2dc",
+		"MAC" : "61f21bbe8d2a58b61e44618f74dfdbd4",
+		"key" : "6386ff9be67fa7fd7a6beefe2f3034b71889c8ad22a2dea20c5512ecca7eaa1c"
+	},
+	"iterations" : 2,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "360d5cd35b82c80e0bb746a560324d2e8a17c1139c443d8013a3b2baff8e8d46",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,12 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "4c5b6c6aeba12dd127ddebf6b1427aace4d6d27ce2ceb7e90b27760e4480fc1d",
+		"MAC" : "19f732d4ca9029dc550359bcebd760c5",
+		"key" : "ade9acbc43e4dd19199b6cdd3d7b4779c15d2249ef382c8f7945e741efc1ecd8"
+	},
+	"iterations" : 2,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "8271d4a2e29cb0909daf1e3ea9a0644ee43dd028d7f0fecc90f27d915e6d3fa1",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.scrypt.KEYFILE2.json 0.13.1+ds-1/test/reference/1/.securefs.scrypt.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1/.securefs.scrypt.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.scrypt.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "c2e28681344bf968ce681b5ccb8f712377c8599f610c2cb2201c745b78a17f6a",
+		"MAC" : "dd84e978e671cddd1cdc4bb89a2dfc8e",
+		"key" : "b95cde9f085953e48fc8dd2fe1731833f0022b2fa6696e238f9eb2efab02931e"
+	},
+	"iterations" : 2,
+	"pbkdf" : "scrypt",
+	"salt" : "7f4093c84b3d4613f4b0e407d40cc8bd8539fd23430ec0a7632e4d169cf2d65f",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.scrypt.KEYFILE.json 0.13.1+ds-1/test/reference/1/.securefs.scrypt.KEYFILE.json
--- 0.11.1+ds-4/test/reference/1/.securefs.scrypt.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.scrypt.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "bc8ab97167c9eecef4d9df7cde003c124f6eb652416c01d6f798ea0a57a1b1b7",
+		"MAC" : "8465d840caa6f23a4ecaf8e604168239",
+		"key" : "fc616e9a6cc9bde3ddcfa8c43084802d395bd70ad5b5801cb1c5db61a247e0a8"
+	},
+	"iterations" : 2,
+	"pbkdf" : "scrypt",
+	"salt" : "57d006a9ec155872ea1f9642e30d082826dbc53620dd190716201069212a517b",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.scrypt.PASSWORD.json 0.13.1+ds-1/test/reference/1/.securefs.scrypt.PASSWORD.json
--- 0.11.1+ds-4/test/reference/1/.securefs.scrypt.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.scrypt.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "2680252c6d8f4291efef1b39556b6c318266e6e0cc1dbdc822056e0d3ed5ed60",
+		"MAC" : "857eecc3cddee4a111819b1c4de41a41",
+		"key" : "b9218e93c80e1ff5df48abef12dc3a60a264ba541ca25089b5f7b1b0b7c330b7"
+	},
+	"iterations" : 2,
+	"pbkdf" : "scrypt",
+	"salt" : "93d0713d77dff07041220574656a793d3e8235a1f4ed381a3ef0f5e6fb4b3525",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/1/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "b8af4117c2488e1a38925a3ad0d6418042950cba8e66bf33f25c03698e3f693f",
+		"MAC" : "8b86f2292e127e19416ade4d38b7bd39",
+		"key" : "aca6803eb41f0514355d1b4912057af7e28f17ccdedcee812e40b649a3aa6a33"
+	},
+	"iterations" : 2,
+	"pbkdf" : "scrypt",
+	"salt" : "6069c1b4f1be3c03d8afc0477bcb4d781e5ee8cc599d7cde2e344c1d6b97135c",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/1/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/1/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "48753f30f81c8b6cb86cc55857ea3f1f7bcba3e1c5a13777838680891be88199",
+		"MAC" : "4df3938f6de52d52153cc5869c5f222f",
+		"key" : "6b0005fc1eeff062b3782fe3d867b13a7afaa5e30f5a3caf759d01f24be36734"
+	},
+	"iterations" : 2,
+	"pbkdf" : "scrypt",
+	"salt" : "2fd7d476065b24ef80f0d6ee8d9f531605307e351612393b3088de304cc84a1b",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 1
+}
Binary files 0.11.1+ds-4/test/reference/1-keyfile/00/0000000000/0000000000000000000000000000000000000000000000000000 and 0.13.1+ds-1/test/reference/1-keyfile/00/0000000000/0000000000000000000000000000000000000000000000000000 differ
diff -pruN 0.11.1+ds-4/test/reference/1-keyfile/00/0000000000/0000000000000000000000000000000000000000000000000000.meta 0.13.1+ds-1/test/reference/1-keyfile/00/0000000000/0000000000000000000000000000000000000000000000000000.meta
--- 0.11.1+ds-4/test/reference/1-keyfile/00/0000000000/0000000000000000000000000000000000000000000000000000.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-keyfile/00/0000000000/0000000000000000000000000000000000000000000000000000.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-R|}Q,/VJvϏPzfMlVznʡmet*Sxэ|jAb<gȏt]-UOBYc&*XHMy'=ИSs6z5L\7Ikvc
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/1-keyfile/2a/68cdc45aae/1248e0b852cec63d389c2af2a9c4b0c731563ae0dad86bd4c58b and 0.13.1+ds-1/test/reference/1-keyfile/2a/68cdc45aae/1248e0b852cec63d389c2af2a9c4b0c731563ae0dad86bd4c58b differ
Binary files 0.11.1+ds-4/test/reference/1-keyfile/2a/68cdc45aae/1248e0b852cec63d389c2af2a9c4b0c731563ae0dad86bd4c58b.meta and 0.13.1+ds-1/test/reference/1-keyfile/2a/68cdc45aae/1248e0b852cec63d389c2af2a9c4b0c731563ae0dad86bd4c58b.meta differ
diff -pruN 0.11.1+ds-4/test/reference/1-keyfile/3a/5b2f34f0f9/2f6b3596b8815ed0a79b4261fd3888e962f7f355f79461836338 0.13.1+ds-1/test/reference/1-keyfile/3a/5b2f34f0f9/2f6b3596b8815ed0a79b4261fd3888e962f7f355f79461836338
--- 0.11.1+ds-4/test/reference/1-keyfile/3a/5b2f34f0f9/2f6b3596b8815ed0a79b4261fd3888e962f7f355f79461836338	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-keyfile/3a/5b2f34f0f9/2f6b3596b8815ed0a79b4261fd3888e962f7f355f79461836338	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-/}[
\ No newline at end of file
diff -pruN 0.11.1+ds-4/test/reference/1-keyfile/3a/5b2f34f0f9/2f6b3596b8815ed0a79b4261fd3888e962f7f355f79461836338.meta 0.13.1+ds-1/test/reference/1-keyfile/3a/5b2f34f0f9/2f6b3596b8815ed0a79b4261fd3888e962f7f355f79461836338.meta
--- 0.11.1+ds-4/test/reference/1-keyfile/3a/5b2f34f0f9/2f6b3596b8815ed0a79b4261fd3888e962f7f355f79461836338.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-keyfile/3a/5b2f34f0f9/2f6b3596b8815ed0a79b4261fd3888e962f7f355f79461836338.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-~ো*}EG3ְæ[wE	JtU`a,\(.!8R\ê%AMX43c/>|Eh=uv?̚xv8v;,fRXfi)jyCa? |v&p*H݋y
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/1-keyfile/63/bea02d1397/e9f978d9c5001cfe46605bda93977e297ae9878ed4a0b032b552 and 0.13.1+ds-1/test/reference/1-keyfile/63/bea02d1397/e9f978d9c5001cfe46605bda93977e297ae9878ed4a0b032b552 differ
Binary files 0.11.1+ds-4/test/reference/1-keyfile/63/bea02d1397/e9f978d9c5001cfe46605bda93977e297ae9878ed4a0b032b552.meta and 0.13.1+ds-1/test/reference/1-keyfile/63/bea02d1397/e9f978d9c5001cfe46605bda93977e297ae9878ed4a0b032b552.meta differ
Binary files 0.11.1+ds-4/test/reference/1-keyfile/81/1499cf223a/720888e40f11813bbf53235049aa11e18d4285792c8a06ac3684 and 0.13.1+ds-1/test/reference/1-keyfile/81/1499cf223a/720888e40f11813bbf53235049aa11e18d4285792c8a06ac3684 differ
diff -pruN 0.11.1+ds-4/test/reference/1-keyfile/81/1499cf223a/720888e40f11813bbf53235049aa11e18d4285792c8a06ac3684.meta 0.13.1+ds-1/test/reference/1-keyfile/81/1499cf223a/720888e40f11813bbf53235049aa11e18d4285792c8a06ac3684.meta
--- 0.11.1+ds-4/test/reference/1-keyfile/81/1499cf223a/720888e40f11813bbf53235049aa11e18d4285792c8a06ac3684.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-keyfile/81/1499cf223a/720888e40f11813bbf53235049aa11e18d4285792c8a06ac3684.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-rqks*F4CMYxm\V{h4SIoj }lk-*û)DZǳfrƊ0fІMwpn8kghx
- ?sōIw^D8FNSf5;_#cODF	YOñkj$㓉K+Oc߆f%zXÅ>ȸ
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/1-keyfile/97/613cb45ec0/22757346db2b9eddd9458b950d45411c1ed01ea49aae273507f3 and 0.13.1+ds-1/test/reference/1-keyfile/97/613cb45ec0/22757346db2b9eddd9458b950d45411c1ed01ea49aae273507f3 differ
Binary files 0.11.1+ds-4/test/reference/1-keyfile/97/613cb45ec0/22757346db2b9eddd9458b950d45411c1ed01ea49aae273507f3.meta and 0.13.1+ds-1/test/reference/1-keyfile/97/613cb45ec0/22757346db2b9eddd9458b950d45411c1ed01ea49aae273507f3.meta differ
Binary files 0.11.1+ds-4/test/reference/1-keyfile/9b/3f35bb8d77/2a48b4ec9158f8b18773de8ef858393bd01d6655d6d789584ac2 and 0.13.1+ds-1/test/reference/1-keyfile/9b/3f35bb8d77/2a48b4ec9158f8b18773de8ef858393bd01d6655d6d789584ac2 differ
diff -pruN 0.11.1+ds-4/test/reference/1-keyfile/9b/3f35bb8d77/2a48b4ec9158f8b18773de8ef858393bd01d6655d6d789584ac2.meta 0.13.1+ds-1/test/reference/1-keyfile/9b/3f35bb8d77/2a48b4ec9158f8b18773de8ef858393bd01d6655d6d789584ac2.meta
--- 0.11.1+ds-4/test/reference/1-keyfile/9b/3f35bb8d77/2a48b4ec9158f8b18773de8ef858393bd01d6655d6d789584ac2.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-keyfile/9b/3f35bb8d77/2a48b4ec9158f8b18773de8ef858393bd01d6655d6d789584ac2.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-\hg3x[ե+oޔE-{Hv-~q31;+(`E`!7g?W:!Qtj*bQzx'ouA={RiZ2ǐڃSouħDFo#O뜴0M80of
\ No newline at end of file
diff -pruN 0.11.1+ds-4/test/reference/1-keyfile/9e/a58d7b4351/38f94299b28523d1e6ad1f1236f0db5a2067dcd7c267a940aa3e.meta 0.13.1+ds-1/test/reference/1-keyfile/9e/a58d7b4351/38f94299b28523d1e6ad1f1236f0db5a2067dcd7c267a940aa3e.meta
--- 0.11.1+ds-4/test/reference/1-keyfile/9e/a58d7b4351/38f94299b28523d1e6ad1f1236f0db5a2067dcd7c267a940aa3e.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-keyfile/9e/a58d7b4351/38f94299b28523d1e6ad1f1236f0db5a2067dcd7c267a940aa3e.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-oSȽпqB(~^\JOY|>L2LR*.zKW%'rX'7{eE+r-6!oCdJ`sJivk
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/1-keyfile/c0/a8ae96d94a/19d8b90c59846b0b153cb812dc9f8c17cf6a6c53e01047dd126c and 0.13.1+ds-1/test/reference/1-keyfile/c0/a8ae96d94a/19d8b90c59846b0b153cb812dc9f8c17cf6a6c53e01047dd126c differ
Binary files 0.11.1+ds-4/test/reference/1-keyfile/c0/a8ae96d94a/19d8b90c59846b0b153cb812dc9f8c17cf6a6c53e01047dd126c.meta and 0.13.1+ds-1/test/reference/1-keyfile/c0/a8ae96d94a/19d8b90c59846b0b153cb812dc9f8c17cf6a6c53e01047dd126c.meta differ
diff -pruN 0.11.1+ds-4/test/reference/1-keyfile/.securefs.json 0.13.1+ds-1/test/reference/1-keyfile/.securefs.json
--- 0.11.1+ds-4/test/reference/1-keyfile/.securefs.json	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-keyfile/.securefs.json	1970-01-01 00:00:00.000000000 +0000
@@ -1,14 +0,0 @@
-{
-	"encrypted_key" : 
-	{
-		"IV" : "aa55b5c70e5d3b855145479b0267d1c8da15e36f0298478e767c776b38b0dbb2",
-		"MAC" : "815120373f1507b8ce0120860da59b7c",
-		"key" : "b3c01dfe8e3a0e2db0ee54c8fb5b2d3a6a48636ef6048c422b380451132dae51"
-	},
-	"iterations" : 4,
-	"pbkdf" : "scrypt",
-	"salt" : "d71bf51f31d14cbbac49c76101909985d40fe913010f308ed1745796889b30c1",
-	"scrypt_p" : 1,
-	"scrypt_r" : 8,
-	"version" : 1
-}
Binary files 0.11.1+ds-4/test/reference/1-padded/00/0000000000/0000000000000000000000000000000000000000000000000000 and 0.13.1+ds-1/test/reference/1-padded/00/0000000000/0000000000000000000000000000000000000000000000000000 differ
diff -pruN 0.11.1+ds-4/test/reference/1-padded/00/0000000000/0000000000000000000000000000000000000000000000000000.meta 0.13.1+ds-1/test/reference/1-padded/00/0000000000/0000000000000000000000000000000000000000000000000000.meta
--- 0.11.1+ds-4/test/reference/1-padded/00/0000000000/0000000000000000000000000000000000000000000000000000.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/00/0000000000/0000000000000000000000000000000000000000000000000000.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,3 @@
+;U
+WVj0KMž!ϿS޲i9ۉwmIN0RulrlzZb#MN5oޔ%fJ9QEΤz6)4򑤰hFQ̀+m$EG	3i&
+O+_2d3Y3=zANs]/L6q`-:ca ݄y
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/1-padded/09/aa7d29959e/e43bfa8ed54be77746fafbf0c147d5dcd26eb84e2356015ca91b and 0.13.1+ds-1/test/reference/1-padded/09/aa7d29959e/e43bfa8ed54be77746fafbf0c147d5dcd26eb84e2356015ca91b differ
Binary files 0.11.1+ds-4/test/reference/1-padded/09/aa7d29959e/e43bfa8ed54be77746fafbf0c147d5dcd26eb84e2356015ca91b.meta and 0.13.1+ds-1/test/reference/1-padded/09/aa7d29959e/e43bfa8ed54be77746fafbf0c147d5dcd26eb84e2356015ca91b.meta differ
Binary files 0.11.1+ds-4/test/reference/1-padded/18/b6cfc98e0e/ed208c1a59ca9450b419d482e44695c01c12ab1755853598d729 and 0.13.1+ds-1/test/reference/1-padded/18/b6cfc98e0e/ed208c1a59ca9450b419d482e44695c01c12ab1755853598d729 differ
diff -pruN 0.11.1+ds-4/test/reference/1-padded/18/b6cfc98e0e/ed208c1a59ca9450b419d482e44695c01c12ab1755853598d729.meta 0.13.1+ds-1/test/reference/1-padded/18/b6cfc98e0e/ed208c1a59ca9450b419d482e44695c01c12ab1755853598d729.meta
--- 0.11.1+ds-4/test/reference/1-padded/18/b6cfc98e0e/ed208c1a59ca9450b419d482e44695c01c12ab1755853598d729.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/18/b6cfc98e0e/ed208c1a59ca9450b419d482e44695c01c12ab1755853598d729.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,2 @@
+`#wp&&w<ǿ=Nq};@Y<p[e(D//cywmy!.^cSt&/1D$#D`<^ƏRmN4On#G3$!7O%pp&9	52sȲ)oe	f)Z/Nl2In!
+Ҕ>L
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/1-padded/3a/8b5bb07eb1/0d14e937af4ad1812e4709ee5c6b3cca2eb0dc31a89e336d8b8e and 0.13.1+ds-1/test/reference/1-padded/3a/8b5bb07eb1/0d14e937af4ad1812e4709ee5c6b3cca2eb0dc31a89e336d8b8e differ
Binary files 0.11.1+ds-4/test/reference/1-padded/3a/8b5bb07eb1/0d14e937af4ad1812e4709ee5c6b3cca2eb0dc31a89e336d8b8e.meta and 0.13.1+ds-1/test/reference/1-padded/3a/8b5bb07eb1/0d14e937af4ad1812e4709ee5c6b3cca2eb0dc31a89e336d8b8e.meta differ
Binary files 0.11.1+ds-4/test/reference/1-padded/45/1fb0a43294/a8a12782636708f6d1c08bfb9bcac144803137b469751baae392 and 0.13.1+ds-1/test/reference/1-padded/45/1fb0a43294/a8a12782636708f6d1c08bfb9bcac144803137b469751baae392 differ
diff -pruN 0.11.1+ds-4/test/reference/1-padded/45/1fb0a43294/a8a12782636708f6d1c08bfb9bcac144803137b469751baae392.meta 0.13.1+ds-1/test/reference/1-padded/45/1fb0a43294/a8a12782636708f6d1c08bfb9bcac144803137b469751baae392.meta
--- 0.11.1+ds-4/test/reference/1-padded/45/1fb0a43294/a8a12782636708f6d1c08bfb9bcac144803137b469751baae392.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/45/1fb0a43294/a8a12782636708f6d1c08bfb9bcac144803137b469751baae392.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+wHm."7Hco3ae8Pl;nmiʟx)|@9щ[:TUBյЃ'5%Yc[+4xٴ8uf_L[w'a9f~|]?=aI4I?~mY>?<SO-V쇹['8plӱB@1:AC
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/1-padded/4c/bc6a856542/8b893ac25bdb37dcbd35b5753a977af00d3a6c036acac8897c0f and 0.13.1+ds-1/test/reference/1-padded/4c/bc6a856542/8b893ac25bdb37dcbd35b5753a977af00d3a6c036acac8897c0f differ
Binary files 0.11.1+ds-4/test/reference/1-padded/4c/bc6a856542/8b893ac25bdb37dcbd35b5753a977af00d3a6c036acac8897c0f.meta and 0.13.1+ds-1/test/reference/1-padded/4c/bc6a856542/8b893ac25bdb37dcbd35b5753a977af00d3a6c036acac8897c0f.meta differ
diff -pruN 0.11.1+ds-4/test/reference/1-padded/5e/8afaf81eb5/39269a1182a5c56950196cbf31df77da294483d4fe33bbcd9320 0.13.1+ds-1/test/reference/1-padded/5e/8afaf81eb5/39269a1182a5c56950196cbf31df77da294483d4fe33bbcd9320
--- 0.11.1+ds-4/test/reference/1-padded/5e/8afaf81eb5/39269a1182a5c56950196cbf31df77da294483d4fe33bbcd9320	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/5e/8afaf81eb5/39269a1182a5c56950196cbf31df77da294483d4fe33bbcd9320	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+I8'3C_jX܍zܪSz
\ No newline at end of file
diff -pruN 0.11.1+ds-4/test/reference/1-padded/5e/8afaf81eb5/39269a1182a5c56950196cbf31df77da294483d4fe33bbcd9320.meta 0.13.1+ds-1/test/reference/1-padded/5e/8afaf81eb5/39269a1182a5c56950196cbf31df77da294483d4fe33bbcd9320.meta
--- 0.11.1+ds-4/test/reference/1-padded/5e/8afaf81eb5/39269a1182a5c56950196cbf31df77da294483d4fe33bbcd9320.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/5e/8afaf81eb5/39269a1182a5c56950196cbf31df77da294483d4fe33bbcd9320.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,2 @@
+DPPֵ3%a! 
+)4"fk=p+2_%0js}5nuLbFx1[(jX]y :PjJP+F7ˏrq_1\Zn;<Al0
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/1-padded/89/c82a556714/7bb29e1841a557fe34cddc17b0d4b136e67106d3556819e15f7a and 0.13.1+ds-1/test/reference/1-padded/89/c82a556714/7bb29e1841a557fe34cddc17b0d4b136e67106d3556819e15f7a differ
diff -pruN 0.11.1+ds-4/test/reference/1-padded/89/c82a556714/7bb29e1841a557fe34cddc17b0d4b136e67106d3556819e15f7a.meta 0.13.1+ds-1/test/reference/1-padded/89/c82a556714/7bb29e1841a557fe34cddc17b0d4b136e67106d3556819e15f7a.meta
--- 0.11.1+ds-4/test/reference/1-padded/89/c82a556714/7bb29e1841a557fe34cddc17b0d4b136e67106d3556819e15f7a.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/89/c82a556714/7bb29e1841a557fe34cddc17b0d4b136e67106d3556819e15f7a.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,3 @@
+ڿ-3-&HfgIq,DwiC
+{pމ
+Jb(uz^k;U#wu8 +%DkNi=fPV	I$l_䚊#'?z74oj;ԋp.;*9+CF=k#]@.2g
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/1-padded/8d/ab5cfaa3a2/ff87cb2d79ba3b77ed01f52711fbf16028dce07f38a86856c299 and 0.13.1+ds-1/test/reference/1-padded/8d/ab5cfaa3a2/ff87cb2d79ba3b77ed01f52711fbf16028dce07f38a86856c299 differ
Binary files 0.11.1+ds-4/test/reference/1-padded/8d/ab5cfaa3a2/ff87cb2d79ba3b77ed01f52711fbf16028dce07f38a86856c299.meta and 0.13.1+ds-1/test/reference/1-padded/8d/ab5cfaa3a2/ff87cb2d79ba3b77ed01f52711fbf16028dce07f38a86856c299.meta differ
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.argon2id.KEYFILE2.json 0.13.1+ds-1/test/reference/1-padded/.securefs.argon2id.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.argon2id.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.argon2id.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"encrypted_key" : 
+	{
+		"IV" : "3473a58e95dd3dc96516f6ffb2e96bcf94c7ee4733e4ff4229469497a79c797f",
+		"MAC" : "b678affbcb76a5b0b954f33c4bdc2c8b",
+		"key" : "89fb64d34ef990d82d6ed82578d4891e84eec2fab9270e1828a75bb3935c6cbf"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "cee823640dffa2670c61e75263a4778419897d178374c9cb998869e5d1bc9b74",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.argon2id.KEYFILE.json 0.13.1+ds-1/test/reference/1-padded/.securefs.argon2id.KEYFILE.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.argon2id.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.argon2id.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"encrypted_key" : 
+	{
+		"IV" : "da7ee57b1ee598be2931d2c21739b975a270548a51f203e1bf275d3a50f8a487",
+		"MAC" : "14299e59f4e875448ab63e2e88c94584",
+		"key" : "af12e40594fc42582c45028df45e66c73feafed74effec7f2d056707503ab55f"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "0c54fe6442f623c3bb4382394a544dc4f8e93f1dc152cd9514971dc6768a97e5",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.argon2id.PASSWORD.json 0.13.1+ds-1/test/reference/1-padded/.securefs.argon2id.PASSWORD.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.argon2id.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.argon2id.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"encrypted_key" : 
+	{
+		"IV" : "7bb40ccd2e8ffa1f8e51ab835c826ae0987625090a1389a63bb281292347579a",
+		"MAC" : "baba75fd8e72ba12b7cf7c0b1b756a9f",
+		"key" : "1eec96917c9f3c16eb9799d00a3b4b66faa075e4cbb01b753a493d4743ffe834"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "957d0b77370c9e1b819c7bffd06aca87cca3db727cc23ffbfcbf65be82190400",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/1-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"encrypted_key" : 
+	{
+		"IV" : "6a6034833426e30a2c5446d10e1a7c002bd52d0ce17d25509a5b65136b83ee68",
+		"MAC" : "7919385f26d6151504ffab76a885d762",
+		"key" : "e10a5cd9994b4d747ed57f3671cf342f55352c02bf4c8ecf238b474501e3764b"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "212c05a158cb3a50014ea427bfe6ba92521f6867127ef1292bca460dba2470f8",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/1-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"encrypted_key" : 
+	{
+		"IV" : "9713b8c4e2faea89437fda18efc9e6e4d8f798603a9d24f13e43d00dd0bb5977",
+		"MAC" : "375661d2dd3cd76b00fccd7b8e0317bb",
+		"key" : "57ef914089262594704f2243e6f40a80f7bdb714deecdf0e7b6346b59c1e34b8"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "eb3be13f591f2ec193170e020f8d12533d7ca6d1181e1c160eef936ce9898e96",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json 0.13.1+ds-1/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,13 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "0cb5c704b7cb0a6dd81ad4d50f3525f0fd9e87f768aa9c9a633f603c908776bf",
+		"MAC" : "13726bb53b4356dafb0f5dc35a901bc8",
+		"key" : "63ffaaa935b7f0e310f6214d058b00a795b8cc834983b7210e68186309c3c658"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "064f8926a561767bbfc7c85afc8dba03bf6b6bac7b19dd0acc4fe0b04b71e815",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json 0.13.1+ds-1/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,13 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "d431f4bdaca75e9fa4ab994c938d5618420b153feed08c2ed81338316809181a",
+		"MAC" : "e446ef92c07220a3f908d51f5bd44848",
+		"key" : "bc7e8f316db92f938bdcd3d3425a85168f5ce17cac77ad8080292dcb939739bd"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "eadc437d1d45f60a4bb4a5a5f6b62fe369e31a567866f401078684803b8f21fe",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json 0.13.1+ds-1/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,13 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "54078e70fb6fc231986e47368d7e6f9613334efd5733bc0b1365841de7d2646a",
+		"MAC" : "d32447e7fe5de2de130f1db140d76e7c",
+		"key" : "a8d167464c5c876a3d1d7d267bb370d36203f5e814250ae3bc6aa677315ac5bb"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "c415d5ff16fdfb42ad6c999cc2543fda1997af4eacdf083263b77f29475f254e",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,13 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "af331257f464858bab04ecaeb01d1946d2f28b43e29531ec6e547a357962e902",
+		"MAC" : "0ebea89aaf4c2f4984c9882cfb0c4b04",
+		"key" : "bd8f975e999e1fd20d438be03c971dd8a1c111015bbeb192af29e71fb0d1b92b"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "fedde996ab55f80d92c4b20ceb79e053fd8b658581c599a006dd5b490c00b32e",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,13 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "6468d2f5f92a607a68b0905136d6b61996883197d8bef2bba776b95678cce875",
+		"MAC" : "161222470f786b767c83831fd9ecba0f",
+		"key" : "774653197691700da69a2fc238b5fdd67faa245c8341aebcf829c7afeba55e4e"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "fd50bd560e2c7b0603c76c62783943fce60746a88bce1e4d64bab05a85545992",
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.scrypt.KEYFILE2.json 0.13.1+ds-1/test/reference/1-padded/.securefs.scrypt.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.scrypt.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.scrypt.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "e9795439273ad3ecba61407f7ff7fcb68e6794c0cc7b67299d19b82e090d8809",
+		"MAC" : "8905b216d79b5573670810375e4f720e",
+		"key" : "6021edfeada83adde99f517792b88e6cff4fc6ce36041800e1d9cdef43e5352a"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "f77d93f2b5a1ec7980456ee7e4788e49207b74ba60ee83b4b67a160a319325e9",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.scrypt.KEYFILE.json 0.13.1+ds-1/test/reference/1-padded/.securefs.scrypt.KEYFILE.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.scrypt.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.scrypt.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "303c833dfd7a18c7c70c2fff2db7be2a9735d78b1ef0b08e7d2d6ebe7a9141f4",
+		"MAC" : "ad5231e0a196c190c9948a397196463e",
+		"key" : "3417891a74d134ecd607a2271cb3bcb1ccf36f8b1e38215672d9447109fa9428"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "61c37c40e4a70ad391f09efcb3b31f6b31463ed21914381b8cf89816df2e72f5",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.scrypt.PASSWORD.json 0.13.1+ds-1/test/reference/1-padded/.securefs.scrypt.PASSWORD.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.scrypt.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.scrypt.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "480bc878e08124d73ff74e09076dd753ba654aa886d71ba8dcad4a771e36038e",
+		"MAC" : "9ac94e977f3da6be706c7d3f991de768",
+		"key" : "0725e387ca9744e8650fce2a1acff131dfe34b864ad2551c00ad92aca24224ec"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "468280cf61f842124b89030df04c1a1da835fe44188ac94de6d704a5ce1a7858",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/1-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "47ff01cacef04965017e299f95c4203ef986a84fedcdbe31712da47ee0f760e7",
+		"MAC" : "3f46221c570a9413f315e05d92ea582e",
+		"key" : "eab141bc11b3a59c305e812a399a69e4c9c9847220e024802e73b8c79b765cd8"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "828154f4ac192d5b43336ef10d89586fdb7231c7caf8c80a6d1b00650e93b89a",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/1-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/1-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/1-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/1-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"encrypted_key" : 
+	{
+		"IV" : "aa41b71045b1a2f523f243a755d3fa7f3371f827ec4df537ca6f9291f0667d73",
+		"MAC" : "06b684b40ec195349f58156ca4ed3039",
+		"key" : "825588be303faa01cf182723944d76a5e57e214c731be6b2175748e2f04188b4"
+	},
+	"iterations" : 2,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "03628f77a682f484dc9a3f0c91d4c1881a624d3f4f70a34eea148b327cd1e63e",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 1
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.argon2id.KEYFILE2.json 0.13.1+ds-1/test/reference/2/.securefs.argon2id.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2/.securefs.argon2id.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.argon2id.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "ac3376e22fca88ff8099a8e97b6c3996d91f0d0ed9277a473d0f1123b67db1b0",
+		"MAC" : "448757f859d33dfe59533e3f27743382",
+		"key" : "597a65acd0ede69a7c9cfca544338e1d23b132e2e1c3144738ece570d101e2b5"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "64d1e90c05acf130b8c4fbc02e95da01dc092619733f9b33b9be0c8eb618da6b",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.argon2id.KEYFILE.json 0.13.1+ds-1/test/reference/2/.securefs.argon2id.KEYFILE.json
--- 0.11.1+ds-4/test/reference/2/.securefs.argon2id.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.argon2id.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "a156a9d385e4611e7a3ff173f536aafc12238ce61043f850f86b07b939c9f270",
+		"MAC" : "79c9f25709a4f4c925d8dfbdc78a3404",
+		"key" : "b5449eda066c35f4be9f5c66ef509ee2dcbec02a2f68b4c6015a64005984d079"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "b53a6229ace8480a9d1f67ce72df448cd4d396ca23c69534c6048e922b07ec12",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.argon2id.PASSWORD.json 0.13.1+ds-1/test/reference/2/.securefs.argon2id.PASSWORD.json
--- 0.11.1+ds-4/test/reference/2/.securefs.argon2id.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.argon2id.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "fe5bba79b41b4659fcee230e68e5dfc8037f68cbafbc8b4dcfe16d590a7e4b2f",
+		"MAC" : "02322427269aea536421d053bb5f6e9c",
+		"key" : "68bcc90356a19b1f9013a65702592d4fc320bb69ccd4e36c8776866db0b58186"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "3173259db2520fe719a382b3a0672f93060682d09b2612a51fe30d8ff37571fa",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/2/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "1a8b40a9289859ccfcc381d11d9164d955b633ef76d42f3361479150714b737d",
+		"MAC" : "99901df4c071918a001707064f12d783",
+		"key" : "afa51ae497ba03b996f48f215704d81d6132f2d1e17507d0b65d4e9295b6e920"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "b246c1723021d085eef4cd1fb06afa890b50d28a34a292483944130c577cc10e",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/2/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/2/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "d6470dfe85dc036440bfa441e59786c877c2058f33dc3870fc88ac4c4d93dd29",
+		"MAC" : "3aba064c95da08f279dc6917a9572825",
+		"key" : "299ef860e3c61672b9a1e51a537cfcb33b98297ce07232dee2eb3d872206d545"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "70abd3eb6c5f5c20f268272bd148c54f4f60d3b63a775de2309890fba1268ead",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.json 0.13.1+ds-1/test/reference/2/.securefs.json
--- 0.11.1+ds-4/test/reference/2/.securefs.json	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.json	1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-{
-	"block_size" : 4096,
-	"encrypted_key" : 
-	{
-		"IV" : "ff1ce65cbef6460b024279a1d285442b75c2a8814247776aa0a9e6c9ead4ed66",
-		"MAC" : "92854550c44df24ce752f07f1e1a811e",
-		"key" : "83f54f68d04dcc80b18e1b736a835f1a092b83be7d9bd9e8b35f86790f0b4b70"
-	},
-	"iterations" : 4,
-	"iv_size" : 12,
-	"pbkdf" : "scrypt",
-	"salt" : "eec043167580f93a9d6677f9f829b81ecd0ba787d56c23fa8a37fe697e42c00b",
-	"scrypt_p" : 1,
-	"scrypt_r" : 8,
-	"version" : 2
-}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json 0.13.1+ds-1/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "f72166ef4a42a442ef38217be83b1f0697afcb531f10779c39ddf7c6363cc6da",
+		"MAC" : "0088d5ff6c7ba0d080bce2b83d9ae60f",
+		"key" : "4e1a53ab6a27825d74b5119755bf417496f3550486a1afb0654db5b3dcfb62c7"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "3d402bbc96deb88ee810e756fda808e521a896093b65593c2adc8c84bcdf0014",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json 0.13.1+ds-1/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json
--- 0.11.1+ds-4/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "eda641dc5d9703d60873597c29867b4220a31ff9f0ac0425c475a3f541d80235",
+		"MAC" : "2688208713c09866f54a150ec018bc52",
+		"key" : "586d9e7ba36dc13ad06d87a7a88fdbe2e607c4f139f17c98874febfa66a602b2"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "1eb63af8da615fabc8f0620d1d5da921551fa95ffd7d0b8bb0db26224e9c6324",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json 0.13.1+ds-1/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json
--- 0.11.1+ds-4/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "02a2a6696923eb4e0b2d4d5ef891872b6a6dc7adf1860c5324d86f7744ea1808",
+		"MAC" : "61744944f22061c9ea1c713f5142af21",
+		"key" : "832da4a43407097ca3ebbdf9339351d4299ebdffbb06705712304946111a7c06"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "d071ead50f2501b06c8df187e5629b48daed30077a6d250416ab50bc7a406cc6",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "d48417c459f8a66159195636080d4560f812e0d0fde00b7c8142b63a73839a37",
+		"MAC" : "872b3ddec8fda427b1d5fb5fde265c11",
+		"key" : "7110c09b5e5800af3288b2940a81d6ea82d73c4260890aa1bbc1fc4603b7a562"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "fa523bffe41c014f81a3304925e2fd46625a5574d1f71b5d05fe666fb8e66bff",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "c9fc9f9cb12b3dd73cc1bace83c8268f401fb12bc2449f0fcb13a3af39bb9ba4",
+		"MAC" : "704fc9b0fe8de6b6f4a81bed016f4417",
+		"key" : "678835eb9fb3eb34204e99486c30d12fc8188431b903592e20cef43544f9be4e"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "0a1d4b783bbc0556aaddd7ed3b410a06bf744aa83dee1cdc7955473fdbf0ab03",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.scrypt.KEYFILE2.json 0.13.1+ds-1/test/reference/2/.securefs.scrypt.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2/.securefs.scrypt.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.scrypt.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "dbbf4ffab7d3a5c8e8a44533cdf28ec290d321efbc37de4e816d5005bf435913",
+		"MAC" : "a5c36b97153cbfa2be90d4fed7569212",
+		"key" : "c264f6be9ed842ebd837a574903f9f2011b561c086b509e378a26c22aceeb64a"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "40a9d719635ea633c7e9b7e74a8392ce63cf697eac174f492842ecd4a1d880df",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.scrypt.KEYFILE.json 0.13.1+ds-1/test/reference/2/.securefs.scrypt.KEYFILE.json
--- 0.11.1+ds-4/test/reference/2/.securefs.scrypt.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.scrypt.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "83f70a61f3ac823460b465b5dd951825ef6f57623061c8f05a33635cd0e17d90",
+		"MAC" : "8d029a2ad6b998ed5eca3ad728844160",
+		"key" : "9486c7efa6f60ea9df8464e7d0b672386409a4789bc1b8549bc4db17cde4baeb"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "1ad58296db414f663f6aae2f6ebef448253a4071eb05f2f17e4fb168e1c2d025",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.scrypt.PASSWORD.json 0.13.1+ds-1/test/reference/2/.securefs.scrypt.PASSWORD.json
--- 0.11.1+ds-4/test/reference/2/.securefs.scrypt.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.scrypt.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "86eed9ddf2d40ae47d28211eb47c2ae0a7d7d990d782c3a0b1701f5b0d3af85b",
+		"MAC" : "87b36f2b8146fa622c66492b84c2ff25",
+		"key" : "7806fba18e53977ad5a5d176593d9b526cf4c3f44d5b33a9448d28fc18927acf"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "e288c1dc0068699de0caa2e4e18cf9177758f67a3fdbfa96578abc1a2922b745",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/2/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "77c01fae23be1a45da7805263ead987bafebf7df989a43f38e2a93ebd8e0cd90",
+		"MAC" : "435cc2e02f20ced049262e9ff05f3d14",
+		"key" : "2e6b16393b1b9c52f168c8facc5c3a14a22169b94b43358ab8228a938e1c7210"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "b9eaa702f7486a09970d68798a4c8cfc4b1fa0cb3c82485b254f71eb55a62581",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/2/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/2/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "75db43b53ffe497775b19ec7fcaaaecc666fd059d12abe2b92622f6fe235d482",
+		"MAC" : "4368e2d453cc296670430f146e643b78",
+		"key" : "e2e164348d5cbd6383d8ad20023cd93bf4a683731adf88db6010eced855dc376"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "1a3d39abec941f76f15670790f4f41a0daa4342b06869e7f705c0ad6f8f74ac6",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 2
+}
Binary files 0.11.1+ds-4/test/reference/2-keyfile/00/00000000000000000000000000000000000000000000000000000000000000 and 0.13.1+ds-1/test/reference/2-keyfile/00/00000000000000000000000000000000000000000000000000000000000000 differ
Binary files 0.11.1+ds-4/test/reference/2-keyfile/00/00000000000000000000000000000000000000000000000000000000000000.meta and 0.13.1+ds-1/test/reference/2-keyfile/00/00000000000000000000000000000000000000000000000000000000000000.meta differ
diff -pruN 0.11.1+ds-4/test/reference/2-keyfile/09/66f6517d2cb5b64e0aad49b3997c051d299d94b15d8ec1edda88db0c396ce1.meta 0.13.1+ds-1/test/reference/2-keyfile/09/66f6517d2cb5b64e0aad49b3997c051d299d94b15d8ec1edda88db0c396ce1.meta
--- 0.11.1+ds-4/test/reference/2-keyfile/09/66f6517d2cb5b64e0aad49b3997c051d299d94b15d8ec1edda88db0c396ce1.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-keyfile/09/66f6517d2cb5b64e0aad49b3997c051d299d94b15d8ec1edda88db0c396ce1.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-)Kp#Hd$)^cX3#`#Ųmj!8Hb]
-un2`r)
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/2-keyfile/44/a1bac42696e0895f5116fa96b119d33f2b7256fb3fef06e635de731848cefc and 0.13.1+ds-1/test/reference/2-keyfile/44/a1bac42696e0895f5116fa96b119d33f2b7256fb3fef06e635de731848cefc differ
Binary files 0.11.1+ds-4/test/reference/2-keyfile/44/a1bac42696e0895f5116fa96b119d33f2b7256fb3fef06e635de731848cefc.meta and 0.13.1+ds-1/test/reference/2-keyfile/44/a1bac42696e0895f5116fa96b119d33f2b7256fb3fef06e635de731848cefc.meta differ
Binary files 0.11.1+ds-4/test/reference/2-keyfile/6d/28a07e4dd4b1d7a21a9abadee491a8f75211078b56e4a43c7e6c38a4404f5d and 0.13.1+ds-1/test/reference/2-keyfile/6d/28a07e4dd4b1d7a21a9abadee491a8f75211078b56e4a43c7e6c38a4404f5d differ
diff -pruN 0.11.1+ds-4/test/reference/2-keyfile/6d/28a07e4dd4b1d7a21a9abadee491a8f75211078b56e4a43c7e6c38a4404f5d.meta 0.13.1+ds-1/test/reference/2-keyfile/6d/28a07e4dd4b1d7a21a9abadee491a8f75211078b56e4a43c7e6c38a4404f5d.meta
--- 0.11.1+ds-4/test/reference/2-keyfile/6d/28a07e4dd4b1d7a21a9abadee491a8f75211078b56e4a43c7e6c38a4404f5d.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-keyfile/6d/28a07e4dd4b1d7a21a9abadee491a8f75211078b56e4a43c7e6c38a4404f5d.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-hfv/{.=^*{.4o%Rb9莰=MB)KFk ^Gp[!O;z; B?l[)|@#!Wlrf2}
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/2-keyfile/b3/f330a737dbeefd5f163d16e5d09a8e56b36762bb38b907800dba5636ffce1e and 0.13.1+ds-1/test/reference/2-keyfile/b3/f330a737dbeefd5f163d16e5d09a8e56b36762bb38b907800dba5636ffce1e differ
diff -pruN 0.11.1+ds-4/test/reference/2-keyfile/b3/f330a737dbeefd5f163d16e5d09a8e56b36762bb38b907800dba5636ffce1e.meta 0.13.1+ds-1/test/reference/2-keyfile/b3/f330a737dbeefd5f163d16e5d09a8e56b36762bb38b907800dba5636ffce1e.meta
--- 0.11.1+ds-4/test/reference/2-keyfile/b3/f330a737dbeefd5f163d16e5d09a8e56b36762bb38b907800dba5636ffce1e.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-keyfile/b3/f330a737dbeefd5f163d16e5d09a8e56b36762bb38b907800dba5636ffce1e.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-~Acc5wʼT6]rDkS`b(rYS4,KYj#\0cҫk(7~GAc8BDVf[2勎[X
\ No newline at end of file
diff -pruN 0.11.1+ds-4/test/reference/2-keyfile/bd/467327e489024a428264db99818249455379ea4fe2a6c5daa5c89e3d7568a0 0.13.1+ds-1/test/reference/2-keyfile/bd/467327e489024a428264db99818249455379ea4fe2a6c5daa5c89e3d7568a0
--- 0.11.1+ds-4/test/reference/2-keyfile/bd/467327e489024a428264db99818249455379ea4fe2a6c5daa5c89e3d7568a0	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-keyfile/bd/467327e489024a428264db99818249455379ea4fe2a6c5daa5c89e3d7568a0	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-~t_3o
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/2-keyfile/bd/467327e489024a428264db99818249455379ea4fe2a6c5daa5c89e3d7568a0.meta and 0.13.1+ds-1/test/reference/2-keyfile/bd/467327e489024a428264db99818249455379ea4fe2a6c5daa5c89e3d7568a0.meta differ
diff -pruN 0.11.1+ds-4/test/reference/2-keyfile/c7/88ec17fc38bcae53085b55ab8753dc8b799d59702869440e737172fa58de57 0.13.1+ds-1/test/reference/2-keyfile/c7/88ec17fc38bcae53085b55ab8753dc8b799d59702869440e737172fa58de57
--- 0.11.1+ds-4/test/reference/2-keyfile/c7/88ec17fc38bcae53085b55ab8753dc8b799d59702869440e737172fa58de57	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-keyfile/c7/88ec17fc38bcae53085b55ab8753dc8b799d59702869440e737172fa58de57	1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-S4'eSmuPGoJz|R+L[G䲥Lc:,+Rp`+,W
-ja*HOEMzޯQnm3payL<h	EbDt*: #Or ÿexXUڗrK5ַ2JŖwN8Emå<2qFG:År`S7s2ἬU1S`C#MbG*HY_^َT>٥'\VЈ@p"lvu 3KS!3-I+jdDKFx*lfZfXZ'|hj
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/2-keyfile/c7/88ec17fc38bcae53085b55ab8753dc8b799d59702869440e737172fa58de57.meta and 0.13.1+ds-1/test/reference/2-keyfile/c7/88ec17fc38bcae53085b55ab8753dc8b799d59702869440e737172fa58de57.meta differ
Binary files 0.11.1+ds-4/test/reference/2-keyfile/ca/4979a81aca72100bc28f9723b806ebe14c682d65f3bd2267d947a6cfd65091 and 0.13.1+ds-1/test/reference/2-keyfile/ca/4979a81aca72100bc28f9723b806ebe14c682d65f3bd2267d947a6cfd65091 differ
Binary files 0.11.1+ds-4/test/reference/2-keyfile/ca/4979a81aca72100bc28f9723b806ebe14c682d65f3bd2267d947a6cfd65091.meta and 0.13.1+ds-1/test/reference/2-keyfile/ca/4979a81aca72100bc28f9723b806ebe14c682d65f3bd2267d947a6cfd65091.meta differ
Binary files 0.11.1+ds-4/test/reference/2-keyfile/e9/2c96ad9f764725e148049a255785bb46083fb5011f71418281bf2ca71da692 and 0.13.1+ds-1/test/reference/2-keyfile/e9/2c96ad9f764725e148049a255785bb46083fb5011f71418281bf2ca71da692 differ
Binary files 0.11.1+ds-4/test/reference/2-keyfile/e9/2c96ad9f764725e148049a255785bb46083fb5011f71418281bf2ca71da692.meta and 0.13.1+ds-1/test/reference/2-keyfile/e9/2c96ad9f764725e148049a255785bb46083fb5011f71418281bf2ca71da692.meta differ
diff -pruN 0.11.1+ds-4/test/reference/2-keyfile/.securefs.json 0.13.1+ds-1/test/reference/2-keyfile/.securefs.json
--- 0.11.1+ds-4/test/reference/2-keyfile/.securefs.json	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-keyfile/.securefs.json	1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-{
-	"block_size" : 4096,
-	"encrypted_key" : 
-	{
-		"IV" : "15a5e26548882961cd88545a1c015a4f1c0a287d5a42ee552c5d14a7971a7d58",
-		"MAC" : "32090df8db5ae67621a82296297d5894",
-		"key" : "9cd8f31bb1b4023bc358b852295054cf8388cb8e44f982b2a5803c2ccdea9f00"
-	},
-	"iterations" : 4,
-	"iv_size" : 12,
-	"pbkdf" : "scrypt",
-	"salt" : "ec92147bb2925eb269239c231ab81e14ca9393a21ffc30c73d526caa3a21732e",
-	"scrypt_p" : 1,
-	"scrypt_r" : 8,
-	"version" : 2
-}
Binary files 0.11.1+ds-4/test/reference/2-padded/00/00000000000000000000000000000000000000000000000000000000000000 and 0.13.1+ds-1/test/reference/2-padded/00/00000000000000000000000000000000000000000000000000000000000000 differ
diff -pruN 0.11.1+ds-4/test/reference/2-padded/00/00000000000000000000000000000000000000000000000000000000000000.meta 0.13.1+ds-1/test/reference/2-padded/00/00000000000000000000000000000000000000000000000000000000000000.meta
--- 0.11.1+ds-4/test/reference/2-padded/00/00000000000000000000000000000000000000000000000000000000000000.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/00/00000000000000000000000000000000000000000000000000000000000000.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,3 @@
+=I[R\tt9[i؄g.=0127|"A c3
+	4wAIWO!ajx3bl[Rދ&=Mdx&WCA}b	2f%FTTN"p;09$q_$mPK`
+u6n5
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/2-padded/1d/e5f2b66f5c6426765d3b8de6e19bf09cb7a3441b16a8322ff520243ec69b3b and 0.13.1+ds-1/test/reference/2-padded/1d/e5f2b66f5c6426765d3b8de6e19bf09cb7a3441b16a8322ff520243ec69b3b differ
Binary files 0.11.1+ds-4/test/reference/2-padded/1d/e5f2b66f5c6426765d3b8de6e19bf09cb7a3441b16a8322ff520243ec69b3b.meta and 0.13.1+ds-1/test/reference/2-padded/1d/e5f2b66f5c6426765d3b8de6e19bf09cb7a3441b16a8322ff520243ec69b3b.meta differ
Binary files 0.11.1+ds-4/test/reference/2-padded/4b/0317b74d5b5e8f97a9ac81d125edffaa634f03633f29e677367a4db8206ea0 and 0.13.1+ds-1/test/reference/2-padded/4b/0317b74d5b5e8f97a9ac81d125edffaa634f03633f29e677367a4db8206ea0 differ
Binary files 0.11.1+ds-4/test/reference/2-padded/4b/0317b74d5b5e8f97a9ac81d125edffaa634f03633f29e677367a4db8206ea0.meta and 0.13.1+ds-1/test/reference/2-padded/4b/0317b74d5b5e8f97a9ac81d125edffaa634f03633f29e677367a4db8206ea0.meta differ
Binary files 0.11.1+ds-4/test/reference/2-padded/4c/8c3e95d29c797b1fd1c8a2c31540a53fe09d0458bac65138d06127426d936a and 0.13.1+ds-1/test/reference/2-padded/4c/8c3e95d29c797b1fd1c8a2c31540a53fe09d0458bac65138d06127426d936a differ
Binary files 0.11.1+ds-4/test/reference/2-padded/4c/8c3e95d29c797b1fd1c8a2c31540a53fe09d0458bac65138d06127426d936a.meta and 0.13.1+ds-1/test/reference/2-padded/4c/8c3e95d29c797b1fd1c8a2c31540a53fe09d0458bac65138d06127426d936a.meta differ
Binary files 0.11.1+ds-4/test/reference/2-padded/54/3e9a31a92783272b8fc47530adb1c9c697653fd25d9852c55af10d6885de05 and 0.13.1+ds-1/test/reference/2-padded/54/3e9a31a92783272b8fc47530adb1c9c697653fd25d9852c55af10d6885de05 differ
Binary files 0.11.1+ds-4/test/reference/2-padded/54/3e9a31a92783272b8fc47530adb1c9c697653fd25d9852c55af10d6885de05.meta and 0.13.1+ds-1/test/reference/2-padded/54/3e9a31a92783272b8fc47530adb1c9c697653fd25d9852c55af10d6885de05.meta differ
diff -pruN 0.11.1+ds-4/test/reference/2-padded/8c/d52ef7ffa4fd6776982588fb1cb0bfca3bd1b37b9faa97d3a2086593ccc84e 0.13.1+ds-1/test/reference/2-padded/8c/d52ef7ffa4fd6776982588fb1cb0bfca3bd1b37b9faa97d3a2086593ccc84e
--- 0.11.1+ds-4/test/reference/2-padded/8c/d52ef7ffa4fd6776982588fb1cb0bfca3bd1b37b9faa97d3a2086593ccc84e	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/8c/d52ef7ffa4fd6776982588fb1cb0bfca3bd1b37b9faa97d3a2086593ccc84e	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+ftޠGQ5qu><@p6\>]F IIxledfsL~>$F~@U ЍRPmrTB&7V
\ No newline at end of file
diff -pruN 0.11.1+ds-4/test/reference/2-padded/8c/d52ef7ffa4fd6776982588fb1cb0bfca3bd1b37b9faa97d3a2086593ccc84e.meta 0.13.1+ds-1/test/reference/2-padded/8c/d52ef7ffa4fd6776982588fb1cb0bfca3bd1b37b9faa97d3a2086593ccc84e.meta
--- 0.11.1+ds-4/test/reference/2-padded/8c/d52ef7ffa4fd6776982588fb1cb0bfca3bd1b37b9faa97d3a2086593ccc84e.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/8c/d52ef7ffa4fd6776982588fb1cb0bfca3bd1b37b9faa97d3a2086593ccc84e.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+syC{MSm]/bd?08{epϿ-i9K*6bҕxl9.I9\7̅fՁ$ٲgB_l<wA	oB
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/2-padded/9b/85daea10bbb0b50f9e8d6ac7388329a103b718e8c8755068d7947557f20043 and 0.13.1+ds-1/test/reference/2-padded/9b/85daea10bbb0b50f9e8d6ac7388329a103b718e8c8755068d7947557f20043 differ
Binary files 0.11.1+ds-4/test/reference/2-padded/9b/85daea10bbb0b50f9e8d6ac7388329a103b718e8c8755068d7947557f20043.meta and 0.13.1+ds-1/test/reference/2-padded/9b/85daea10bbb0b50f9e8d6ac7388329a103b718e8c8755068d7947557f20043.meta differ
diff -pruN 0.11.1+ds-4/test/reference/2-padded/c9/3ee3c1c7141050c9a8fa2e56e6e2d1b1220c55ddcb4b78ecbfa00ef370d59a 0.13.1+ds-1/test/reference/2-padded/c9/3ee3c1c7141050c9a8fa2e56e6e2d1b1220c55ddcb4b78ecbfa00ef370d59a
--- 0.11.1+ds-4/test/reference/2-padded/c9/3ee3c1c7141050c9a8fa2e56e6e2d1b1220c55ddcb4b78ecbfa00ef370d59a	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/c9/3ee3c1c7141050c9a8fa2e56e6e2d1b1220c55ddcb4b78ecbfa00ef370d59a	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+%(>@(>?4WA`9
\ No newline at end of file
diff -pruN 0.11.1+ds-4/test/reference/2-padded/c9/3ee3c1c7141050c9a8fa2e56e6e2d1b1220c55ddcb4b78ecbfa00ef370d59a.meta 0.13.1+ds-1/test/reference/2-padded/c9/3ee3c1c7141050c9a8fa2e56e6e2d1b1220c55ddcb4b78ecbfa00ef370d59a.meta
--- 0.11.1+ds-4/test/reference/2-padded/c9/3ee3c1c7141050c9a8fa2e56e6e2d1b1220c55ddcb4b78ecbfa00ef370d59a.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/c9/3ee3c1c7141050c9a8fa2e56e6e2d1b1220c55ddcb4b78ecbfa00ef370d59a.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+	u#Ӈ绢8D+B|E'_ mK}G24A2h8-׌R6Le	59+6@ʻrѓ
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/2-padded/e7/e6f9393bd4ac12d272cf69ee738ef0e1c2ea6d93ce228eac4bb91ac169756c and 0.13.1+ds-1/test/reference/2-padded/e7/e6f9393bd4ac12d272cf69ee738ef0e1c2ea6d93ce228eac4bb91ac169756c differ
diff -pruN 0.11.1+ds-4/test/reference/2-padded/e7/e6f9393bd4ac12d272cf69ee738ef0e1c2ea6d93ce228eac4bb91ac169756c.meta 0.13.1+ds-1/test/reference/2-padded/e7/e6f9393bd4ac12d272cf69ee738ef0e1c2ea6d93ce228eac4bb91ac169756c.meta
--- 0.11.1+ds-4/test/reference/2-padded/e7/e6f9393bd4ac12d272cf69ee738ef0e1c2ea6d93ce228eac4bb91ac169756c.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/e7/e6f9393bd4ac12d272cf69ee738ef0e1c2ea6d93ce228eac4bb91ac169756c.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+Ooo~"=S8B_RUEgeXF#%NOOҴ1=!|ӃD) )cUA2i!h?Â7J\`33+eM	{xXDr@t{׭wo4L
\ No newline at end of file
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.argon2id.KEYFILE2.json 0.13.1+ds-1/test/reference/2-padded/.securefs.argon2id.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.argon2id.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.argon2id.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "8e6d4cb2859afcaad1c8f18d99b7444a9021351c1c1e4be74e10b3f4c5d7d90e",
+		"MAC" : "8d00b9527fca84352a104e5c89529be1",
+		"key" : "1e67aeddf0ecc3761ff7001fa6dc2acf8ceab89d0909f36468ca24a709772257"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "9e6c919e80c2554922eb892d01e8f240e4c5d7d6380b16513dfadea16ac26cc7",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.argon2id.KEYFILE.json 0.13.1+ds-1/test/reference/2-padded/.securefs.argon2id.KEYFILE.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.argon2id.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.argon2id.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "50df5338214acced850d582e5fc11bc18faa3b883a703597c60a7dd4f2c3b94f",
+		"MAC" : "14bac47cf6e9e37a31de84329ad723be",
+		"key" : "8480f7ef305c64277c50975cadcbe00c88ab7b20a0d14260c291567575c2ccfb"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "7049dda88f7dc700b155b748a50187f00240f8cd1c58cfde59b9164b90b61e88",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.argon2id.PASSWORD.json 0.13.1+ds-1/test/reference/2-padded/.securefs.argon2id.PASSWORD.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.argon2id.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.argon2id.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "289cded6ccc7df31e79db54665bd47abb52c88d0548195b122b0b7ecf9db54a1",
+		"MAC" : "322bb23460d998430ebc864516f107d4",
+		"key" : "dd732b054fd288f838c13b5a72b12e29720274882195377cf6bcd7f839e8ed77"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "8b266ec0cb309b136843cb152b2732863fa756e7e4a1ae2f124e5670f678fe69",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/2-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "62b409ac6a4d0e931c0eef580e02771e964bfb98326c5cb5e8abaf56bdd4feb0",
+		"MAC" : "7a08a5c86ec99fa5ca53f212c2a353ac",
+		"key" : "b28da391ef973f11d4e6964d0bed3adee5afdd4c01a42c744ae53c7e0ad0282d"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "26c93b2e4059a653b01770c234e6ebaa1d1be0c94f0094fbb6c26fb1e298dbb1",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/2-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "4d279fbe20ac3380e45baf723c4448be805511dd39c1a6aec7779e92f86dda40",
+		"MAC" : "32e8ab339091cdcffd2c9148f85d61bb",
+		"key" : "1d401dcd47ab8a297a0d22305963a5f80a9b3f10e273a59dd6d7a2860a7c0b82"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "e1f954afe1b8443a4114b61031c1af4804808a222e044fbc5f77f157d1fc2a4d",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json 0.13.1+ds-1/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "67bb577584d22738ece3a2d8471bae6bb146166a44f42190cf01904e00381816",
+		"MAC" : "09ccf85377f96a12817e029248936f36",
+		"key" : "ea9625c39931e483e280fc364d96afa161fd87c1903834fd67ff45b757691dab"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "cc630665a1b34d6265980bea7a3aaa962f270813d42ac38dfca2d9c26d80eb20",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json 0.13.1+ds-1/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "2226540d930090e262d46feba14b67fd89451d3fc541d2f4c1b00e1a2d403b08",
+		"MAC" : "ac030eb583571f6856f0824bd932335f",
+		"key" : "287181cab7d4c181d0304d952269588b1c8f9b8b035509a23e1f318b22a9a3b5"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "7e089b422aa10839cb0946a556229267cbd98d66419fd9bb1b64aa495bba13de",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json 0.13.1+ds-1/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "3b68ce7d8b77d539d9489add5b6a12e98c4f173d26a9ea69179ebfb50b28e0b0",
+		"MAC" : "4102665480ed910ce2074f9c400ab704",
+		"key" : "ea15b083faf0fccce8860eeec30aeabc2ae719698dbeae98c7297d03a2b82777"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "91ca8984b7ea9f7451fb8ffe940ccdb0d087805a71233dc4cc06cce4574214c7",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "dd988df942bcceef3de9e5511d36b691402e551d90617915fab54c8c0a78d5c9",
+		"MAC" : "d49c05b6aaa1d976d15d9383ca036cb6",
+		"key" : "4b8711eb11bfb98657275e70aa62932a0d5993b81057d4e1359de092e7ca80f2"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "721a36a0b722809b2bc893aff136933fafbb3ce90a963ad755fbd591cce38512",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "7d86aa08ebe2d65d3d6d3e0a35b4a17e8e3def1f61a302393c1dde2a9c068352",
+		"MAC" : "d2935b9e346f28dad279519b7187b4b4",
+		"key" : "6eafa464c74837d96f463268618c6dbe29f0b8b9aa15992976433a7e0c68d91d"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "b6b562343cdee7c63698e265a1d9f96dd709d16aa3d627076a4d138f2f7d836a",
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.scrypt.KEYFILE2.json 0.13.1+ds-1/test/reference/2-padded/.securefs.scrypt.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.scrypt.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.scrypt.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "577a4cce74f0b6b6ab70202c5a23b81a6eb3a9772f228d08d7b4bcfaf47c1f35",
+		"MAC" : "c2af1ef1d555d9726758cda28ad85dd0",
+		"key" : "f40ff09d451356fb190b8423cfd7d67a5c1bcdddf4582238e0af425cef9c8417"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "b5194c63d92cb8ac066c8d054390216cc366e6c1d8be5b4111c8260033047797",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.scrypt.KEYFILE.json 0.13.1+ds-1/test/reference/2-padded/.securefs.scrypt.KEYFILE.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.scrypt.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.scrypt.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "a6dac10a546497fa12335b91342d46a4abf5f5dc3f804dd11832bccf678d022e",
+		"MAC" : "1070bb0b74c0aa17362b8cc2c8e65dad",
+		"key" : "56cca0682de7f82fe46b633ed64960b175dfd83307cfd8e0d9d7acc0752b47c0"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "cb32d279925c67e37815ca2595c605af3b806adb8501f6eae7f35b9b83cc1ac9",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.scrypt.PASSWORD.json 0.13.1+ds-1/test/reference/2-padded/.securefs.scrypt.PASSWORD.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.scrypt.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.scrypt.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "44c49c5d8db23cd8d7ec5f2095b3035a072f42453af8778a1d18babed10aae3f",
+		"MAC" : "218cff82ad583cb10863286e3d0c683b",
+		"key" : "ca5efa9b72a16ce730cb35d91449e62cb26c4b0a07114243bf65ec05f228534c"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "ff47914743a6b6b89459e0a188022824cf4a17becd80aac5dd17437d27b7b319",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/2-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "b59cece25018e4c4dc67b9903382a006b753ad2efb0715ab27ec3f1b4a12e620",
+		"MAC" : "6310528e86da1cd0c0c798cc50f88797",
+		"key" : "25490553b91f1d66ed4ca24d31e79f6e268654fb3ba5442a775fbc9067e966b6"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "e9a1ac5b37ee903be841202116634bc105178c6ea309ae46b11ac771dae81337",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/2-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/2-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/2-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/2-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "379653ce34b96c65164a4fa34494361147ad1a52b3ac312c9485578dbeccbfca",
+		"MAC" : "932105c5c30ca844132fc9d9771144ad",
+		"key" : "b27290497c3d1cc8d54eff9bf34091dae7f4b6561511f7ecb2681744c07cea09"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "b18ca2262295de223b6902edaba480ec0961bc53fad3ebb005e84dc08c6870f5",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 2
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.argon2id.KEYFILE2.json 0.13.1+ds-1/test/reference/3/.securefs.argon2id.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3/.securefs.argon2id.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.argon2id.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "9af0e3620eea489b5b85432dac865b355f7e95038f30bfd25f7aa70499f4468b",
+		"MAC" : "f7a04c4a2bcef64bfc7378b90648f020",
+		"key" : "4c2257cd1e13320a1f0a7d47297fecc0f51647c93d8f354f50e1dff05497fce1"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "c94dd9f7db4db00638514dc060eed05b2fddf858ae4b9489fcbe91cb8a989372",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.argon2id.KEYFILE.json 0.13.1+ds-1/test/reference/3/.securefs.argon2id.KEYFILE.json
--- 0.11.1+ds-4/test/reference/3/.securefs.argon2id.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.argon2id.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "6250a5eed5690f326302c4328171f152be37787334d12ca316f455da84cc4fb2",
+		"MAC" : "451359fcff33b45ed7fce2bb915409de",
+		"key" : "fb8f91228a9055320b1e106405e7e3308e9fef5142ad21e4d177e494e8b9593e"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "6f5905d32055bc8074deacc817c7a3678571eadfee43b917877184b3aa1ea549",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.argon2id.PASSWORD.json 0.13.1+ds-1/test/reference/3/.securefs.argon2id.PASSWORD.json
--- 0.11.1+ds-4/test/reference/3/.securefs.argon2id.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.argon2id.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "243986aef6fdb93ecf37237c6a3b531b6d313fc8c0bb71c3582cc6b683ec8e54",
+		"MAC" : "6b1430069b6ed25b697ecf74ec1cbb38",
+		"key" : "a32e0e374be9285afe39de68b2e0c6879b920a460f3796627228e8c88f507205"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "326deae503ab919cf7f855b97539b626bdedd2f4762e5fc01c0161651617e166",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/3/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "2974eaf1d589732c3cb2a76c7db4b4489bf5f0032dd1947eeca885b41088a9cd",
+		"MAC" : "bdf33202296a9e1c72815376f8cb6991",
+		"key" : "95f1ab1506b6826d482d8c724696496af6f09d1f38ebe84928a43f94d165ec22"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "f83be4b3e5d06e8574bdc1bbfeeaf9f76725d385f108b350dd0a6381626e5dc0",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/3/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/3/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "1ba7c12fb39f7eaa28b5ebd82355494bddc2c466a5a22c01a7802a6e4ea7e9af",
+		"MAC" : "f1c75dc91942a7997b16018fa18f5419",
+		"key" : "285e094b025b3310f0602ddaf1688702ccbb70b81b85ce287a901273f7bf625c"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "01c491d5d9b48294531ca4eb4f5b37728b72bdcb85a404fb5b61839123bc03ec",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.json 0.13.1+ds-1/test/reference/3/.securefs.json
--- 0.11.1+ds-4/test/reference/3/.securefs.json	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.json	1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-{
-	"block_size" : 4096,
-	"encrypted_key" : 
-	{
-		"IV" : "e7b7787c159fd7f0fd3531ac9181973ac6d60cd8cd78a30e602e8325641f5b66",
-		"MAC" : "bb192763ff52e869d7d0b17c214006d8",
-		"key" : "8bb5eb3a45ab619b7d6198b12fa8a16b7ea870fa995d59efae488a5678b9f8b4"
-	},
-	"iterations" : 4,
-	"iv_size" : 12,
-	"pbkdf" : "scrypt",
-	"salt" : "510701c37bf227da629f8ab4fe228ce7d5ec78abb5fa6d6cafe7d8917949a070",
-	"scrypt_p" : 1,
-	"scrypt_r" : 8,
-	"version" : 3
-}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json 0.13.1+ds-1/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "865387d76acfcb62720d8b0f8fb777a0ec0b19e361c187ae57cf9bb17eea6dfa",
+		"MAC" : "78e2ba05d7515e41f29f87e8ec21e925",
+		"key" : "2006a5ca01d19917843bb5892096e2406c092a1ed60fc5cc928e0a17d0cd6372"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "0afd452caab732f5041c7b9646c9a4cca8aa3845b69e68abcec80777f2b1ee06",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json 0.13.1+ds-1/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json
--- 0.11.1+ds-4/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "88a09c2c58b13da51b6de69002365ed8ee16c9bd34015d76de6ff2867619b6ad",
+		"MAC" : "18e7f9f71be35292955a7c6df2e1126f",
+		"key" : "93edddc812a9386ab148ef099be5329d33db48a6efc1ff4800a4aa7a65da8266"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "d8073c8f0d5b07b7230613382f8af99092cdb72dcc29360d2fb6b8a9ec0e10cc",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json 0.13.1+ds-1/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json
--- 0.11.1+ds-4/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "ccbbaa0b1c8984745c6127968927e2f210ee4de9b219d8f7a37eb720d0483154",
+		"MAC" : "ccf6e51aacadf40601e17a45be0d1464",
+		"key" : "fb87fc88fb8a51ec860416f4ebdcd220faaf435849055e91cc85e59ecf687d67"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "ad30fc3ce284fae3a0ba2737aabdf5a66f8d90dbea25031c884a3d26cd79df1c",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "9bf6ddb042c03afa99d2a37b9f6ef30d0f53606877399d1549188d00609026f4",
+		"MAC" : "1805581e4354cde6059b9b7f712cf6fe",
+		"key" : "f8407e2eb4a7c9e68931becfcbd63f56cadc54c2515e173d0a8649b3828baac8"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "41fff7c47f9f24d386daa5194f0d0a5ee1623c4e9843f18fd087b3af1b633691",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "56f68b1cb1ad8d1caf4c7810d4a03d546743b26d61d417a99af2e43fd7b879bc",
+		"MAC" : "cb55bfccb0b85ef33b01f0fc75340559",
+		"key" : "5b3cad4b17f51f63ce27d27486481815456bdcf503da4f51998f3e640f69c420"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "8a656baf405c709d6efae58a3c48554a95328c9fe359d7def1621c68bfab9b31",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.scrypt.KEYFILE2.json 0.13.1+ds-1/test/reference/3/.securefs.scrypt.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3/.securefs.scrypt.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.scrypt.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "9e5a8138260f1d093efc6afabc194dc77e9b0342c0027b1e9d32b34406a14d6c",
+		"MAC" : "1eea23da2c86de956c9aca2111e7c2e8",
+		"key" : "1a0dc3c09d0003722474b65e7d9032e9edad7bafe04eef831895dd9168182574"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "e7d4d641a8dc66c9f0679e3ceb98a4d0a98a7e3f821b92e23b18e171173c8a99",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.scrypt.KEYFILE.json 0.13.1+ds-1/test/reference/3/.securefs.scrypt.KEYFILE.json
--- 0.11.1+ds-4/test/reference/3/.securefs.scrypt.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.scrypt.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "f57fd1c1c8e712bdaf54c0252bbbe0e87fa1963be1063d4660ef5c9e2ae17365",
+		"MAC" : "b7bba481a0038b1536eb4bf543fdd85a",
+		"key" : "813f83d5a4f8d3d6ea7cad8e9bde47c3009d99f62085d0a8f03741ea677ef4db"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "4750805e98d9c1d1c071fd6ebbcf8bd536b1e84eb1cd99450fd3520b19b8b464",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.scrypt.PASSWORD.json 0.13.1+ds-1/test/reference/3/.securefs.scrypt.PASSWORD.json
--- 0.11.1+ds-4/test/reference/3/.securefs.scrypt.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.scrypt.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "3fc263e60b36260011096fbac33742b4f36967cf0ca344c703c1d87f5cba70d2",
+		"MAC" : "15dfa0c77de8497aa107610a1671cc13",
+		"key" : "60ad0df7efdf3d9c4945480ef39877be3aee8db6833477471c97a14921c0454d"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "c6da2c96e7fbe34b5ce797526c35e224705ef606d5de1412ab73c802f789d1f6",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/3/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "b09e395eb676cfe086d1245e3c3e95f2422e1acf924c19fe69aa136a70ddd7d7",
+		"MAC" : "b2d89baf57a85d5eb364cde3e6c3a7e9",
+		"key" : "05438c5dd5aeb98ce44dc0399001b472c2a2c5d1e0d0cc18951031a807313928"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "49083c3b41904e7e75e7fafd0705cbc5ba52f5b750fd6518e4ceb47aeddfd868",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/3/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/3/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "ea7939b494107bb03da21b5d845af2ec7e57e47e06510aec02b1b8c0c053f970",
+		"MAC" : "8d84e6d85e06c7880e2cdbb4a8bb0d57",
+		"key" : "da2aec7d1305e7e959877213f1eb1131154fe43dbfd0b9d1981c1d0bcd5bda80"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "f5fb7774f94fcad05849152c375c6cadf247778c933c5add18acab24ba7cd947",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 3
+}
Binary files 0.11.1+ds-4/test/reference/3-keyfile/00/00000000000000000000000000000000000000000000000000000000000000 and 0.13.1+ds-1/test/reference/3-keyfile/00/00000000000000000000000000000000000000000000000000000000000000 differ
diff -pruN 0.11.1+ds-4/test/reference/3-keyfile/00/00000000000000000000000000000000000000000000000000000000000000.meta 0.13.1+ds-1/test/reference/3-keyfile/00/00000000000000000000000000000000000000000000000000000000000000.meta
--- 0.11.1+ds-4/test/reference/3-keyfile/00/00000000000000000000000000000000000000000000000000000000000000.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-keyfile/00/00000000000000000000000000000000000000000000000000000000000000.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-c5[jk*vu +cztG?M\B%֞B\"k_2UKE+l{*_^&v./sLsLp#ًb
-^AݸͽǶ1ֈtW4&pkR.%@ח٧XA(oԄ5|
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/3-keyfile/49/990f5e1da00f40f09380b10e2a8069a80d6cdb2f446b91357917cde7736c34 and 0.13.1+ds-1/test/reference/3-keyfile/49/990f5e1da00f40f09380b10e2a8069a80d6cdb2f446b91357917cde7736c34 differ
Binary files 0.11.1+ds-4/test/reference/3-keyfile/49/990f5e1da00f40f09380b10e2a8069a80d6cdb2f446b91357917cde7736c34.meta and 0.13.1+ds-1/test/reference/3-keyfile/49/990f5e1da00f40f09380b10e2a8069a80d6cdb2f446b91357917cde7736c34.meta differ
Binary files 0.11.1+ds-4/test/reference/3-keyfile/55/cb6c54b1fa746ad2638e12fc23b8dee7915fe53303dc57e521c7a395cc4df0 and 0.13.1+ds-1/test/reference/3-keyfile/55/cb6c54b1fa746ad2638e12fc23b8dee7915fe53303dc57e521c7a395cc4df0 differ
diff -pruN 0.11.1+ds-4/test/reference/3-keyfile/55/cb6c54b1fa746ad2638e12fc23b8dee7915fe53303dc57e521c7a395cc4df0.meta 0.13.1+ds-1/test/reference/3-keyfile/55/cb6c54b1fa746ad2638e12fc23b8dee7915fe53303dc57e521c7a395cc4df0.meta
--- 0.11.1+ds-4/test/reference/3-keyfile/55/cb6c54b1fa746ad2638e12fc23b8dee7915fe53303dc57e521c7a395cc4df0.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-keyfile/55/cb6c54b1fa746ad2638e12fc23b8dee7915fe53303dc57e521c7a395cc4df0.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-*UY~BBI[`qK	iz3AKvfOhNP2ݳ8
-yoB&KS&*Ӳ/Âr5v,\zCm]S=`A1ZD(Dp.Le028-!'3-SNhҡႶ5Y
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/3-keyfile/6a/f994452233d3cfcef7f15e4940b57710f3ab720500bf17fe3022ac1b2454b1 and 0.13.1+ds-1/test/reference/3-keyfile/6a/f994452233d3cfcef7f15e4940b57710f3ab720500bf17fe3022ac1b2454b1 differ
Binary files 0.11.1+ds-4/test/reference/3-keyfile/6a/f994452233d3cfcef7f15e4940b57710f3ab720500bf17fe3022ac1b2454b1.meta and 0.13.1+ds-1/test/reference/3-keyfile/6a/f994452233d3cfcef7f15e4940b57710f3ab720500bf17fe3022ac1b2454b1.meta differ
Binary files 0.11.1+ds-4/test/reference/3-keyfile/73/59e5648e8b7bb1a08387276333c4db6e389e288eef940ec95be143506890a8 and 0.13.1+ds-1/test/reference/3-keyfile/73/59e5648e8b7bb1a08387276333c4db6e389e288eef940ec95be143506890a8 differ
diff -pruN 0.11.1+ds-4/test/reference/3-keyfile/73/59e5648e8b7bb1a08387276333c4db6e389e288eef940ec95be143506890a8.meta 0.13.1+ds-1/test/reference/3-keyfile/73/59e5648e8b7bb1a08387276333c4db6e389e288eef940ec95be143506890a8.meta
--- 0.11.1+ds-4/test/reference/3-keyfile/73/59e5648e8b7bb1a08387276333c4db6e389e288eef940ec95be143506890a8.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-keyfile/73/59e5648e8b7bb1a08387276333c4db6e389e288eef940ec95be143506890a8.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-r]L룙7SrQx%aC%!&<	LS6S@S|e4'8spz#qkI_3fsMԴjٶp%iÀVxJOAZ,U=XfTЇԽ*Yl.V۶
-2=
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/3-keyfile/7e/bc6761fe8fec86b747f26bee24fc94b3ec68ee8af4c1d3babdb8cf8e2e8ef2 and 0.13.1+ds-1/test/reference/3-keyfile/7e/bc6761fe8fec86b747f26bee24fc94b3ec68ee8af4c1d3babdb8cf8e2e8ef2 differ
Binary files 0.11.1+ds-4/test/reference/3-keyfile/7e/bc6761fe8fec86b747f26bee24fc94b3ec68ee8af4c1d3babdb8cf8e2e8ef2.meta and 0.13.1+ds-1/test/reference/3-keyfile/7e/bc6761fe8fec86b747f26bee24fc94b3ec68ee8af4c1d3babdb8cf8e2e8ef2.meta differ
diff -pruN 0.11.1+ds-4/test/reference/3-keyfile/b7/7844182b14255ba94fe3f0b3c6857adad58226fa67917eed70edafa70601b0 0.13.1+ds-1/test/reference/3-keyfile/b7/7844182b14255ba94fe3f0b3c6857adad58226fa67917eed70edafa70601b0
--- 0.11.1+ds-4/test/reference/3-keyfile/b7/7844182b14255ba94fe3f0b3c6857adad58226fa67917eed70edafa70601b0	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-keyfile/b7/7844182b14255ba94fe3f0b3c6857adad58226fa67917eed70edafa70601b0	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-1;XUL*/
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/3-keyfile/b7/7844182b14255ba94fe3f0b3c6857adad58226fa67917eed70edafa70601b0.meta and 0.13.1+ds-1/test/reference/3-keyfile/b7/7844182b14255ba94fe3f0b3c6857adad58226fa67917eed70edafa70601b0.meta differ
diff -pruN 0.11.1+ds-4/test/reference/3-keyfile/b7/91ba5a9464b33491ed9c7941b88eb7479367ed0deb64f22f4472e55f2fe442.meta 0.13.1+ds-1/test/reference/3-keyfile/b7/91ba5a9464b33491ed9c7941b88eb7479367ed0deb64f22f4472e55f2fe442.meta
--- 0.11.1+ds-4/test/reference/3-keyfile/b7/91ba5a9464b33491ed9c7941b88eb7479367ed0deb64f22f4472e55f2fe442.meta	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-keyfile/b7/91ba5a9464b33491ed9c7941b88eb7479367ed0deb64f22f4472e55f2fe442.meta	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-cbr^ B!|H7Ir6@w0}KCmԑ=G1L<!9\HTgz/q	$i47qO+@ʏӧ98$u4quBXl|-M?VqT""h$.1
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/3-keyfile/ca/a4ed417544d387e9244c10925c2774c38d2e75735f5d0d08812d1e07e09f89 and 0.13.1+ds-1/test/reference/3-keyfile/ca/a4ed417544d387e9244c10925c2774c38d2e75735f5d0d08812d1e07e09f89 differ
Binary files 0.11.1+ds-4/test/reference/3-keyfile/ca/a4ed417544d387e9244c10925c2774c38d2e75735f5d0d08812d1e07e09f89.meta and 0.13.1+ds-1/test/reference/3-keyfile/ca/a4ed417544d387e9244c10925c2774c38d2e75735f5d0d08812d1e07e09f89.meta differ
diff -pruN 0.11.1+ds-4/test/reference/3-keyfile/.securefs.json 0.13.1+ds-1/test/reference/3-keyfile/.securefs.json
--- 0.11.1+ds-4/test/reference/3-keyfile/.securefs.json	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-keyfile/.securefs.json	1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-{
-	"block_size" : 4096,
-	"encrypted_key" : 
-	{
-		"IV" : "00a5513da8efe0ddc355e1504045d45bc421363b540045346ee80972702fe2d2",
-		"MAC" : "d485b9fd04a75b5d312feb99e172b81d",
-		"key" : "238835fe5e291ac94bc09e12ef18b6334cb578cd239ecc13f715054bf2d52123"
-	},
-	"iterations" : 4,
-	"iv_size" : 12,
-	"pbkdf" : "scrypt",
-	"salt" : "b1917e1285d5ca7bceef0df3168411deaa34d0b7d2fbe765f87e6340b95a879d",
-	"scrypt_p" : 1,
-	"scrypt_r" : 8,
-	"version" : 3
-}
Binary files 0.11.1+ds-4/test/reference/3-padded/00/00000000000000000000000000000000000000000000000000000000000000 and 0.13.1+ds-1/test/reference/3-padded/00/00000000000000000000000000000000000000000000000000000000000000 differ
diff -pruN 0.11.1+ds-4/test/reference/3-padded/00/00000000000000000000000000000000000000000000000000000000000000.meta 0.13.1+ds-1/test/reference/3-padded/00/00000000000000000000000000000000000000000000000000000000000000.meta
--- 0.11.1+ds-4/test/reference/3-padded/00/00000000000000000000000000000000000000000000000000000000000000.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/00/00000000000000000000000000000000000000000000000000000000000000.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,2 @@
+34ve31Yq]Z1*DD`hHhVαoc)VunHN=8xfˈ5VDk?vU&Sqc<93Iu`Y`?-|X9
+>~0o#N9^ v}Rs(&}zAC,tҳLqd8
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/3-padded/55/aea882889d6a2cf8a4954ba62aca318244fea1d6f3a5b6b4523f1cc294aa0d and 0.13.1+ds-1/test/reference/3-padded/55/aea882889d6a2cf8a4954ba62aca318244fea1d6f3a5b6b4523f1cc294aa0d differ
diff -pruN 0.11.1+ds-4/test/reference/3-padded/55/aea882889d6a2cf8a4954ba62aca318244fea1d6f3a5b6b4523f1cc294aa0d.meta 0.13.1+ds-1/test/reference/3-padded/55/aea882889d6a2cf8a4954ba62aca318244fea1d6f3a5b6b4523f1cc294aa0d.meta
--- 0.11.1+ds-4/test/reference/3-padded/55/aea882889d6a2cf8a4954ba62aca318244fea1d6f3a5b6b4523f1cc294aa0d.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/55/aea882889d6a2cf8a4954ba62aca318244fea1d6f3a5b6b4523f1cc294aa0d.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+zÅP$v;(qiH-hJh,hb)odNpgi,QtѦ=WbGWVGǳ=y>ET/+c$yh*B9:/_Q}8#]5q(ZmL}i.5\Ud8/Lz_{u5
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/3-padded/61/df00c83ca67af03afdd285b754a660d678bea05a5cf014c7f970a384d1492a and 0.13.1+ds-1/test/reference/3-padded/61/df00c83ca67af03afdd285b754a660d678bea05a5cf014c7f970a384d1492a differ
Binary files 0.11.1+ds-4/test/reference/3-padded/61/df00c83ca67af03afdd285b754a660d678bea05a5cf014c7f970a384d1492a.meta and 0.13.1+ds-1/test/reference/3-padded/61/df00c83ca67af03afdd285b754a660d678bea05a5cf014c7f970a384d1492a.meta differ
Binary files 0.11.1+ds-4/test/reference/3-padded/94/164b4ee1a9c7bffa9447858aeb85e52742d357f1500450ccb8c0b41a200415 and 0.13.1+ds-1/test/reference/3-padded/94/164b4ee1a9c7bffa9447858aeb85e52742d357f1500450ccb8c0b41a200415 differ
diff -pruN 0.11.1+ds-4/test/reference/3-padded/94/164b4ee1a9c7bffa9447858aeb85e52742d357f1500450ccb8c0b41a200415.meta 0.13.1+ds-1/test/reference/3-padded/94/164b4ee1a9c7bffa9447858aeb85e52742d357f1500450ccb8c0b41a200415.meta
--- 0.11.1+ds-4/test/reference/3-padded/94/164b4ee1a9c7bffa9447858aeb85e52742d357f1500450ccb8c0b41a200415.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/94/164b4ee1a9c7bffa9447858aeb85e52742d357f1500450ccb8c0b41a200415.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+RTD&Cfz^,U>b^^g5=2i	Y޾|'_ާƪHS`"MI0%gba5&9$>!aǨH8w'.ߋqޗ*Pxˆoґb& u`헽-U
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/3-padded/b1/92369d6526f986a2114b202bf5bb942b85a7dd76551389e559204c965e68d2 and 0.13.1+ds-1/test/reference/3-padded/b1/92369d6526f986a2114b202bf5bb942b85a7dd76551389e559204c965e68d2 differ
diff -pruN 0.11.1+ds-4/test/reference/3-padded/b1/92369d6526f986a2114b202bf5bb942b85a7dd76551389e559204c965e68d2.meta 0.13.1+ds-1/test/reference/3-padded/b1/92369d6526f986a2114b202bf5bb942b85a7dd76551389e559204c965e68d2.meta
--- 0.11.1+ds-4/test/reference/3-padded/b1/92369d6526f986a2114b202bf5bb942b85a7dd76551389e559204c965e68d2.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/b1/92369d6526f986a2114b202bf5bb942b85a7dd76551389e559204c965e68d2.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,3 @@
+A9U	ɒVߴ1rAGPSuhqBT
+/s^ukETȴQ=冢pTuz\Z$<]d8a ߄eAII Sf틓
+T|ձú7̯j,.4IqƎc'FY[U`IJmAu<
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/3-padded/b6/9e1c5c87778226655d14ab39a7050be9455eec054e28aa53e99edebad81c7b and 0.13.1+ds-1/test/reference/3-padded/b6/9e1c5c87778226655d14ab39a7050be9455eec054e28aa53e99edebad81c7b differ
Binary files 0.11.1+ds-4/test/reference/3-padded/b6/9e1c5c87778226655d14ab39a7050be9455eec054e28aa53e99edebad81c7b.meta and 0.13.1+ds-1/test/reference/3-padded/b6/9e1c5c87778226655d14ab39a7050be9455eec054e28aa53e99edebad81c7b.meta differ
Binary files 0.11.1+ds-4/test/reference/3-padded/b7/c78515d8ff91be615f39308ff44f0f01415fe2699171b25c600d11a1ac8ddd and 0.13.1+ds-1/test/reference/3-padded/b7/c78515d8ff91be615f39308ff44f0f01415fe2699171b25c600d11a1ac8ddd differ
diff -pruN 0.11.1+ds-4/test/reference/3-padded/b7/c78515d8ff91be615f39308ff44f0f01415fe2699171b25c600d11a1ac8ddd.meta 0.13.1+ds-1/test/reference/3-padded/b7/c78515d8ff91be615f39308ff44f0f01415fe2699171b25c600d11a1ac8ddd.meta
--- 0.11.1+ds-4/test/reference/3-padded/b7/c78515d8ff91be615f39308ff44f0f01415fe2699171b25c600d11a1ac8ddd.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/b7/c78515d8ff91be615f39308ff44f0f01415fe2699171b25c600d11a1ac8ddd.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,3 @@
+
+V'}GlyeYϭݝy)#έ*͉K 3v〒=ddohߏ7(afF|}<\>iZQQ@\fRKo- F=zۡ8h<4&45u>#
+:F|Vh,d"f/eD?uUz
\ No newline at end of file
diff -pruN 0.11.1+ds-4/test/reference/3-padded/e3/5e2ae5e2fc05f4cae9dcfc73766764419d16bc5c4f0e8b221ac4683fe3a0fe 0.13.1+ds-1/test/reference/3-padded/e3/5e2ae5e2fc05f4cae9dcfc73766764419d16bc5c4f0e8b221ac4683fe3a0fe
--- 0.11.1+ds-4/test/reference/3-padded/e3/5e2ae5e2fc05f4cae9dcfc73766764419d16bc5c4f0e8b221ac4683fe3a0fe	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/e3/5e2ae5e2fc05f4cae9dcfc73766764419d16bc5c4f0e8b221ac4683fe3a0fe	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,2 @@
+ٙs<޾
+&ː^-W;zZ5J2!
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/3-padded/e3/5e2ae5e2fc05f4cae9dcfc73766764419d16bc5c4f0e8b221ac4683fe3a0fe.meta and 0.13.1+ds-1/test/reference/3-padded/e3/5e2ae5e2fc05f4cae9dcfc73766764419d16bc5c4f0e8b221ac4683fe3a0fe.meta differ
diff -pruN 0.11.1+ds-4/test/reference/3-padded/fc/d69806e2242bce1874b73ddbc933cd8420740ea19eacb0235554cfd94f50c0 0.13.1+ds-1/test/reference/3-padded/fc/d69806e2242bce1874b73ddbc933cd8420740ea19eacb0235554cfd94f50c0
--- 0.11.1+ds-4/test/reference/3-padded/fc/d69806e2242bce1874b73ddbc933cd8420740ea19eacb0235554cfd94f50c0	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/fc/d69806e2242bce1874b73ddbc933cd8420740ea19eacb0235554cfd94f50c0	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+kz^8\vX|+ͲWmkd1H_i?t0A.z>MB+ɮ@GqW0^"bCWu̻!G;݄ѯ|7Yp im\n=#]DhVy$I߈j3T.dxRP,	|vrcw@'6x1x
\ No newline at end of file
diff -pruN 0.11.1+ds-4/test/reference/3-padded/fc/d69806e2242bce1874b73ddbc933cd8420740ea19eacb0235554cfd94f50c0.meta 0.13.1+ds-1/test/reference/3-padded/fc/d69806e2242bce1874b73ddbc933cd8420740ea19eacb0235554cfd94f50c0.meta
--- 0.11.1+ds-4/test/reference/3-padded/fc/d69806e2242bce1874b73ddbc933cd8420740ea19eacb0235554cfd94f50c0.meta	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/fc/d69806e2242bce1874b73ddbc933cd8420740ea19eacb0235554cfd94f50c0.meta	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1 @@
+yO4%RoN{VbFlxng[@=[=slo*pt0te#3kqʣ>^Ͳ &aYXh*N&<v?@qnʈXt7g.V'gѣBcMy0IV.
\ No newline at end of file
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.argon2id.KEYFILE2.json 0.13.1+ds-1/test/reference/3-padded/.securefs.argon2id.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.argon2id.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.argon2id.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "3bebef10dd9891337a2cf3876a699b78e0d5cfcafb1186969e5e46dddc98fff7",
+		"MAC" : "cafab88c0251cbe745ef5373e2cbeba8",
+		"key" : "c955f00802a7ec671a20bcf15192d49a93fa03abd28bccfa0e7dbe4d80cc6ac0"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "6ba9395cdeea6668f88ed1f4de5a74ba3faf3d340db91f8dbc2fca747a71125d",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.argon2id.KEYFILE.json 0.13.1+ds-1/test/reference/3-padded/.securefs.argon2id.KEYFILE.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.argon2id.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.argon2id.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "cfedee6cfb6a54eeee4ded2d74c18ae8a9da7164f5710bbdb43a22a834096e2a",
+		"MAC" : "a8433151d2ecd4668e47fe13e01246de",
+		"key" : "6b0c3d04c32395c2b8e6e99dd4e804aa8cc2b6117df3db661538dea2447eb11f"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "ebe7c064ddd45bf3b90592c99eafec3f28e0accbf278e88cf0f54604749391bf",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.argon2id.PASSWORD.json 0.13.1+ds-1/test/reference/3-padded/.securefs.argon2id.PASSWORD.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.argon2id.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.argon2id.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "e6fdd6b4da84371ab7b3bed57f32fcb861c81ed7496deb671253b5e47489963f",
+		"MAC" : "4c17dafd51cbde8812d50c75f0788ba0",
+		"key" : "ef3c6d9d79f0a48a0256481ad29769dd87d4bf6d31943225a1c7c55cb67819c1"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "f9e99193da4d9b948bf4c4ac3880a390587de12b8e1bf87fbbd4ca55b4a1c417",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/3-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "d7a4bbc1e242c5f7da731c1429703f655206428111e147430a9ad7c6a0d2073a",
+		"MAC" : "35afb40155138c3ec69c497dd6793417",
+		"key" : "12a19e9a94bfa3d7903ddd47c54b98fb335c1b48b38e1113db0ba740784e641b"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "b7d44e7df497cd9afa06e7eb5c9ff373b9b52172bc95ff15c969d85d31660969",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/3-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "9df35e90f1ef2569c3ed574fc19a53c4527cbfc3004ee96c81801163a9a10ab7",
+		"MAC" : "1b770c52514851ec843d37790a1f5852",
+		"key" : "c9e7d4fbacd2cca437730121a129f76862dddd342db745be0c57ee13c4a11127"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "2bd31c55324f0a902ff97afca326b2c4fce8d4cab7c43a1aefbd435d7ed3ab5f",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json 0.13.1+ds-1/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "bee9eae27366937b6ceb69c564c1a585509ef10ba2000dced80485c1e2156a0e",
+		"MAC" : "2a211c8a4af5b2f254691ba19accc88b",
+		"key" : "d16d57786dc432babc0c34107674a3222c388dba0b0a375858d1da2d5b7d4828"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "c0e3d3a8fe45108532a491576b4640576125cc71c473c7614d13a2f6df92263c",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json 0.13.1+ds-1/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "a59a63133a0825f38518a8cf3f126eb8e276fb255fd117df1873a4967f0a75cc",
+		"MAC" : "174e7acb40d9d4b4961a5a057f505e30",
+		"key" : "dfea3434c77e3548a51218d066022ebf9160e9c4a4c4fb0f4306590b8059b7b7"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "64e3560b7b673bd883dacd0f929402d8c144b1fad7f9dab81b91fe7c4cb92b7e",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json 0.13.1+ds-1/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "a8eacca8d0360498fb03a225802e3ab0e006dd6b8eba33a9f1346d8c4266f8c7",
+		"MAC" : "6e885291e07e65e2d910fd2dc3b3a58c",
+		"key" : "d32d4d33bb9f7d67004d306903cea1e3cba36bb9f20e763d51b05d8f8891aef8"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "fd5e31fddd45ebffff08cc0e5c4d6d0bdcf1a433b80cd6f31ef594d150a0bfe2",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "f8921f5cbb2f2147b854175ac8f2128155f63bd74b3eeded5ef673ae23e78e33",
+		"MAC" : "a269b253bedae101b6faaaf235897743",
+		"key" : "fc1a533273fb375ba2e1cf7c1feb3d9bdadac7028ca2068cb4aad76af13a93e7"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "113ea9803d56b0db78d999df21f91af6875d3c41dcd4bbdfb09978751ce58d5f",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "3f63db9fc228e08aabb68dfa4cfc351ab3e252e2d2e7c56a68b9cc555cce5ca4",
+		"MAC" : "b6b7c5a67e7773b1fad1df803c82bbd1",
+		"key" : "caf78f8498ecce6b966789a820e1ab08baab84508c342936bf1bec6427b7416b"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "6a58b7814b4b02afe4b8369f92227f82ca40700f0120890c22c6cd8f6fe9c987",
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.scrypt.KEYFILE2.json 0.13.1+ds-1/test/reference/3-padded/.securefs.scrypt.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.scrypt.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.scrypt.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "e00f93575fa6466a9e2131936534326a6e308bfda73293abbf745a80b2501ea6",
+		"MAC" : "4d0dcab92276a3b6be685ddfc35ef784",
+		"key" : "2be7561de5a2e868d368900c65014e71b1d4851fb0cba863c3b158461387773c"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "84ac772ec873e5c713d6c7951d458de02a07f1f1b6cb4f3bfe711d5c263c0164",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.scrypt.KEYFILE.json 0.13.1+ds-1/test/reference/3-padded/.securefs.scrypt.KEYFILE.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.scrypt.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.scrypt.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "46269dca64f4db470cf0453f995a8c2e2b04bd6b2c3390ea68ca0edbb50ab7ec",
+		"MAC" : "42fb4bff4784657157d09f44005403ef",
+		"key" : "705c7d2911c11f6431c71df4c746c5a29e232b2c148aa1035b7d31d8e531c1b7"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "cf4e6b1ea83fd5cec4f5d44ad9f154bf1ac0b082ac8a390dfa6eedadace5b10a",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.scrypt.PASSWORD.json 0.13.1+ds-1/test/reference/3-padded/.securefs.scrypt.PASSWORD.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.scrypt.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.scrypt.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "1859e19edffd9d39c74a1429fcd9f41acd3b1084d6172191512b552b08a1deb4",
+		"MAC" : "b121f1e5032312e8712057516337bd46",
+		"key" : "a2455cd29394f0088cd4e20f37fe42a6d734c11267d1948d324dc4ec1e50079e"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "627240297a530f1cacb02842b432e6deed62a2e2d96347cb4540876565939ad1",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/3-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "d88f9eba67b174d9fef75341f1f69985d16a762ebd2a3a55ceda3d2c5b962cb2",
+		"MAC" : "83a80ec6b25e07fa549420c3d7c61bc6",
+		"key" : "a631fd5a88aea9e6af90ed4e203dd5e26dcf679d0a077da97690218f04bb83b1"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "cda6ce654d8f027e61478762a8051e4954ffe6812d0b980e58444fe550432f04",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/3-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/3-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/3-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/3-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "19f2847363d3fb2cac7ce4b29020691d09b2fead83f317617a7e75d0aff6fa57",
+		"MAC" : "b2dba0c027c89497371a4560c3109a51",
+		"key" : "d41a59578cf6cb5abbf5cc31e60e9024382c8b17fcb543738c675cd5c46e8a62"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "8de33b2520d0c7ea6cfb22ca4f052364f07e62a3b78bc40b31feeaece9e58c82",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 3
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.argon2id.KEYFILE2.json 0.13.1+ds-1/test/reference/4/.securefs.argon2id.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4/.securefs.argon2id.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.argon2id.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "8294acf499b3aa6320467938a0a9105d0b606bd213a8b1fedc32034127226248",
+		"MAC" : "44c49a189c2b771a3cbebda5a18e9776",
+		"key" : "d1aff1e36f31ca639ccd860fff1aa61681e4eddf6aa31cd411b9012d3f731b5f940e9bbd003cf75d7d6daf0425e896f418851035f872f2e133710d0758e752e9b2d1dc18ed7f2b0708b9028fee6c9749825a84ce5ee8a47f9352c67e8e047ff3"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "485e91bcbd8c4685a0a172101151c603cfd1d7d58d6cf1e0f7a0023ab38d74c0",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.argon2id.KEYFILE.json 0.13.1+ds-1/test/reference/4/.securefs.argon2id.KEYFILE.json
--- 0.11.1+ds-4/test/reference/4/.securefs.argon2id.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.argon2id.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "7c73bec2cf15183fcde46097f7893361680deba40ff440968d4e12c4b2848d98",
+		"MAC" : "99f629174f648cb0015971af7fe8ada8",
+		"key" : "41d8e8fc75738204cb120e9f5c37e89887595c3c93918eb9e7f0bdff79c7a12889cc51fe6993cf998b8be64d4efec46c6285eae18656d4fdd2d93120d4c77c9558359ed4496142b3bcc555d104ebede39e426d09e143fbac7668a27c6d130194"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "b88d66c2a7241cd6649507c3d4930ca208bc536ae6509375565cb2a25fc5a679",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.argon2id.PASSWORD.json 0.13.1+ds-1/test/reference/4/.securefs.argon2id.PASSWORD.json
--- 0.11.1+ds-4/test/reference/4/.securefs.argon2id.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.argon2id.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "ef334a95029eaf48afa9d17eafcec3ade0a376e5a08f7717162f8d785062e853",
+		"MAC" : "d2ca7ddb5e56c3e6c4d170331a86e780",
+		"key" : "5477943654f08ecf1bc3c356a85abbc2de0f7043a984aae7466d823c39b081395b3a76446802a635d451a2c94316089fcf611eb66974473b8400a5f61fb3a6d367b41aaca5c9f922f71ffc8bcdde141cfd745a6b9e9e5326e94c3a7023e8ad4c"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "80dc5845efb7c2c7c1cc27a3da89fddcf2ecb0b00293e999d924faca7da4e2b4",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/4/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "90e8e8c0d058ef1763b559eabb6b0395642231cc2972934b4484b7a9995bcf0f",
+		"MAC" : "52b6fb5d3a82e38554530a116dc6d589",
+		"key" : "e479ed9e00af525de84128800c48ab42bea4954cd820783dcd45c93fec0a2d2ae8f9449eaed211b3c44f4d665e0d2d4861573be7d9237dc7ca133cdce66b8214a36a9ebba26ef4c0de6a1695add50ff27a6ec07df5c3f39ba2020df2f3191817"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "86526f0305245a7904f101bc2ca3c044d153c06a5ab7d63b953b1f6baddcd342",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/4/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/4/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "879db6589148bff101d20ce54085136347c21c61361174e51ce40ca663e0132d",
+		"MAC" : "63aa9bd298fc994e0e0fef6ca236594c",
+		"key" : "ef2fa7e81ed83ccc5aaa518ac23c0d9f3070f183c17a58a0961461be8c78e50ca9ac2b41dbaef1f5536cf7a8816b51053c5c923e094e2e2cbecc6abc560f09d2c43f119de921e1552664e997bd5632b4df8124f7cb19c1e6c157cc0fccd3c973"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "argon2id",
+	"salt" : "bd0ccc4d503893b43c55a8c2e97ead6115eb132916248d6387c86ac5bf9f708e",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.json 0.13.1+ds-1/test/reference/4/.securefs.json
--- 0.11.1+ds-4/test/reference/4/.securefs.json	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.json	1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-{
-	"block_size" : 4096,
-	"encrypted_key" : 
-	{
-		"IV" : "72c9dd13ef08cc9be4d1d652b35e58c63a5bf3fab2d8e986e54b66aa5546980b",
-		"MAC" : "5e66dac0bec23e851f3568ee2155cd5e",
-		"key" : "655e318ce9d192d6e2df7ab9f829e8e3cd41a8654118351b47801617793ad0a866abc9b04abfa4f0b218695d02b0eeee9eb18f66db7b45c559c2c84cfa169ffc2b5917936f13ceb9c38e0a5ab4809a871aefe108b5da7fb025b29073c69602b0"
-	},
-	"iterations" : 4,
-	"iv_size" : 12,
-	"pbkdf" : "scrypt",
-	"salt" : "7775462822d24892baf4bbcd5149e5ff76d8a2408e120639bfcef8bbad2637ab",
-	"scrypt_p" : 1,
-	"scrypt_r" : 8,
-	"version" : 4
-}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json 0.13.1+ds-1/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "5b15c33340e823021507d7abaa60380e56358ad012d0169425c0f0abad882970",
+		"MAC" : "a05adf8d918ba52bc6c048e45132de53",
+		"key" : "464c70ee1072477f6a59d443a86bebf71e331f038902343dfc609a4c0e56368c12cb8d8ab7f7c0e94ae8e2ddbbb174d3e1dbd583fc0b88f56fb09d6b18bf183298c96c1e295caa380bd35674ef57c985e52c7741cce5fc5697dbfc28686c06d6"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "a279044a06aed7a68c109c75ea67e5fcbf36dc95034bdd827cc8ebef03ee670f",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json 0.13.1+ds-1/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json
--- 0.11.1+ds-4/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "029ec5f6a0458478f9ddba14d74aa70ca6dc40dbcadc47ab848eb474ccdabc8d",
+		"MAC" : "04e1505e32c48d5fe9ff99dea8859afc",
+		"key" : "8a9f111afebf37749d2d15fdb75c56cfe3d83955315fe3fcd4d0dcee8e8d9f549c602ef614fd791c710cf174a28d9c1dac9760533dc2aab4e40be841c74ed511a153c8c4111df739b2162c657b76df8b29d0212ca6e075bb8727929d96856c59"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "68f04a2e2e4f8d0d90de9bee3a35b4a6b4f04c3139be73aab56356b18921158d",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json 0.13.1+ds-1/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json
--- 0.11.1+ds-4/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "8a6e5fbeb3b2f314656f647e908f15660deaa384954ea8b1daeb42edbfcd895b",
+		"MAC" : "1d6e3c19a6adda98507a3f253a3802b0",
+		"key" : "148b4b00ffdb126a2dc1a63a227b0e30d41070cb235f7d8155490cc17979174d404c6987d5b2842221fba8503c091a46cae22e431240f289df61bbe303efde7f1e44c5cc5c82f9c22799dd7cc0ce3dd12f5cb9fd013907568ab6f3b88233e132"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "2a5a9154fe1f4a0476fe6bf5a2747ce704720d0da24ab7a426c45b0c9d932111",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "efc4e87caf4c2c531e29332f3ec5a54ab2ba39a002c41398963a0bc80ea0d38c",
+		"MAC" : "d46cec89445aed17172e7f640cbcc3c7",
+		"key" : "6a30273f99d1c02f0ce04e5055f438523cb4796a83a45f5220e38fb339e1e89c02a54d569c57c4702520d096d2ce7d455b97eb97beaae0df431b5c3fa8c33d0453a6cadd6394cef11c22fdf37d64adba1c598f8a5919bd985ae9b630a9aa5a3f"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "042f70db4f8d260b5329c9da0010bacde52e518a2e266e463a42339f7d8abf11",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,14 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "c5d103fdc7ec6afb5a5ab27d1e8c6a6c9b29813fa2c71ec557ddede0a74659d3",
+		"MAC" : "dcd21693071aaa84db843d73ec4ea02f",
+		"key" : "b8aae2f5f01fd764df20dbb521cab38ad2cd73ac969929973a6df2703adf2ee963487fe318eb62c6b04562c7eeed01fb898a35a90ef255d1102c40e80e898bc9321491b3a324dec65420635bc1358c8cae480ef0cf7777a787085090c9c46883"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "e293701ba46bcc9ab874947fd7d412946c6e23e827b526841b61567ced9910eb",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.scrypt.KEYFILE2.json 0.13.1+ds-1/test/reference/4/.securefs.scrypt.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4/.securefs.scrypt.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.scrypt.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "82afdc4b17eec55ce4adf9b64f05ec58fc4c7054b666b1b735c79681c20f5f8b",
+		"MAC" : "b3df552bece79cee106d67c932707660",
+		"key" : "369ed2557409fcd92d94558c40e08cd90f447125020ca4c61ba322c7f739c0ea7c0cd1485ea0fba73ea5f615e62e565aed098daca67ccf7e2b6d0b0062efe16b358242b629bd40af673cd132d9e28b2ed4a4f11a7ee2cd4dc9fef4afcaf1c242"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "91d78d9fc97604a883b0d471115d4f88de1f2ac184d99906a10cc6df95bf34da",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.scrypt.KEYFILE.json 0.13.1+ds-1/test/reference/4/.securefs.scrypt.KEYFILE.json
--- 0.11.1+ds-4/test/reference/4/.securefs.scrypt.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.scrypt.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "72646bc7d82497ed7c66c41c6609b22c343dafcbd48c7cdc326ee8fd4561423e",
+		"MAC" : "a45256faf8d3a44b3f4aea8e133310f5",
+		"key" : "3e44958dcf98b0555cf660a155c27c440a31c6b9df4ea48964bcb6cf58fd240e47f75d1d1de9148949ddd1c93c890640b6bd405e9da747c5982f1662f0d317305bb685a9244c5800cbfbd9602a144136cd6865bba4ba0266e88f37c04dc9a402"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "f1ce13d8fd61f42a5b8e72ff05c52b29dfac763f6a28f05fc1de0ba9743e31ee",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.scrypt.PASSWORD.json 0.13.1+ds-1/test/reference/4/.securefs.scrypt.PASSWORD.json
--- 0.11.1+ds-4/test/reference/4/.securefs.scrypt.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.scrypt.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "54a79a06adb6b7d22338cfe55753fffe4ec5cd9f203107e8faa848643234106b",
+		"MAC" : "57ba435bcb54c2d2616c341fbe035693",
+		"key" : "02e6c87b4afb2b97c1723431a92b66072a2b83201c5f3299290033d7262fd80e80b2dce830a09616869f29b415ce740ddc871ab6626020e8aec5d1f1fcd58d69c94bae47ea47ccc8d8f45e00ab2cfdaa537fe89f0dde8f38d53c96cce26e19c1"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "0105c30cc501b9a2a91ea8b98a92938942668a4761c912b0d37623144b7a305a",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/4/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "1d6c901a24b8729c73a7a7919dd6435e9679e2936fed3319de0fa6ad4fe31dde",
+		"MAC" : "6320ce0fb4efb9b6eda4197ff9d9e542",
+		"key" : "9c1d877bae3b36c94042838861447f0eaef4ccc8b94eb089854580c65c43072290939a9fb49b15e29256aa9798dae9f138a23c33f0a7868b0fe472d4a8e73f4bcd2bc851017983b0929eb54bd985e33eafcb2c902f80bd548934278853503fd6"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "6c818bd9b5ce987639d52b854a6ba369eda274d9edaad3e3777126e12c863316",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/4/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/4/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,16 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "fdc417b508f7909903ea42a812cab30f6dd0ba8dbe359c1803a5f60822dd511a",
+		"MAC" : "32552fe2412f4c103aed7d12e378522f",
+		"key" : "b612199bcc45342eddf511844fc48d6b8df6dd3224c6e117dc47b2970541672ef1bdbb02d626d35bd998e6bba0529e24afd34bcb6e0758c0b3a925422538512d8c01e01ac9d5df61a9d5a1f6af5331a79256f73a1b5e31426b3cfb816828b589"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"pbkdf" : "scrypt",
+	"salt" : "a267129efd5efc3b031ab3b47684d12ed508480422bf0b239f090983ce652ba3",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 4
+}
Binary files 0.11.1+ds-4/test/reference/4-keyfile/2FGKAGVD7MECYS6QFEKY7F3X2KUQ2CE89T9S/358BFIRRGA3XE559IWIC63BK3F8FCBMHRGDFXJP8K7NU42QW9HAC4C9QTWIVVQHRPZPA/DQ3SJB9ZNYISKTC973PVCCGQ3Y234PZXAPTPPPI and 0.13.1+ds-1/test/reference/4-keyfile/2FGKAGVD7MECYS6QFEKY7F3X2KUQ2CE89T9S/358BFIRRGA3XE559IWIC63BK3F8FCBMHRGDFXJP8K7NU42QW9HAC4C9QTWIVVQHRPZPA/DQ3SJB9ZNYISKTC973PVCCGQ3Y234PZXAPTPPPI differ
Binary files 0.11.1+ds-4/test/reference/4-keyfile/2FGKAGVD7MECYS6QFEKY7F3X2KUQ2CE89T9S/C459VVNQD38362TMWKBM2FHESII49QVMRRJ4Y and 0.13.1+ds-1/test/reference/4-keyfile/2FGKAGVD7MECYS6QFEKY7F3X2KUQ2CE89T9S/C459VVNQD38362TMWKBM2FHESII49QVMRRJ4Y differ
diff -pruN 0.11.1+ds-4/test/reference/4-keyfile/KJ9DSI6CYKHAXT68FSH4QUN2KQ9FSKVH2IUTW 0.13.1+ds-1/test/reference/4-keyfile/KJ9DSI6CYKHAXT68FSH4QUN2KQ9FSKVH2IUTW
--- 0.11.1+ds-4/test/reference/4-keyfile/KJ9DSI6CYKHAXT68FSH4QUN2KQ9FSKVH2IUTW	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-keyfile/KJ9DSI6CYKHAXT68FSH4QUN2KQ9FSKVH2IUTW	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-֊l%AۆieGR"qgҪPM9^'٢WsZR]ʲ
\ No newline at end of file
diff -pruN 0.11.1+ds-4/test/reference/4-keyfile/.securefs.json 0.13.1+ds-1/test/reference/4-keyfile/.securefs.json
--- 0.11.1+ds-4/test/reference/4-keyfile/.securefs.json	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-keyfile/.securefs.json	1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-{
-	"block_size" : 4096,
-	"encrypted_key" : 
-	{
-		"IV" : "11ddfce0d647550f2aef3e588af180568b0c05c6a862d7c0ad666e293c6347ad",
-		"MAC" : "b97bae778a5a58eb0fc920f032525e9b",
-		"key" : "b43ea3e7eabd3973c86faef8c10e4616fbe3c0668f90901773cf511d7650f8d11b87344c9cabe50a294bd86316837e470961b10c7bba0e62cb46294b6476f3032ab94712d5ef72789fe2f2f80618dbe80c0937df4db7e34e83734fed46d58c64"
-	},
-	"iterations" : 4,
-	"iv_size" : 12,
-	"pbkdf" : "scrypt",
-	"salt" : "cfe827c3c61052804ddad40b48a2c6311565e12b52dbc54a0a701db557d8aea2",
-	"scrypt_p" : 1,
-	"scrypt_r" : 8,
-	"version" : 4
-}
diff -pruN 0.11.1+ds-4/test/reference/4-keyfile/TSYV6RMRGFWFYYF8VHUSU6W5MFBQGC2UQ6C7DTVQ 0.13.1+ds-1/test/reference/4-keyfile/TSYV6RMRGFWFYYF8VHUSU6W5MFBQGC2UQ6C7DTVQ
--- 0.11.1+ds-4/test/reference/4-keyfile/TSYV6RMRGFWFYYF8VHUSU6W5MFBQGC2UQ6C7DTVQ	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-keyfile/TSYV6RMRGFWFYYF8VHUSU6W5MFBQGC2UQ6C7DTVQ	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-͠+WϨ*ԋ'
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/4-keyfile/W795E838WH6TZHHW58T32B4S5YB2R37MKR6VAD7KTFAU6VAPSUX79YITUISS/F6CP7BNNMIQGBA2RRQCVU2W4ZKZ6RISTW4SP6H2 and 0.13.1+ds-1/test/reference/4-keyfile/W795E838WH6TZHHW58T32B4S5YB2R37MKR6VAD7KTFAU6VAPSUX79YITUISS/F6CP7BNNMIQGBA2RRQCVU2W4ZKZ6RISTW4SP6H2 differ
diff -pruN 0.11.1+ds-4/test/reference/4-padded/35ZQWZ4FMEJR2GZRK3S78H9IB6H9XMTQY39QC 0.13.1+ds-1/test/reference/4-padded/35ZQWZ4FMEJR2GZRK3S78H9IB6H9XMTQY39QC
--- 0.11.1+ds-4/test/reference/4-padded/35ZQWZ4FMEJR2GZRK3S78H9IB6H9XMTQY39QC	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/35ZQWZ4FMEJR2GZRK3S78H9IB6H9XMTQY39QC	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,2 @@
+y8/C˶5CB^n[CX
+h1겏c3A.b#=?8bE!K+D5PدcSu0$!}aB#|9蟪
\ No newline at end of file
Binary files 0.11.1+ds-4/test/reference/4-padded/ATVYQRCAGSDKMFQ63FDQ4C7IJMUAX2VCXW3EGCMT and 0.13.1+ds-1/test/reference/4-padded/ATVYQRCAGSDKMFQ63FDQ4C7IJMUAX2VCXW3EGCMT differ
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.argon2id.KEYFILE2.json 0.13.1+ds-1/test/reference/4-padded/.securefs.argon2id.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.argon2id.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.argon2id.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "08e8814e19be2463679fc616de088c6332e595f49d850d3b91c0c7f1d16feda4",
+		"MAC" : "5146b810ffff0ac9deb0c89d2b9cf560",
+		"key" : "a25b7258588a2bfc8e8e719b35988bccd4a860013f8f06c400d8162e879fa26a7a228b2e51c88de411b9f34804e93e68b2e8c4de7057d23bc7c561a6000afca66fb153819fa1cbb93d073408ff83ded119196e197888b93a80daa5057a42f04e14fdb401e6842b0256955ae185f3975ca593458245090bc627a36261bdbd4d88"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "bca355efea9d006888fa909cdb4056e5842a192675f188da51babc7b2da49d05",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.argon2id.KEYFILE.json 0.13.1+ds-1/test/reference/4-padded/.securefs.argon2id.KEYFILE.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.argon2id.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.argon2id.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "3f1d9a5f7329e7e3741d4261581a3939f279c3a65b586b2f77173aa535ae1435",
+		"MAC" : "e9a983eb46ab7c136bd5bae4476ad40f",
+		"key" : "086495e4dea3f445006ea43e3a9d51d2a4a5b1915b380c7fbf8d0979896800fd7163418becb09dfb068b9cdd3a042ed51655e317ed83aad47432676482fefe4fe4d283c5159524c2e9d34bb517996a0218c85dc9f272de00bb613e86431e1ccf6bcb94438b86d31039f051efb9820776a35276fa5d39915f46be87af39201dc1"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "a24dcc700c100a80f5d1d9e600e3c29f5307ceec8b328d992fd8877758495f7a",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.argon2id.PASSWORD.json 0.13.1+ds-1/test/reference/4-padded/.securefs.argon2id.PASSWORD.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.argon2id.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.argon2id.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "b6b7fcfce9b858875157c17af84b1d1ffbab16574eaeb743d3b6bbd839849d1c",
+		"MAC" : "b65a6928bdb858795e36ecba6c494735",
+		"key" : "dd6c65072a8e14e25037c690ccaaeff83f27c2be60b7e47d0a82dabd2e013beeec1cc27bd72f9185d4fa0d3c2afc9beb892d8e436ef677a5c1db01e72903fd99950e0a00e002b4ef4b198ed3bd05a72e19ececcd334692c61926aa8506a9d46726533e350692d03f4dfc30cdda002839adb4d0536b1130359e10c31269a66e62"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "97f1d562e92e9ee4fb5216d84a165c0e2d28158ad1b21c4f75ff1f465d77c8ea",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/4-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "2415f81251e704f410975fb067ae523e42ef454422aa76cd70cb898805dbc593",
+		"MAC" : "1c782b87e5e8dbaf3caa34205f152612",
+		"key" : "b0c66e5f21f5fe6b1200452c2d7eb5b5be40a31c308464a40e0a1368df504ea8869052787c272106d5c9629aec43a59bc517b7d06bf7d549241240430750e20a983e4ff222f12f6beb96851df4e58768eda7e2aa1cf8db0406ee934fa071122ccda60dbbf4f718ef8baccbbdeb7a5f9f22eed4cdb34e1a0ba3998525e811ef26"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "e57901d5201a819d1aab041c06094b57c6eda5cad921dfb52b149cef49fe14a0",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/4-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.argon2id.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"argon2_m_cost" : 16,
+	"argon2_p" : 2,
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "514382cc9f8324bb41e73c0998a7bfbed174c7841441718bc03bb409dd5845b3",
+		"MAC" : "6dde875c4d3bfc9534778d0bd21c11ad",
+		"key" : "0c150c9fd1a942f65e8cf132255780685b47a3c9f06adcee9d856fa2ff467cf8656e482f7c57b885e7f312ac2a44607a36dbcc631d45c0b43e0c52128569ddcacb6aee46c2507d32c280f33d702523bf25727ad04275ace71f8ef808571eef6324e81841e35fbec3bcb6ed47437528d2d4e7ee2508b06f8dd38f7e98a16845e0"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "argon2id",
+	"salt" : "3fec0345b0afa2d359cb8a0721d7e0b79b08142536f3051f345d8157c598d97f",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json 0.13.1+ds-1/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "1764d7b891cebc8279ff36fca29b440b2b8d5d9399ceb48b27a2d61ec95da084",
+		"MAC" : "84e186d93d2c55eab52d6c446aad9c8d",
+		"key" : "d4f712290f58afa6900dcb1ee394e74ac007d11f9b04adc176a71a942a3d568105de1cef984d50c86bff99c92009ed6938e5f49bc7f3c82c8aaa08b938fef91876714fab81c43a959bfad8fb26e00d24e439c1af37380dd3d32761f2e3ef59798317c123aced2880be777427d8ba1597fba3dfb38fe1019afd0e9d05b74a9bf5"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "7e6d79bf3624b16e5e424363150bd6f136a57bffbeda1bd7d9a35a2fa70b03bd",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json 0.13.1+ds-1/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "ec74b517eea06bf5fc04931d97f00fcd8291cd2dbff88aa084068bb421221541",
+		"MAC" : "bab72e7630dff5958e599906702c1ee9",
+		"key" : "fc863397367ac767638cb21dd10f26b6efe6deb3a5514ab385919d812a410171b7859b87e35b3771b56f1466af95ff8b3385d2ac6bc55c340f6fbf6e0725e87da5c1d212252fc0d384bd3398e7042bdf3be0635800f0cf80da80fd9457fcfdd3aef968f8fa0080f84e7f12528c6e7e849e25c4b1f279fb9d52b7d08c1a8920f4"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "95c8fd68e458e14e0681bb52d93a8c2a8592d2ae4b2d562ba2d0da7eb58362c1",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json 0.13.1+ds-1/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "15ea087865bbf33723eee5881e5e4e776f93460c1175b2e2afb9c2b49959e8df",
+		"MAC" : "155027f98d83773f5916ef193199d96c",
+		"key" : "7c659c08364434237db4599ffc477e08969035855326e1b864c37fa8f580cb258607c4ecc4378e61d6dfb8b8b3f80062084213a64986fe45fdfcde8a8bae0739fdb974f252b5c0a523dd979b40eb7e8b27622ee78d70af4b1a2e63d8701b1495af821a76f9dc059796309390b55d1d01db5098b2d2ed482a519d68df94b0ed0f"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "dacfccd217b4fd77203790e718a13c7f0be93b6606087947a6ebbc10d4f35cb7",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "44cb60da2d587b6925065314bac7b07a7d82ad9439b2223cd0aa0daca1cbc550",
+		"MAC" : "bda75ca733652f27d4afb50ce566f1b8",
+		"key" : "3d45ffd063580121a1fd4a95b81afbe8ec4d8aebd5da8514a457b1d90275ece28aac29364bbcf38138a5355f8506c673f4694d830364fc7e0fd2465c05f81cd40d7783c9961c35981453eafab27c4617756a4e3286d709629415296c7d24d6a78d0ce779b7f28da8ab96dc94f52da7307718e92ae73d89ed236489f7a184533e"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "8a74ac0c052e19c561847f3f75743855401a178bc1aebdd000ed1e190e4b12be",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.pkcs5-pbkdf2-hmac-sha256.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,15 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "8674023c1819cd0a6b1a414381edbc899d61fb7273b273ed7133d88119b1589f",
+		"MAC" : "4475223df1a0df1e817c9ec5225eb40b",
+		"key" : "d5c20e2f098a148325786aa8c533b210abe8e63489d70e93ee88209413c3864a9d47fefd94fa93979628761bfb24e8db20a00385d44e5cf5db3aeaf33d91f3497b5bec02ef3e0b160edd7b655714a42b3573d82403048986245c2d00632e19953dc6420a3a69b762b3aa5396fd03ba8da3fb5d010f8a59b85f31201b9a529442"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "pkcs5-pbkdf2-hmac-sha256",
+	"salt" : "c277eba81b4b3c7ac5e267ad7a52fc3646037ebc84b29d7927110411d956f435",
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.scrypt.KEYFILE2.json 0.13.1+ds-1/test/reference/4-padded/.securefs.scrypt.KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.scrypt.KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.scrypt.KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "7da2c54d86258a295bb7b63eb7f68bcab0b9fe160fc271a628a3333deb9fe8fd",
+		"MAC" : "94dd710762881fd90dc4900977429f7d",
+		"key" : "e11c5dc7a467273d43d0d08f1b7ba88614a5c04c7f1fdc56ecf9688968b4b4e62a248bfbcbfe2b8e4cd760c9818c41c4610e3f82173b5388372a6d6b87e1100a7cab27b7e73382060a486ed4126d025708456e8abbdf046efd107b948c3ebe84dcefdd89fc04464d0e1b07a7bf0fd9b0c0157e3b08019fdeb5796cf28d7c1afa"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "a8c7420216143bba44d89f793c9a045f8aeae6912cedebffd595417312306ead",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.scrypt.KEYFILE.json 0.13.1+ds-1/test/reference/4-padded/.securefs.scrypt.KEYFILE.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.scrypt.KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.scrypt.KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "beca4343a57b99bfeeff0a9c992825d31c6054e06b837d22c660e71fb433f88e",
+		"MAC" : "52c39a1da4f5df0d01327ad570000cdd",
+		"key" : "86ad29e376b3ffcabf4c460f6aed39e81b467a7c1ee067ce650024b80859294e7bcdbab5d583dc36730af21eed975be4906e971ff436e1b4def00554de84e50620fc2d1523392f58329007526ee4d15925662b718369abcfd9234337a99036a8d136f4b06ed81b9da6d351e32134331d4ad9c74e0a3e8752e932183b0ecddf60"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "124b499b0a9f18d09e26ad408ac018dca1da01b0a2bfb9b61d308dd3efa7915e",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.scrypt.PASSWORD.json 0.13.1+ds-1/test/reference/4-padded/.securefs.scrypt.PASSWORD.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.scrypt.PASSWORD.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.scrypt.PASSWORD.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "098321825007f84c661ea1513a5ce57e760459207748f8f37642ecbcf37cb082",
+		"MAC" : "755382aedd6a171bb0529c90b76f9b64",
+		"key" : "795fb054bf882d3b6853aa0760c41f9bf94a41f23f7296c642135c62e8b5525aa77079fcccf71f9e3953879755c47a7cac0ddd975da6a632fb4763c6bb6cac75ea225a10301b38dc7cb54c3d7dcc7141492f970ea688e9c05b3cd2706d39eb07e1c641c5c4808dbe363a465b8d1bc7783f6b0920df47ccf697b1968214d1feed"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "d79a6ebb84d675ae353f149b0ede87a75e2fd1df805a2ef6cf670b1c21e92a48",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json 0.13.1+ds-1/test/reference/4-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE2.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "6b36721b5163eb5a423ea29213b7b4ee0863e9ae9dd27b1d06cf2cccba7b9fcf",
+		"MAC" : "c77ac40f9fdec19177404b588d90a9c1",
+		"key" : "890896fe9dbf3c07fb0808cf61f9e3a5be000406b0d90cd8807c9ca05fd22746a8fce207a0be00df86786ba9ce3f71841de3bd50b0f8fc37c65502e9a4f2acf8f3c1e5ec2e8ba1ac36a41503c2503eb6e7d3f16fb13bace448f598a79089e234b66c408491a1d538e7009264948efe97183ebe7d2bc9b00b747c67b8f6599a64"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "1144b5fba73081e602f9840b972d36d04b324a19cccd6422c3eaeac7c82cc6b7",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 4
+}
diff -pruN 0.11.1+ds-4/test/reference/4-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json 0.13.1+ds-1/test/reference/4-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json
--- 0.11.1+ds-4/test/reference/4-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/4-padded/.securefs.scrypt.PASSWORD_WITH_KEYFILE.json	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,17 @@
+{
+	"block_size" : 4096,
+	"encrypted_key" : 
+	{
+		"IV" : "e944916006377ef435b9ca65fcd895e6575ad0f997c03743bda2d6e4a472f0b8",
+		"MAC" : "4627be2d684a013c37bcf5569f948b1b",
+		"key" : "133ab04ef40aacd8936dee0d4e02859ad3b2ceff7a5aab41f54e9e00a5ba6ca3de047f287f2320e75ce3277d58a7d9c1d8d081fb4a0525b944a7ceb087b8c6715846c203fb314080d63c6da832fb5fb95bb13c68d43a92f2261699b08359f268ae5940fd521bf174057e7836086472e356fa240ec958a797c6ca6ee2a25c1b3d"
+	},
+	"iterations" : 2,
+	"iv_size" : 12,
+	"max_padding" : 256,
+	"pbkdf" : "scrypt",
+	"salt" : "df66bb5deebf6f1366da963b0d2d6a5c80766e9eceecfd8823fe169c6fc53cff",
+	"scrypt_p" : 1,
+	"scrypt_r" : 8,
+	"version" : 4
+}
Binary files 0.11.1+ds-4/test/reference/4-padded/TVGIFJBPT7XCDRQJQ77RGAA5UHYWWUGKY7KAFRU7NDWYVFYTSB8XYNKTQYAS/EJAG7CFH2JAY5RG6FV6UK8EVPUYHKRGDKPN9WCA and 0.13.1+ds-1/test/reference/4-padded/TVGIFJBPT7XCDRQJQ77RGAA5UHYWWUGKY7KAFRU7NDWYVFYTSB8XYNKTQYAS/EJAG7CFH2JAY5RG6FV6UK8EVPUYHKRGDKPN9WCA differ
Binary files 0.11.1+ds-4/test/reference/4-padded/U689DZRBFXB7VM8G7CTAFGQT8M6HSAPI3JWA/7CZ36XY8S6KW3WDW99NX8TEXEHGC3TVWKPV4A and 0.13.1+ds-1/test/reference/4-padded/U689DZRBFXB7VM8G7CTAFGQT8M6HSAPI3JWA/7CZ36XY8S6KW3WDW99NX8TEXEHGC3TVWKPV4A differ
Binary files 0.11.1+ds-4/test/reference/4-padded/U689DZRBFXB7VM8G7CTAFGQT8M6HSAPI3JWA/R9ZJ5VUMXZKRRF76PTVDQJV683N5JTEUPG9Z35FMHQHDQ476VYSAI5K6ZG8MY3SRXYPA/DKWEQYEIVYC73W9M4Y5BU33453NZZR3IQHXWSHS and 0.13.1+ds-1/test/reference/4-padded/U689DZRBFXB7VM8G7CTAFGQT8M6HSAPI3JWA/R9ZJ5VUMXZKRRF76PTVDQJV683N5JTEUPG9Z35FMHQHDQ476VYSAI5K6ZG8MY3SRXYPA/DKWEQYEIVYC73W9M4Y5BU33453NZZR3IQHXWSHS differ
diff -pruN 0.11.1+ds-4/test/reference/chpass_all.py 0.13.1+ds-1/test/reference/chpass_all.py
--- 0.11.1+ds-4/test/reference/chpass_all.py	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/reference/chpass_all.py	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+
+"""
+A binary file to create all variations of .securefs.json by calling `chpass`.
+"""
+
+import enum
+import os
+import subprocess
+import shutil
+import sys
+import glob
+
+
+@enum.unique
+class SecretInputMode(enum.IntEnum):
+    PASSWORD = 0b1
+    KEYFILE = 0b10
+    PASSWORD_WITH_KEYFILE = PASSWORD | KEYFILE
+    KEYFILE2 = KEYFILE | 0b1000
+    PASSWORD_WITH_KEYFILE2 = PASSWORD | KEYFILE2
+
+
+def create(
+    securefs_binary: str, version: int, pbkdf: str, mode: SecretInputMode, padded: bool
+):
+    if padded:
+        data_dir = f"{version}-padded"
+    else:
+        data_dir = str(version)
+    new_config_filename = os.path.join(data_dir, f".securefs.{pbkdf}.{mode.name}.json")
+    if os.path.exists(new_config_filename):
+        print(new_config_filename, "already exists", file=sys.stderr)
+        return
+    original_config_filename = next(
+        glob.iglob(os.path.join(data_dir, ".securefs.*.PASSWORD.json"))
+    )
+    shutil.copy(original_config_filename, new_config_filename)
+    args = [
+        securefs_binary,
+        "chpass",
+        "--oldpass",
+        "abc",
+        "--pbkdf",
+        pbkdf,
+        "--config",
+        new_config_filename,
+        "-r",
+        "2",
+    ]
+    if mode & SecretInputMode.KEYFILE:
+        args.extend(["--newkeyfile", "keyfile"])
+    if mode & SecretInputMode.PASSWORD:
+        args.extend(["--newpass", "abc"])
+    args.append(f"{version}")
+    subprocess.check_call(args)
+
+
+def main():
+    os.environ["SECUREFS_ARGON2_M_COST"] = "16"
+    os.environ["SECUREFS_ARGON2_P"] = "2"
+    binary = os.path.realpath(sys.argv[1])
+    os.chdir(os.path.dirname(__file__))
+    for version in range(1, 5):
+        for pbkdf in ("scrypt", "pkcs5-pbkdf2-hmac-sha256", "argon2id"):
+            for mode in SecretInputMode:
+                for padded in [False, True]:
+                    create(
+                        binary, version=version, pbkdf=pbkdf, mode=mode, padded=padded
+                    )
+
+
+if __name__ == "__main__":
+    main()
diff -pruN 0.11.1+ds-4/test/simple_test.py 0.13.1+ds-1/test/simple_test.py
--- 0.11.1+ds-4/test/simple_test.py	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/simple_test.py	2023-01-27 02:25:50.000000000 +0000
@@ -6,7 +6,7 @@ import faulthandler
 import itertools
 import logging
 import os
-import platform
+import inspect
 import shutil
 import signal
 import stat
@@ -17,24 +17,23 @@ import time
 import traceback
 import unittest
 import uuid
+from typing import List, Optional, Sequence
 from typing import Set
+import enum
+import multiprocessing
+import random
+import secrets
+import io
+from collections import namedtuple
 
 faulthandler.enable()
 
 
-def find_securefs_binary():
-    for dir_path, _, files in os.walk("."):
-        for fn in files:
-            if fn == "securefs" or fn == "securefs.exe":
-                return os.path.join(dir_path, fn)
-    raise RuntimeError("securefs binary not found")
+SECUREFS_BINARY = os.environ["SECUREFS_BINARY"]
+if not os.path.isfile(SECUREFS_BINARY):
+    raise ValueError(f"{repr(SECUREFS_BINARY)} is not a file!")
 
-
-SECUREFS_BINARY = find_securefs_binary()
-
-IS_WINDOWS = os.name == "nt"
-
-if platform.system() == "Darwin":
+if sys.platform == "darwin":
     try:
         import xattr
     except ImportError:
@@ -46,20 +45,28 @@ else:
     xattr = None
 
 
-if IS_WINDOWS:
+if sys.platform == "win32":
 
     def ismount(path):
         # Not all reparse points are mounts, but in our test, that is close enough
         attribute = ctypes.windll.kernel32.GetFileAttributesW(path.rstrip("/\\"))
         return attribute != -1 and (attribute & 0x400) == 0x400
 
+    def statvfs(path):
+        if not ctypes.windll.kernel32.GetDiskFreeSpaceExW(path, None, None, None):
+            raise ctypes.WinError()
 
 else:
     ismount = os.path.ismount
+    statvfs = os.statvfs
 
 
 def securefs_mount(
-    data_dir: str, mount_point: str, password: str, keyfile: str = None
+    data_dir: str,
+    mount_point: str,
+    password: Optional[str],
+    keyfile: Optional[str] = None,
+    config_filename: Optional[str] = None,
 ) -> subprocess.Popen:
     command = [
         SECUREFS_BINARY,
@@ -75,39 +82,58 @@ def securefs_mount(
     if keyfile:
         command.append("--keyfile")
         command.append(keyfile)
+    if config_filename:
+        command.append("--config")
+        command.append(config_filename)
     logging.info("Start mounting, command:\n%s", " ".join(command))
     p = subprocess.Popen(
-        command, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if IS_WINDOWS else 0
+        command,
+        creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
+        if sys.platform == "win32"
+        else 0,
     )
-
-    for _ in range(300):
-        time.sleep(0.05)
-        try:
-            if ismount(mount_point):
-                return p
-        except EnvironmentError:
-            traceback.print_exc()
-    raise RuntimeError(f"Failed to mount, command {command}")
+    try:
+        for _ in range(300):
+            try:
+                if ismount(mount_point):
+                    statvfs(mount_point)
+                    if sys.platform == "darwin":
+                        time.sleep(0.01)
+                    return p
+            except EnvironmentError:
+                traceback.print_exc()
+            time.sleep(0.005)
+        raise TimeoutError(f"Failed to mount {repr(mount_point)} after many attempts")
+    except:
+        p.communicate(timeout=0.1)
+        p.kill()
+        raise
 
 
 def securefs_unmount(p: subprocess.Popen, mount_point: str):
-    try:
-        if IS_WINDOWS:
+    statvfs(mount_point)
+    with p:
+        if sys.platform == "win32":
             p.send_signal(signal.CTRL_BREAK_EVENT)
+        elif sys.platform == "linux":
+            subprocess.check_call(["fusermount", "-u", mount_point])
         else:
-            p.send_signal(signal.SIGINT)
-        p.communicate(timeout=5)
+            subprocess.check_call(["umount", mount_point])
+        p.wait(timeout=5)
         if p.returncode:
-            raise RuntimeError(f"securefs failed with code {p.returncode}")
+            logging.warn("securefs exited with non-zero code: %d", p.returncode)
         if ismount(mount_point):
             raise RuntimeError(f"{mount_point} still mounted")
-    except:
-        if ismount(mount_point):
-            raise  # Still mounted
-        traceback.print_exc()
 
 
-def securefs_create(data_dir, password, version, keyfile=None):
+def securefs_create(
+    data_dir: str,
+    version: int,
+    pbkdf: str,
+    password: Optional[str],
+    keyfile: Optional[str] = None,
+    max_padding: int = 0,
+):
     command = [
         SECUREFS_BINARY,
         "create",
@@ -116,6 +142,10 @@ def securefs_create(data_dir, password,
         data_dir,
         "--rounds",
         "2",
+        "--pbkdf",
+        pbkdf,
+        "--max-padding",
+        str(max_padding),
     ]
     if password:
         command.append("--pass")
@@ -123,27 +153,37 @@ def securefs_create(data_dir, password,
     if keyfile:
         command.append("--keyfile")
         command.append(keyfile)
-    p = subprocess.Popen(command)
-    p.communicate(timeout=5)
+    logging.info("Creating securefs repo with command %s", command)
+    subprocess.check_call(command)
 
 
 def securefs_chpass(
     data_dir,
-    old_pass: str = None,
-    new_pass: str = None,
-    old_keyfile: str = None,
-    new_keyfile: str = None,
+    pbkdf: str,
+    old_pass: Optional[str] = None,
+    new_pass: Optional[str] = None,
+    old_keyfile: Optional[str] = None,
+    new_keyfile: Optional[str] = None,
+    use_stdin: bool = True,
 ):
     if not old_pass and not old_keyfile:
         raise ValueError("At least one of old_pass and old_keyfile must be specified")
     if not new_pass and not new_keyfile:
         raise ValueError("At least one of new_pass and new_keyfile must be specified")
 
-    args = [SECUREFS_BINARY, "chpass", data_dir, "--rounds", "2"]
+    args = [SECUREFS_BINARY, "chpass", data_dir, "--rounds", "2", "--pbkdf", pbkdf]
     if old_pass:
-        args.append("--askoldpass")
+        if use_stdin:
+            args.append("--askoldpass")
+        else:
+            args.append("--oldpass")
+            args.append(old_pass)
     if new_pass:
-        args.append("--asknewpass")
+        if use_stdin:
+            args.append("--asknewpass")
+        else:
+            args.append("--newpass")
+            args.append(new_pass)
     if old_keyfile:
         args.append("--oldkeyfile")
         args.append(old_keyfile)
@@ -151,20 +191,22 @@ def securefs_chpass(
         args.append("--newkeyfile")
         args.append(new_keyfile)
     logging.info("Executing command: %s", args)
-    p = subprocess.Popen(
+    with subprocess.Popen(
         args,
         stdin=subprocess.PIPE,
         stdout=subprocess.PIPE,
         stderr=subprocess.PIPE,
         universal_newlines=True,
-    )
-    input = ""
-    if old_pass:
-        input += old_pass + "\n"
-    if new_pass:
-        input += (new_pass + "\n") * 2
-    out, err = p.communicate(input=input, timeout=3)
-    logging.info("chpass output:\n%s\n%s", out, err)
+    ) as p:
+        input = ""
+        if use_stdin:
+            if old_pass:
+                input += old_pass + "\n"
+            if new_pass:
+                input += (new_pass + "\n") * 2
+        out, err = p.communicate(input=input, timeout=3)
+        if p.returncode:
+            raise subprocess.CalledProcessError(p.returncode, args, out, err)
 
 
 def get_data_dir(format_version=4):
@@ -179,19 +221,78 @@ def get_mount_point():
     return result
 
 
-def make_test_case(format_version):
+@enum.unique
+class SecretInputMode(enum.IntEnum):
+    PASSWORD = 0b1
+    KEYFILE = 0b10
+    PASSWORD_WITH_KEYFILE = PASSWORD | KEYFILE
+    KEYFILE2 = KEYFILE | 0b1000
+    PASSWORD_WITH_KEYFILE2 = PASSWORD | KEYFILE2
+
+
+def parametrize(possible_args: Sequence[Sequence]):
+    def real_parametrize(func):
+        sig = inspect.signature(func)
+        for l in possible_args:
+            if len(l) != len(sig.parameters):
+                raise ValueError(
+                    "The possible arguments list does not match the parameters"
+                )
+        for l in possible_args:
+            cls = func(*l)
+            if cls is None:
+                continue
+            assert isinstance(cls, type)
+            kwargs = {}
+            for l, p in zip(l, sig.parameters.keys()):
+                kwargs[p] = l
+            cls_name = cls.__name__ + repr(kwargs)
+            globals()[cls_name] = type(cls_name, (cls,), {})  # type: ignore
+        return func
+
+    return real_parametrize
+
+
+ALL_PBKDFS = ("scrypt", "pkcs5-pbkdf2-hmac-sha256", "argon2id")
+
+
+@parametrize(
+    tuple(
+        itertools.product(
+            range(1, 5),
+            ALL_PBKDFS,
+            [
+                SecretInputMode.PASSWORD,
+                SecretInputMode.KEYFILE2,
+                SecretInputMode.PASSWORD_WITH_KEYFILE2,
+            ],
+            [0, 15],
+        )
+    )
+)
+def make_test_case(version: int, pbkdf: str, mode: SecretInputMode, max_padding: int):
     class SimpleSecureFSTestBase(unittest.TestCase):
+        data_dir: str
+        password: Optional[str]
+        keyfile: Optional[str]
+        mount_point: str
+        securefs_process: Optional[subprocess.Popen]
+
         @classmethod
         def setUpClass(cls):
-            try:
-                os.mkdir("tmp")
-            except EnvironmentError as e:
-                if e.errno != errno.EEXIST:
-                    raise
-            cls.data_dir = get_data_dir(format_version=format_version)
+            os.makedirs("tmp", exist_ok=True)
+            cls.data_dir = get_data_dir(format_version=version)
             cls.mount_point = get_mount_point()
-            cls.password = "pvj8lRgrrsqzlr"
-            securefs_create(cls.data_dir, cls.password, format_version)
+            cls.password = "pvj8lRgrrsqzlr" if mode & SecretInputMode.PASSWORD else None
+            cls.keyfile = generate_keyfile() if mode & SecretInputMode.KEYFILE else None
+            securefs_create(
+                data_dir=cls.data_dir,
+                password=cls.password,
+                version=version,
+                keyfile=cls.keyfile,
+                pbkdf=pbkdf,
+                max_padding=max_padding,
+            )
             cls.mount()
 
         @classmethod
@@ -201,7 +302,10 @@ def make_test_case(format_version):
         @classmethod
         def mount(cls):
             cls.securefs_process = securefs_mount(
-                cls.data_dir, cls.mount_point, cls.password
+                cls.data_dir,
+                cls.mount_point,
+                password=cls.password,
+                keyfile=cls.keyfile,
             )
 
         @classmethod
@@ -215,10 +319,10 @@ def make_test_case(format_version):
             with self.assertRaises(EnvironmentError) as context:
                 os.mkdir(os.path.join(self.mount_point, "k" * 256))
                 self.fail("mkdir should fail")
-            if not IS_WINDOWS:
+            if sys.platform != "win32":
                 self.assertEqual(context.exception.errno, errno.ENAMETOOLONG)
 
-        if xattr:
+        if xattr is not None:
 
             def test_xattr(self):
                 fn = os.path.join(self.mount_point, str(uuid.uuid4()))
@@ -226,11 +330,11 @@ def make_test_case(format_version):
                     with open(fn, "wt") as f:
                         f.write("hello\n")
                     x = xattr.xattr(fn)
-                    x.set("abc", "def")
-                    x.set("123", "456")
+                    x.set("abc", b"def")
+                    x.set("123", b"456")
                     self.unmount()
                     self.mount()
-                    self.assertEqual(x.get("abc"), "def")
+                    self.assertEqual(x.get("abc"), b"def")
                     self.assertEqual(set(x.list()), {"abc", "123"})
                     xattr.removexattr(fn, "abc")
                     self.assertEqual(set(x.list()), {"123"})
@@ -240,7 +344,7 @@ def make_test_case(format_version):
                     except EnvironmentError:
                         pass
 
-        if format_version < 4 and not IS_WINDOWS:
+        if version < 4 and sys.platform != "win32":
 
             def test_hardlink(self):
                 data = os.urandom(16)
@@ -271,7 +375,7 @@ def make_test_case(format_version):
                     except EnvironmentError:
                         pass
 
-        if not IS_WINDOWS:
+        if sys.platform != "win32":
 
             def test_symlink(self):
                 data = os.urandom(16)
@@ -296,6 +400,14 @@ def make_test_case(format_version):
                     except EnvironmentError:
                         pass
 
+        else:
+
+            def test_win_long_path(self):
+                long_mount_point = rf"\\?\{os.path.abspath(self.mount_point)}"
+                long_dir = os.path.join(long_mount_point, *(["🐋🐳" * 10] * 40))
+                os.makedirs(long_dir)
+                shutil.rmtree(os.path.join(long_mount_point, "🐋🐳" * 10))
+
         def test_rename(self):
             data = os.urandom(32)
             source = os.path.join(self.mount_point, str(uuid.uuid4()))
@@ -353,8 +465,16 @@ def make_test_case(format_version):
             self.unmount()
 
             self.mount()
+            st = os.lstat(rng_filename)
+            self.assertEqual(st.st_size, len(random_data))
+            self.assertEqual(stat.S_IFMT(st.st_mode), stat.S_IFREG)
+
             with open(rng_filename, "rb") as f:
                 self.assertEqual(f.read(), random_data)
+                fst = os.fstat(f.fileno())
+                self.assertEqual(st.st_ino, fst.st_ino)
+                self.assertEqual(st.st_size, fst.st_size)
+
             data = b"\0" * len(random_data) + b"0"
             with open(rng_filename, "wb") as f:
                 f.write(data)
@@ -363,6 +483,8 @@ def make_test_case(format_version):
             os.remove(rng_filename)
             for n in dir_names:
                 os.mkdir(os.path.join(self.mount_point, n))
+                st = os.lstat(os.path.join(self.mount_point, n))
+                self.assertEqual(stat.S_IFMT(st.st_mode), stat.S_IFDIR)
             for n in dir_names:
                 os.mkdir(os.path.join(self.mount_point, "0", n))
             for n in dir_names:
@@ -383,7 +505,7 @@ def make_test_case(format_version):
                 except EnvironmentError:
                     pass
 
-        if format_version == 3:
+        if version == 3:
 
             def test_time(self):
                 rand_dirname = os.path.join(self.mount_point, str(uuid.uuid4()))
@@ -407,84 +529,70 @@ def make_test_case(format_version):
     return SimpleSecureFSTestBase
 
 
-class TestVersion1(make_test_case(1)):
-    pass
-
-
-class TestVersion2(make_test_case(2)):
-    pass
-
-
-class TestVersion3(make_test_case(3)):
-    pass
-
-
-class TestVersion4(make_test_case(4)):
-    pass
-
-
-class RegressionTest(unittest.TestCase):
-    """
-    Ensures that future versions of securefs can read old versions just fine.
-    """
-
-    def test_all(self):
-        # Because securefs cannot handle readonly filesystem for now, we need to copy
-        # all the reference data to the working dir.
-        reference_data_dir = shutil.copytree(
-            os.path.join(os.path.dirname(os.path.abspath(__file__)), "reference"),
-            f"tmp/{uuid.uuid4()}",
-        )
-        for i in [1, 2, 3, 4]:
-            self._run_test(
-                version=i, use_keyfile=False, reference_data_dir=reference_data_dir
+reference_data_dir = shutil.copytree(
+    os.path.join(os.path.dirname(os.path.abspath(__file__)), "reference"),
+    f"tmp/{uuid.uuid4()}",
+)
+
+
+@parametrize(
+    tuple(itertools.product(range(1, 5), ALL_PBKDFS, SecretInputMode, [False, True]))
+)
+def make_regression_test(version: int, pbkdf: str, mode: SecretInputMode, padded: bool):
+    class RegressionTestBase(unittest.TestCase):
+        """
+        Ensures that future versions of securefs can read old versions just fine.
+        """
+
+        def test_regression(self):
+            mount_point = get_mount_point()
+            if padded:
+                data_dir = f"{version}-padded"
+            else:
+                data_dir = str(version)
+            config_filename = os.path.join(
+                reference_data_dir, data_dir, f".securefs.{pbkdf}.{mode.name}.json"
             )
-            self._run_test(
-                version=i, use_keyfile=True, reference_data_dir=reference_data_dir
-            )
-
-    def _run_test(self, version: int, use_keyfile: bool, reference_data_dir: str):
-        mount_point = get_mount_point()
-        if use_keyfile:
             p = securefs_mount(
-                os.path.join(reference_data_dir, f"{version}-keyfile"),
+                os.path.join(reference_data_dir, data_dir),
                 mount_point,
-                password=None,
-                keyfile=os.path.join(reference_data_dir, "keyfile"),
+                password="abc" if mode & SecretInputMode.PASSWORD else None,
+                keyfile=os.path.join(reference_data_dir, "keyfile")
+                if mode & SecretInputMode.KEYFILE
+                else None,
+                config_filename=config_filename,
             )
-        else:
-            p = securefs_mount(
-                os.path.join(reference_data_dir, str(version)),
-                mount_point,
-                password="abc",
-            )
-        try:
-            self.compare_directory(
-                os.path.join(reference_data_dir, "plain"), mount_point
-            )
-        finally:
-            securefs_unmount(p, mount_point)
+            try:
+                self.compare_directory(
+                    os.path.join(reference_data_dir, "plain"), mount_point
+                )
+            finally:
+                securefs_unmount(p, mount_point)
 
-    def compare_directory(self, dir1, dir2):
-        listing1 = list_dir_recursive(dir1, relpath=True)
-        listing2 = list_dir_recursive(dir2, relpath=True)
+        def compare_directory(self, dir1, dir2):
+            listing1 = list_dir_recursive(dir1, relpath=True)
+            listing2 = list_dir_recursive(dir2, relpath=True)
 
-        self.assertEqual(
-            listing1, listing2, f"{dir1} and {dir2} differ in file names",
-        )
+            self.assertEqual(
+                listing1,
+                listing2,
+                f"{dir1} and {dir2} differ in file names",
+            )
 
-        for fn in listing1:
-            fn1 = os.path.join(dir1, fn)
-            fn2 = os.path.join(dir2, fn)
+            for fn in listing1:
+                fn1 = os.path.join(dir1, fn)
+                fn2 = os.path.join(dir2, fn)
+
+                if os.path.isdir(fn1) and os.path.isdir(fn2):
+                    continue
+
+                with open(fn1, "rb") as f:
+                    data1 = f.read()
+                with open(fn2, "rb") as f:
+                    data2 = f.read()
+                self.assertEqual(data1, data2, f"{fn1} and {fn2} differ in contents")
 
-            if os.path.isdir(fn1) and os.path.isdir(fn2):
-                continue
-
-            with open(fn1, "rb") as f:
-                data1 = f.read()
-            with open(fn2, "rb") as f:
-                data2 = f.read()
-            self.assertEqual(data1, data2, f"{fn1} and {fn2} differ in contents")
+    return RegressionTestBase
 
 
 def list_dir_recursive(dirname: str, relpath=False) -> Set[str]:
@@ -504,73 +612,202 @@ def list_dir_recursive(dirname: str, rel
     return result
 
 
-class ChpassTest(unittest.TestCase):
-    def _generate_keyfile(self):
-        with tempfile.NamedTemporaryFile(
-            dir="tmp", mode="wb", delete=False, prefix="key"
-        ) as f:
-            f.write(os.urandom(9))
-            return f.name
-
-    def _test_chpass(self, old_pass, new_pass, old_keyfile, new_keyfile):
-        data_dir = get_data_dir()
-        mount_point = get_mount_point()
-        test_dir_path = os.path.join(mount_point, "test")
-
-        logging.info(
-            "Testing chpass on data_dir=%s mount_point=%s old_pass=%s new_pass=%s old_keyfile=%s new_keyfile=%s",
-            data_dir,
-            mount_point,
-            old_pass,
-            new_pass,
-            old_keyfile,
-            new_keyfile,
-        )
+def generate_keyfile():
+    with tempfile.NamedTemporaryFile(
+        dir="tmp", mode="wb", delete=False, prefix="key"
+    ) as f:
+        f.write(os.urandom(9))
+        return f.name
+
+
+@parametrize([[1], [2], [3], [4]])
+def make_size_test(version):
+    """Ensures that padding actually increases the underlying file sizes."""
+
+    class SizeTestBase(unittest.TestCase):
+        def test_size(self):
+            nonpadded_data_dir = os.path.join(reference_data_dir, str(version))
+            padded_data_dir = os.path.join(reference_data_dir, f"{version}-padded")
+            nonpadded_fs = compute_file_statistics(
+                nonpadded_data_dir, exclude_securefs_json=True
+            )
+            padded_fs = compute_file_statistics(
+                padded_data_dir, exclude_securefs_json=True
+            )
+            self.assertEqual(nonpadded_fs.count, padded_fs.count)
+            self.assertGreater(
+                padded_fs.total_size - nonpadded_fs.total_size, padded_fs.count * 32
+            )
 
-        securefs_create(
-            data_dir=data_dir, password=old_pass, version=4, keyfile=old_keyfile
-        )
+    return SizeTestBase
+
+
+FileStatistics = namedtuple("FileStatistics", ("total_size", "count"))
 
-        self.assertFalse(os.path.exists(test_dir_path))
 
-        p = securefs_mount(data_dir, mount_point, old_pass, old_keyfile)
-        try:
-            os.mkdir(test_dir_path)
-        finally:
-            securefs_unmount(p, mount_point)
-
-        self.assertFalse(os.path.exists(test_dir_path))
-
-        securefs_chpass(
-            data_dir,
-            old_pass=old_pass,
-            new_pass=new_pass,
-            old_keyfile=old_keyfile,
-            new_keyfile=new_keyfile,
+def compute_file_statistics(
+    base_dir: str, exclude_securefs_json: bool
+) -> FileStatistics:
+    size = 0
+    count = 0
+    with os.scandir(base_dir) as it:
+        for entry in it:
+            name: str = entry.name
+            if entry.is_dir():
+                fs = compute_file_statistics(
+                    os.path.join(base_dir, name), exclude_securefs_json
+                )
+                size += fs.total_size
+                count += fs.count
+            elif (
+                entry.is_file()
+                and not name.startswith(".securefs")
+                and not name.endswith(".json")
+            ):
+                size += entry.stat().st_size
+                count += 1
+    return FileStatistics(total_size=size, count=count)
+
+
+@parametrize(
+    tuple(
+        itertools.product(
+            [None, "abc"],
+            [None, "abc"],
+            [None, generate_keyfile()],
+            [None, generate_keyfile()],
+            [True, False],
+            range(1, 5),
+            ALL_PBKDFS,
+            [0, 32],
         )
+    )
+)
+def make_chpass_test(
+    old_pass, new_pass, old_keyfile, new_keyfile, use_stdin, version, pbkdf, max_padding
+):
+    if not old_pass and not old_keyfile:
+        return
+    if not new_pass and not new_keyfile:
+        return
 
-        p = securefs_mount(data_dir, mount_point, new_pass, new_keyfile)
-        try:
-            self.assertTrue(os.path.isdir(test_dir_path))
-        finally:
-            securefs_unmount(p, mount_point)
-
-    def test_chpass(self):
-        old_passes = [None, "abc"]
-        new_passes = [None, "def"]
-        old_keyfiles = [None, self._generate_keyfile()]
-        new_keyfiles = [None, self._generate_keyfile()]
-
-        for old_pass, new_pass, old_keyfile, new_keyfile in itertools.product(
-            old_passes, new_passes, old_keyfiles, new_keyfiles
-        ):
-            if not old_pass and not old_keyfile:
-                continue
-            if not new_pass and not new_keyfile:
-                continue
-            self._test_chpass(old_pass, new_pass, old_keyfile, new_keyfile)
+    class ChpassTestBase(unittest.TestCase):
+        def test_chpass(self):
+            data_dir = get_data_dir()
+            mount_point = get_mount_point()
+            test_dir_path = os.path.join(mount_point, "test")
+            test_file_path = os.path.join(mount_point, "aaa")
+
+            securefs_create(
+                data_dir=data_dir,
+                password=old_pass,
+                keyfile=old_keyfile,
+                version=version,
+                pbkdf=pbkdf,
+                max_padding=max_padding,
+            )
+
+            self.assertFalse(os.path.exists(test_dir_path))
+
+            p = securefs_mount(data_dir, mount_point, old_pass, old_keyfile)
+            try:
+                os.mkdir(test_dir_path)
+                with open(test_file_path, "xb") as f:
+                    f.write(b"x" * 10)
+            finally:
+                securefs_unmount(p, mount_point)
+
+            self.assertFalse(os.path.exists(test_dir_path))
+
+            securefs_chpass(
+                data_dir,
+                old_pass=old_pass,
+                new_pass=new_pass,
+                old_keyfile=old_keyfile,
+                new_keyfile=new_keyfile,
+                use_stdin=use_stdin,
+                pbkdf=pbkdf,
+            )
+
+            p = securefs_mount(data_dir, mount_point, new_pass, new_keyfile)
+            try:
+                self.assertTrue(os.path.isdir(test_dir_path))
+                self.assertEqual(os.lstat(test_file_path).st_size, 10)
+                with open(test_file_path, "rb") as f:
+                    self.assertEqual(f.read(), b"x" * 10)
+            finally:
+                securefs_unmount(p, mount_point)
+
+    return ChpassTestBase
+
+
+def randomly_act_on_file(filename: str, barrier) -> None:
+    rng = random.Random(os.urandom(16))
+
+    def run_once(f: io.FileIO):
+        action = rng.randrange(0, 5)
+        if action == 0:
+            f.read(rng.randrange(5000))
+        elif action == 1:
+            f.write(secrets.token_bytes(rng.randrange(1, 5000)))
+        elif action == 2:
+            f.seek(rng.randrange(0, 1 << 20))
+        elif action == 3:
+            os.ftruncate(f.fileno(), rng.randrange(0, 1 << 20))
+            f.seek(0)
+        elif action == 4:
+            os.fsync(f.fileno())
+
+    barrier.wait()
+    for _ in range(3):
+        with open(filename, "r+b", buffering=0) as f:
+            for _ in range(rng.randrange(10, 30)):
+                run_once(f)
+
+
+@parametrize([[2], [4]])
+def make_concurrency_test(version: int):
+    class ConcurrencyTestBase(unittest.TestCase):
+        def test_concurrent_access(self):
+            data_dir = get_data_dir()
+            mount_point = get_mount_point()
+
+            securefs_create(
+                data_dir=data_dir,
+                password="xxxx",
+                version=version,
+                pbkdf=ALL_PBKDFS[-1],
+            )
+            test_filename = os.path.join(mount_point, "a" * 10)
+            p = securefs_mount(data_dir, mount_point, "xxxx")
+            try:
+                with open(test_filename, "xb") as f:
+                    pass
+                count = multiprocessing.cpu_count()
+                barrier = multiprocessing.Barrier(count)
+                processes = [
+                    multiprocessing.Process(
+                        target=randomly_act_on_file, args=(test_filename, barrier)
+                    )
+                    for _ in range(count)
+                ]
+                for proc in processes:
+                    proc.start()
+                for proc in processes:
+                    proc.join()
+                for proc in processes:
+                    if proc.exitcode != 0:
+                        raise ValueError(
+                            "A process that reads/writes test file has failed"
+                        )
+            finally:
+                securefs_unmount(p, mount_point)
+
+    return ConcurrencyTestBase
 
 
 if __name__ == "__main__":
+    os.environ["SECUREFS_ARGON2_M_COST"] = "16"
+    os.environ["SECUREFS_ARGON2_P"] = "2"
     logging.getLogger().setLevel(logging.INFO)
     unittest.main()
diff -pruN 0.11.1+ds-4/test/test_btree.cpp 0.13.1+ds-1/test/test_btree.cpp
--- 0.11.1+ds-4/test/test_btree.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/test_btree.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -1,6 +1,7 @@
 #include "btree_dir.h"
 #include "crypto.h"
 #include "myutils.h"
+#include "test_common.h"
 
 #include <catch.hpp>
 
@@ -19,26 +20,28 @@ static void test(securefs::BtreeDirector
                  double prob_get,
                  double prob_add,
                  double prob_del,
-                 unsigned sequence)
+                 unsigned sequence) THREAD_ANNOTATION_REQUIRES(dir)
+    THREAD_ANNOTATION_REQUIRES(reference)
 {
     (void)sequence;    // May be used later
     bool is_prob_valid = (prob_get >= 0 && prob_add >= 0 && prob_del >= 0
                           && prob_get + prob_add + prob_del <= 1.0);
     REQUIRE(is_prob_valid);
 
-    std::mt19937 engine{std::random_device{}()};
     std::uniform_real_distribution<> prob_dist(0, 1);
     std::uniform_int_distribution<int> name_dist(0, 65535);
     std::vector<std::string> filenames, filenames_prime;
 
     securefs::Directory::callback inserter
-        = [&](const std::string& name, const securefs::id_type&, int) -> bool {
+        = [&](const std::string& name, const securefs::id_type&, int) -> bool
+    {
         filenames.push_back(name);
         return true;
     };
 
     securefs::Directory::callback inserter_prime
-        = [&](const std::string& name, const securefs::id_type&, int) -> bool {
+        = [&](const std::string& name, const securefs::id_type&, int) -> bool
+    {
         filenames_prime.push_back(name);
         return true;
     };
@@ -55,7 +58,7 @@ static void test(securefs::BtreeDirector
     int type, type_prime;
     for (unsigned i = 0; i < rounds; ++i)
     {
-        auto p = prob_dist(engine);
+        auto p = prob_dist(get_random_number_engine());
         if (p < prob_get)
         {
             filenames.clear();
@@ -72,7 +75,7 @@ static void test(securefs::BtreeDirector
         }
         else if (p < prob_get + prob_add)
         {
-            auto name = securefs::strprintf("%12d", name_dist(engine));
+            auto name = securefs::strprintf("%12d", name_dist(get_random_number_engine()));
             securefs::generate_random(id.data(), id.size());
             type = S_IFREG;
             bool added = dir.add_entry(name, id, type);
@@ -85,7 +88,7 @@ static void test(securefs::BtreeDirector
             if (filenames.empty())
                 continue;
             std::uniform_int_distribution<size_t> index_dist(0, filenames.size() - 1);
-            size_t idx = index_dist(engine);
+            size_t idx = index_dist(get_random_number_engine());
             bool removed = dir.remove_entry(filenames[idx], id, type);
             bool removed_prime = reference.remove_entry(filenames[idx], id_prime, type_prime);
             REQUIRE(removed == removed_prime);
@@ -99,12 +102,10 @@ static void test(securefs::BtreeDirector
     }
 }
 
-TEST_CASE("Test BtreeDirectory")
+static void test_btree_dir(unsigned max_padding_size)
 {
     const size_t NUM_ENTRIES = 1000;
 
-    std::mt19937 engine{std::random_device{}()};
-
     securefs::key_type key(0x3e);
     securefs::id_type null_id{};
 
@@ -123,15 +124,19 @@ TEST_CASE("Test BtreeDirectory")
                                      null_id,
                                      true,
                                      8000,
-                                     12);
+                                     12,
+                                     max_padding_size,
+                                     false);
         securefs::SimpleDirectory ref_dir(service.open_file_stream(tmp3, flags, 0644),
                                           service.open_file_stream(tmp4, flags, 0644),
                                           key,
                                           null_id,
                                           true,
                                           8000,
-                                          12);
-
+                                          12,
+                                          max_padding_size,
+                                          false);
+        securefs::DoubleFileLockGuard dflg(dir, ref_dir);
         test(dir, ref_dir, 1000, 0.3, 0.5, 0.1, 1);
         test(dir, ref_dir, 1000, 0.3, 0.1, 0.5, 2);
         test(dir, ref_dir, 1000, 0.3, 0.3, 0.3, 3);
@@ -146,16 +151,27 @@ TEST_CASE("Test BtreeDirectory")
                                      null_id,
                                      true,
                                      8000,
-                                     12);
+                                     12,
+                                     max_padding_size,
+                                     false);
         securefs::SimpleDirectory ref_dir(service.open_file_stream(tmp3, O_RDWR, 0),
                                           service.open_file_stream(tmp4, O_RDWR, 0),
                                           key,
                                           null_id,
                                           true,
                                           8000,
-                                          12);
+                                          12,
+                                          max_padding_size,
+                                          false);
+        securefs::DoubleFileLockGuard dflg(dir, ref_dir);
         test(dir, ref_dir, 1000, 0.3, 0.3, 0.3, 4);
         dir.flush();
         ref_dir.flush();
     }
 }
+
+TEST_CASE("Test BtreeDirectory")
+{
+    test_btree_dir(0);
+    test_btree_dir(128);
+}
diff -pruN 0.11.1+ds-4/test/test_common.cpp 0.13.1+ds-1/test/test_common.cpp
--- 0.11.1+ds-4/test/test_common.cpp	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/test_common.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,37 @@
+#include "test_common.h"
+#include "logger.h"
+
+#include <cryptopp/osrng.h>
+
+#include <cstdlib>
+
+std::mt19937& get_random_number_engine()
+{
+    struct Initializer
+    {
+        std::mt19937 mt;
+
+        Initializer()
+        {
+            uint32_t data[64];
+            const char* seed = std::getenv("SECUREFS_TEST_SEED");
+            if (seed && seed[0])
+            {
+                securefs::parse_hex(seed, reinterpret_cast<unsigned char*>(data), sizeof(data));
+            }
+            else
+            {
+                CryptoPP::OS_GenerateRandomBlock(
+                    false, reinterpret_cast<unsigned char*>(data), sizeof(data));
+            }
+            INFO_LOG("Random seed: %s",
+                     securefs::hexify(reinterpret_cast<const unsigned char*>(data), sizeof(data))
+                         .c_str());
+            std::seed_seq seq(std::begin(data), std::end(data));
+            mt.seed(seq);
+        }
+    };
+
+    static thread_local Initializer initializer;
+    return initializer.mt;
+}
diff -pruN 0.11.1+ds-4/test/test_common.h 0.13.1+ds-1/test/test_common.h
--- 0.11.1+ds-4/test/test_common.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.13.1+ds-1/test/test_common.h	2023-01-27 02:25:50.000000000 +0000
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <random>
+
+std::mt19937& get_random_number_engine();
diff -pruN 0.11.1+ds-4/test/test_crypto.cpp 0.13.1+ds-1/test/test_crypto.cpp
--- 0.11.1+ds-4/test/test_crypto.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/test_crypto.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -1,4 +1,5 @@
 #include <catch.hpp>
+#include <cryptopp/scrypt.h>
 
 #include "crypto.h"
 #include "lite_fs.h"
@@ -304,15 +305,16 @@ static void test_scrypt(const char* pass
                         const char* expected)
 {
     std::vector<byte> output(dkLen);
-    securefs::libscrypt_scrypt(reinterpret_cast<const byte*>(password),
-                               strlen(password),
-                               reinterpret_cast<const byte*>(salt),
-                               strlen(salt),
-                               N,
-                               r,
-                               p,
-                               output.data(),
-                               dkLen);
+    CryptoPP::Scrypt scrypt;
+    scrypt.DeriveKey(output.data(),
+                     output.size(),
+                     reinterpret_cast<const byte*>(password),
+                     strlen(password),
+                     reinterpret_cast<const byte*>(salt),
+                     strlen(salt),
+                     N,
+                     r,
+                     p);
     CAPTURE(password);
     CAPTURE(salt);
     CHECK(memcmp(expected, output.data(), dkLen) == 0);
diff -pruN 0.11.1+ds-4/test/test_files.cpp 0.13.1+ds-1/test/test_files.cpp
--- 0.11.1+ds-4/test/test_files.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/test_files.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -10,7 +10,7 @@
 #include <string.h>
 #include <vector>
 
-TEST_CASE("File table")
+static void test_file_table(unsigned max_padding_size)
 {
     using namespace securefs;
     auto base_dir = OSService::temp_name("tmp/file_table", ".dir");
@@ -24,8 +24,11 @@ TEST_CASE("File table")
 
     {
         auto root = std::make_shared<OSService>(base_dir);
-        FileTable table(2, root, master_key, 0, 3000, 16);
+        ShardedFileTableImpl table(2, root, master_key, 0, 3000, 16, max_padding_size);
         auto dir = dynamic_cast<Directory*>(table.create_as(null_id, FileBase::DIRECTORY));
+        DEFER(table.close(dir));
+
+        FileLockGuard flg(*dir);
         table.create_as(file_id, FileBase::REGULAR_FILE);
         dir->add_entry(".", null_id, FileBase::DIRECTORY);
         dir->add_entry("..", null_id, FileBase::DIRECTORY);
@@ -38,7 +41,6 @@ TEST_CASE("File table")
         {
             REQUIRE(e.error_number() == ENOTSUP);
         }
-        table.close(dir);
     }
 
     {
@@ -50,11 +52,14 @@ TEST_CASE("File table")
 
     {
         auto root = std::make_shared<OSService>(base_dir);
-        FileTable table(2, root, master_key, 0, 3000, 16);
+        FileTableImpl table(2, root, master_key, 0, 3000, 16, max_padding_size);
         auto dir = dynamic_cast<Directory*>(table.open_as(null_id, FileBase::DIRECTORY));
+        DEFER(table.close(dir));
+
         securefs::PODArray<char, 32> xattr_test_value(0);
         try
         {
+            FileLockGuard flg(*dir);
             dir->getxattr(xattr_name, xattr_test_value.data(), xattr_test_value.size());
             REQUIRE(xattr_value == xattr_test_value);
         }
@@ -64,10 +69,13 @@ TEST_CASE("File table")
         }
 
         std::set<std::string> filenames;
-        dir->iterate_over_entries([&](const std::string& fn, const id_type&, int) {
-            filenames.insert(fn);
-            return true;
-        });
+        FileLockGuard flg(*dir);
+        dir->iterate_over_entries(
+            [&](const std::string& fn, const id_type&, int)
+            {
+                filenames.insert(fn);
+                return true;
+            });
         REQUIRE((filenames == decltype(filenames){".", "..", "hello"}));
         id_type id;
         int type;
@@ -75,6 +83,11 @@ TEST_CASE("File table")
         REQUIRE(memcmp(id.data(), file_id.data(), id.size()) == 0);
         bool is_regular_file = type == FileBase::REGULAR_FILE;
         REQUIRE(is_regular_file);
-        table.close(dir);
     }
 }
+
+TEST_CASE("File table")
+{
+    test_file_table(0);
+    test_file_table(255);
+}
diff -pruN 0.11.1+ds-4/test/test_streams.cpp 0.13.1+ds-1/test/test_streams.cpp
--- 0.11.1+ds-4/test/test_streams.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/test_streams.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -1,8 +1,11 @@
 #include "catch.hpp"
 
+#include "crypto.h"
 #include "lite_stream.h"
+#include "logger.h"
 #include "platform.h"
 #include "streams.h"
+#include "test_common.h"
 
 #include <algorithm>
 #include <array>
@@ -13,21 +16,64 @@
 
 using securefs::OSService;
 
-static void test(securefs::StreamBase& stream, unsigned times)
+namespace securefs
 {
-    auto posix_stream_impl = OSService::get_default().open_file_stream(
-        OSService::temp_name("tmp/", "stream"), O_RDWR | O_CREAT | O_EXCL, 0644);
-    auto&& posix_stream = *posix_stream_impl;
+namespace
+{
+    class MemoryStream : public StreamBase
+    {
+    private:
+        std::vector<unsigned char> m_buffer;
+
+    public:
+        explicit MemoryStream() { m_buffer.reserve(1u << 20); }
+
+        length_type read(void* output, offset_type offset, length_type length) override
+        {
+            if (offset >= m_buffer.size() || length <= 0)
+            {
+                return 0;
+            }
+            auto read_sz = std::min<length_type>(length, m_buffer.size() - offset);
+            memcpy(output, m_buffer.data() + offset, read_sz);
+            return read_sz;
+        }
+
+        void write(const void* input, offset_type offset, length_type length) override
+        {
+            if (length <= 0)
+            {
+                return;
+            }
+            if (offset + length > m_buffer.size())
+            {
+                m_buffer.resize(offset + length);
+            }
+            memcpy(m_buffer.data() + offset, input, length);
+        }
+
+        length_type size() const override { return m_buffer.size(); }
+
+        void flush() override {}
+
+        void resize(length_type size) override { m_buffer.resize(size); }
+        bool is_sparse() const noexcept { return true; }
+    };
+}    // namespace
+}    // namespace securefs
 
-    posix_stream.resize(0);
+static void test(securefs::StreamBase& stream, unsigned times)
+{
+    CAPTURE(typeid(stream).name());
+    securefs::MemoryStream memory_stream;
     stream.resize(0);
 
     std::vector<byte> data(4096 * 5);
-    std::vector<byte> buffer(data), posix_buffer(data);
-    std::mt19937 mt{std::random_device{}()};
+    std::vector<byte> buffer(data), memory_buffer(data);
+    auto& mt = get_random_number_engine();
 
     {
-        std::uniform_int_distribution<unsigned> dist;
+        std::uniform_int_distribution<unsigned> dist(0, 255);
         for (auto&& b : data)
             b = static_cast<byte>(dist(mt));
     }
@@ -43,32 +89,35 @@ static void test(securefs::StreamBase& s
         {
         case 0:
             stream.write(data.data(), a, std::min<size_t>(b, data.size()));
-            posix_stream.write(data.data(), a, std::min<size_t>(b, data.size()));
+            memory_stream.write(data.data(), a, std::min<size_t>(b, data.size()));
             break;
 
         case 1:
         {
-            posix_buffer = buffer;
+            memory_buffer = buffer;
             auto read_sz = stream.read(buffer.data(), a, std::min<size_t>(b, buffer.size()));
-            auto posix_read_sz = posix_stream.read(
-                posix_buffer.data(), a, std::min<size_t>(b, posix_buffer.size()));
-            REQUIRE(read_sz == posix_read_sz);
-            REQUIRE(memcmp(buffer.data(), posix_buffer.data(), read_sz) == 0);
+            auto memory_read_sz = memory_stream.read(
+                memory_buffer.data(), a, std::min<size_t>(b, memory_buffer.size()));
+            CHECK(read_sz == memory_read_sz);
+            if (read_sz == memory_read_sz)
+                CHECK(memcmp(buffer.data(), memory_buffer.data(), read_sz) == 0);
             break;
         }
 
         case 2:
-            REQUIRE(stream.size() == posix_stream.size());
+            CHECK(stream.size() == memory_stream.size());
             break;
 
         case 3:
-            // stream.resize(a);
-            // posix_stream.resize(a);
+            stream.resize(a);
+            memory_stream.resize(a);
+            CHECK(stream.size() == a);
+            CHECK(memory_stream.size() == a);
             break;
 
         case 4:
             stream.flush();
-            posix_stream.flush();
+            memory_stream.flush();
 
         default:
             break;
@@ -152,7 +201,28 @@ namespace dummy
             memcpy(m_buffer[block_number].data(), input, length);
         }
 
-        void adjust_logical_size(length_type length) override { (void)length; }
+        void adjust_logical_size(length_type length) override
+        {
+            if (length == 0)
+            {
+                m_buffer.clear();
+                return;
+            }
+            auto num_blocks = (length + (BLOCK_SIZE - 1)) / BLOCK_SIZE;
+            auto residue = length % BLOCK_SIZE;
+            if (num_blocks > m_buffer.size())
+            {
+                for (auto i = m_buffer.size(); i < num_blocks; ++i)
+                {
+                    m_buffer.emplace_back(BLOCK_SIZE, 0);
+                }
+            }
+            else if (num_blocks < m_buffer.size())
+            {
+                m_buffer.resize(num_blocks);
+            }
+            m_buffer.back().resize(residue ? residue : BLOCK_SIZE);
+        }
     };
 
     const size_t DummyBlockStream::BLOCK_SIZE = 1000;
@@ -169,27 +239,33 @@ void dump_contents(const std::vector<byt
 
 TEST_CASE("Test streams")
 {
-    auto filename = OSService::temp_name("tmp/", ".stream");
-
     securefs::key_type key(0xf4);
     securefs::id_type id(0xee);
-    auto posix_stream
-        = OSService::get_default().open_file_stream(filename, O_RDWR | O_CREAT | O_EXCL, 0644);
-
     {
-        auto hmac_stream = securefs::make_stream_hmac(key, id, posix_stream, true);
+        auto filename = OSService::temp_name("tmp/", ".stream");
+        auto posix_stream
+            = OSService::get_default().open_file_stream(filename, O_RDWR | O_CREAT | O_EXCL, 0644);
+        test(*posix_stream, 4000);
+    }
+    {
+        auto hmac_stream
+            = securefs::make_stream_hmac(key, id, std::make_shared<securefs::MemoryStream>(), true);
         test(*hmac_stream, 5000);
     }
     {
-        posix_stream->resize(0);
-        securefs::dummy::DummpyCryptStream ds(posix_stream, 8000);
+        securefs::dummy::DummpyCryptStream ds(std::make_shared<securefs::MemoryStream>(), 8000);
         test(ds, 5000);
     }
     {
-        auto meta_posix_stream = OSService::get_default().open_file_stream(
-            OSService::temp_name("tmp/", "metastream"), O_RDWR | O_CREAT | O_EXCL, 0644);
-        auto aes_gcm_stream = securefs::make_cryptstream_aes_gcm(
-            posix_stream, meta_posix_stream, key, key, id, true, 4096, 12);
+        auto aes_gcm_stream
+            = securefs::make_cryptstream_aes_gcm(std::make_shared<securefs::MemoryStream>(),
+                                                 std::make_shared<securefs::MemoryStream>(),
+                                                 key,
+                                                 key,
+                                                 id,
+                                                 true,
+                                                 4096,
+                                                 12);
         std::vector<byte> header(aes_gcm_stream.second->max_header_length() - 1, 5);
         aes_gcm_stream.second->write_header(header.data(), header.size());
         test(*aes_gcm_stream.first, 1000);
@@ -203,14 +279,50 @@ TEST_CASE("Test streams")
         test(dbs, 3001);
     }
     {
-        auto underlying_stream = OSService::get_default().open_file_stream(
-            OSService::temp_name("tmp/", "litestream"), O_RDWR | O_CREAT | O_EXCL, 0644);
-        securefs::lite::AESGCMCryptStream lite_stream(underlying_stream, key);
-        const byte test_data[] = "Hello, world";
-        byte output[4096];
-        lite_stream.write(test_data, 0, sizeof(test_data));
-        REQUIRE(lite_stream.read(output, 0, sizeof(output)) == sizeof(test_data));
-        REQUIRE(memcmp(test_data, output, sizeof(test_data)) == 0);
-        test(lite_stream, 3001);
+        securefs::PaddedStream ps(std::make_shared<securefs::MemoryStream>(), 16);
+        test(ps, 1000);
+    }
+    CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption padding_aes(key.data(), key.size());
+    auto test_lite_stream = [&](unsigned block_size, unsigned iv_size, unsigned padding_size)
+    {
+        CAPTURE(block_size);
+        CAPTURE(iv_size);
+        CAPTURE(padding_size);
+
+        auto memory_stream = std::make_shared<securefs::MemoryStream>();
+        {
+            securefs::lite::AESGCMCryptStream lite_stream(
+                memory_stream, key, block_size, iv_size, true, padding_size, &padding_aes);
+            INFO_LOG("Actual padding size: %u", lite_stream.get_padding_size());
+
+            const byte test_data[] = "Hello, world";
+            byte output[4096];
+            lite_stream.write(test_data, 0, sizeof(test_data));
+            REQUIRE(lite_stream.read(output, 0, sizeof(output)) == sizeof(test_data));
+            REQUIRE(memcmp(test_data, output, sizeof(test_data)) == 0);
+            test(lite_stream, 1001);
+        }
+        {
+            securefs::lite::AESGCMCryptStream lite_stream(
+                memory_stream, key, block_size, iv_size, true, padding_size, &padding_aes);
+            INFO_LOG("Actual padding size: %u", lite_stream.get_padding_size());
+            test(lite_stream, 1001);
+        }
+    };
+
+    test_lite_stream(4096, 12, 0);
+    test_lite_stream(333, 16, 0);
+    test_lite_stream(333, 12, 14);
+    test_lite_stream(4096, 12, 1);
+    test_lite_stream(4096, 12, 32);
+
+    {
+        // Test that the `padding_aes` is stateless
+        CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption second_padding_aes(key.data(), key.size());
+        byte plaintext[16], ciphertext[16], second_ciphertext[16];
+        securefs::generate_random(plaintext, sizeof(plaintext));
+        padding_aes.ProcessData(ciphertext, plaintext, sizeof(ciphertext));
+        second_padding_aes.ProcessData(second_ciphertext, plaintext, sizeof(second_ciphertext));
+        REQUIRE(memcmp(ciphertext, second_ciphertext, sizeof(ciphertext)) == 0);
     }
 }
diff -pruN 0.11.1+ds-4/test/test_win.cpp 0.13.1+ds-1/test/test_win.cpp
--- 0.11.1+ds-4/test/test_win.cpp	2020-03-28 14:28:41.000000000 +0000
+++ 0.13.1+ds-1/test/test_win.cpp	2023-01-27 02:25:50.000000000 +0000
@@ -10,13 +10,21 @@ TEST_CASE("Test windows path normalizati
     REQUIRE(OSService::concat_and_norm(R"(C:\Users)", R"(C:\abc.txt)") == LR"(C:\abc.txt)");
     REQUIRE(OSService::concat_and_norm(R"(C:\Users)", R"(\\server\share)") == LR"(\\server\share)");
     REQUIRE(OSService::concat_and_norm(R"(C:\Users)", R"(/cygwin)") == LR"(/cygwin)");
-    REQUIRE(OSService::concat_and_norm(R"(C:\Users)", R"(cygwin)") == LR"(\\?\C:\Users\cygwin)");
+    REQUIRE(OSService::concat_and_norm(R"(C:\Users)", R"(👌🎍😍)") == LR"(\\?\C:\Users\👌🎍😍)");
     REQUIRE(OSService::concat_and_norm(R"(C:\Users)", R"(cygwin\..\abc\.\.\.)")
             == LR"(\\?\C:\Users\abc)");
     REQUIRE(OSService::concat_and_norm(R"(\\server\share\)", R"(cygwin\..\abc\.\.\.)")
             == LR"(\\server\share\abc)");
     REQUIRE(OSService::concat_and_norm(R"(\\?\\C:\Users\\\.//..)", R"(cygwin/)")
             == LR"(\\?\C:\cygwin)");
+    REQUIRE(OSService::concat_and_norm(R"(\\?\C:\Users)", R"(cygwin/../c)")
+            == LR"(\\?\C:\Users\c)");
+    REQUIRE(OSService::concat_and_norm(R"(\\?\C:\Users)", R"(cygwin/./c)")
+            == LR"(\\?\C:\Users\cygwin\c)");
+    REQUIRE(OSService::concat_and_norm(R"(\\?\C:\Users)", R"(cygwin)")
+            == LR"(\\?\C:\Users\cygwin)");
+    REQUIRE(OSService::concat_and_norm(R"(\\?\UNC\server\share)", R"(a\b\c)")
+            == LR"(\\?\UNC\server\share\a\b\c)");
     REQUIRE_THROWS(OSService::concat_and_norm("abc", "def"));
 }
-#endif
\ No newline at end of file
+#endif
