Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ntfs2btrfs for openSUSE:Factory 
checked in at 2023-10-31 20:26:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ntfs2btrfs (Old)
 and      /work/SRC/openSUSE:Factory/.ntfs2btrfs.new.17445 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ntfs2btrfs"

Tue Oct 31 20:26:28 2023 rev:2 rq:1121427 version:20230501

Changes:
--------
--- /work/SRC/openSUSE:Factory/ntfs2btrfs/ntfs2btrfs.changes    2023-10-24 
20:09:30.395031778 +0200
+++ /work/SRC/openSUSE:Factory/.ntfs2btrfs.new.17445/ntfs2btrfs.changes 
2023-10-31 20:26:47.560348610 +0100
@@ -1,0 +2,10 @@
+Tue Oct 24 00:00:00 CEST 2023 - dste...@suse.cz
+
+- Update to version 20230501:
+  * Fixed inline extent items being written out of order (not diagnosed by
+    btrfs check)
+  * Fixed metadata items being written with wrong level value (not diagnosed by
+    btrfs check)
+  * ADSes with overly-long names now get skipped
+
+-------------------------------------------------------------------

Old:
----
  20220812.tar.gz

New:
----
  20230501.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ntfs2btrfs.spec ++++++
--- /var/tmp/diff_new_pack.Z9Kfzv/_old  2023-10-31 20:26:48.064367123 +0100
+++ /var/tmp/diff_new_pack.Z9Kfzv/_new  2023-10-31 20:26:48.064367123 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package ntfs2btrfs
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,7 +16,7 @@
 #
 
 
-%define                tag     20220812
+%define                tag     20230501
 Name:           ntfs2btrfs
 Version:        %{tag}
 Release:        0

++++++ 20220812.tar.gz -> 20230501.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ntfs2btrfs-20220812/CMakeLists.txt 
new/ntfs2btrfs-20230501/CMakeLists.txt
--- old/ntfs2btrfs-20220812/CMakeLists.txt      2022-08-12 02:07:00.000000000 
+0200
+++ new/ntfs2btrfs-20230501/CMakeLists.txt      2023-05-01 22:59:36.000000000 
+0200
@@ -3,7 +3,7 @@
 cmake_policy(SET CMP0091 NEW)
 set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
 
-project(ntfs2btrfs VERSION 20220812)
+project(ntfs2btrfs VERSION 20230501)
 
 include(GNUInstallDirs)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ntfs2btrfs-20220812/README.md 
new/ntfs2btrfs-20230501/README.md
--- old/ntfs2btrfs-20220812/README.md   2022-08-12 02:07:00.000000000 +0200
+++ new/ntfs2btrfs-20230501/README.md   2023-05-01 22:59:36.000000000 +0200
@@ -37,10 +37,12 @@
 download the latest Zip file, or use 
[Scoop](https://github.com/ScoopInstaller/Main/blob/master/bucket/ntfs2btrfs.json).
 
 For Linux:
-* [Arch](https://aur.archlinux.org/packages/ntfs2btrfs-git) (thanks to 
[nicman23](https://github.com/nicman23))
+* [Arch](https://aur.archlinux.org/packages/ntfs2btrfs)
 * [Fedora](https://src.fedoraproject.org/rpms/ntfs2btrfs) (thanks to 
[Conan-Kudo](https://github.com/Conan-Kudo))
-* [Gentoo 
ebuild](https://raw.githubusercontent.com/maharmstone/ntfs2btrfs/master/ntfs2btrfs-20210923.ebuild)
-* [Debian & Ubuntu](https://sid.ethz.ch/debian/ntfs2btrfs/) (thanks to 
[alexmyczko](https://github.com/alexmyczko))
+* Gentoo - available as sys-fs/ntfs2btrfs in the guru repository
+* [Debian](https://packages.debian.org/ntfs2btrfs) (thanks to 
[alexmyczko](https://github.com/alexmyczko))
+* [Ubuntu](https://packages.ubuntu.com/ntfs2btrfs) (thanks to 
[alexmyczko](https://github.com/alexmyczko))
+* [openSUSE](https://build.opensuse.org/package/show/filesystems/ntfs2btrfs) 
(thanks to David Sterba)
 
 For other distributions or operating systems, you will need to compile it 
yourself - see
 below.
@@ -48,6 +50,11 @@
 Changelog
 ---------
 
+* 20230501
+  * Fixed inline extent items being written out of order (not diagnosed by 
`btrfs check`)
+  * Fixed metadata items being written with wrong level value (not diagnosed 
by `btrfs check`)
+  * ADSes with overly-long names now get skipped
+
 * 20220812
   * Added --no-datasum option, to skip calculating checksums
   * LXSS / WSL metadata is now preserved
@@ -93,7 +100,9 @@
 
 On Linux:
 
-    cmake .
+    mkdir build
+    cd build
+    cmake ..
     make
 
 You'll also need [libfmt](https://github.com/fmtlib/fmt) installed - it should 
be
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ntfs2btrfs-20220812/ntfs2btrfs-20210923.ebuild 
new/ntfs2btrfs-20230501/ntfs2btrfs-20210923.ebuild
--- old/ntfs2btrfs-20220812/ntfs2btrfs-20210923.ebuild  2022-08-12 
02:07:00.000000000 +0200
+++ new/ntfs2btrfs-20230501/ntfs2btrfs-20210923.ebuild  1970-01-01 
01:00:00.000000000 +0100
@@ -1,42 +0,0 @@
-# Copyright 2021 Gentoo Authors
-# Distributed under the terms of the GNU General Public License v2
-
-EAPI=8
-
-inherit cmake
-
-DESCRIPTION="Conversion tool from NTFS to Btrfs"
-HOMEPAGE="https://github.com/maharmstone/ntfs2btrfs";
-
-if [[ ${PV} = *9999 ]]; then
-    inherit git-r3
-    EGIT_REPO_URI="https://github.com/maharmstone/ntfs2btrfs.git";
-else
-       SRC_URI="https://github.com/maharmstone/${PN}/archive/${PV}.tar.gz -> 
${P}.tar.gz"
-       KEYWORDS="~amd64 ~arm ~arm64 ~ppc64 ~x86"
-fi
-
-LICENSE="GPL-2"
-SLOT="0"
-IUSE="+zlib +lzo +zstd"
-
-DEPEND="dev-libs/libfmt
-       zlib? ( sys-libs/zlib )
-       lzo? ( dev-libs/lzo )
-       zstd? ( app-arch/zstd )"
-RDEPEND="${DEPEND}"
-BDEPEND=""
-
-src_prepare() {
-       cmake_src_prepare
-}
-
-src_configure() {
-       local mycmakeargs=(
-               -DWITH_ZLIB=$(usex zlib)
-               -DWITH_LZO=$(usex lzo)
-               -DWITH_ZSTD=$(usex zstd)
-       )
-
-       cmake_src_configure
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ntfs2btrfs-20220812/ntfs2btrfs.8.in 
new/ntfs2btrfs-20230501/ntfs2btrfs.8.in
--- old/ntfs2btrfs-20220812/ntfs2btrfs.8.in     2022-08-12 02:07:00.000000000 
+0200
+++ new/ntfs2btrfs-20230501/ntfs2btrfs.8.in     2023-05-01 22:59:36.000000000 
+0200
@@ -1,4 +1,4 @@
-.TH NTFS2BTRFS "8" "August 2022" "ntfs2btrfs @PROJECT_VERSION@" "System 
Administration"
+.TH NTFS2BTRFS "8" "May 2023" "ntfs2btrfs @PROJECT_VERSION@" "System 
Administration"
 .SH NAME
 ntfs2btrfs \- convert ntfs filesystem to btrfs filesystem
 .SH SYNOPSIS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ntfs2btrfs-20220812/src/btrfs.h 
new/ntfs2btrfs-20230501/src/btrfs.h
--- old/ntfs2btrfs-20220812/src/btrfs.h 2022-08-12 02:07:00.000000000 +0200
+++ new/ntfs2btrfs-20230501/src/btrfs.h 2023-05-01 22:59:36.000000000 +0200
@@ -16,36 +16,38 @@
 #define MAX_LABEL_SIZE      0x100
 #define SUBVOL_ROOT_INODE   0x100
 
-#define TYPE_INODE_ITEM        0x01
-#define TYPE_INODE_REF         0x0C
-#define TYPE_INODE_EXTREF      0x0D
-#define TYPE_XATTR_ITEM        0x18
-#define TYPE_ORPHAN_INODE      0x30
-#define TYPE_DIR_ITEM          0x54
-#define TYPE_DIR_INDEX         0x60
-#define TYPE_EXTENT_DATA       0x6C
-#define TYPE_EXTENT_CSUM       0x80
-#define TYPE_ROOT_ITEM         0x84
-#define TYPE_ROOT_BACKREF      0x90
-#define TYPE_ROOT_REF          0x9C
-#define TYPE_EXTENT_ITEM       0xA8
-#define TYPE_METADATA_ITEM     0xA9
-#define TYPE_TREE_BLOCK_REF    0xB0
-#define TYPE_EXTENT_DATA_REF   0xB2
-#define TYPE_EXTENT_REF_V0     0xB4
-#define TYPE_SHARED_BLOCK_REF  0xB6
-#define TYPE_SHARED_DATA_REF   0xB8
-#define TYPE_BLOCK_GROUP_ITEM  0xC0
-#define TYPE_FREE_SPACE_INFO   0xC6
-#define TYPE_FREE_SPACE_EXTENT 0xC7
-#define TYPE_FREE_SPACE_BITMAP 0xC8
-#define TYPE_DEV_EXTENT        0xCC
-#define TYPE_DEV_ITEM          0xD8
-#define TYPE_CHUNK_ITEM        0xE4
-#define TYPE_TEMP_ITEM         0xF8
-#define TYPE_DEV_STATS         0xF9
-#define TYPE_SUBVOL_UUID       0xFB
-#define TYPE_SUBVOL_REC_UUID   0xFC
+enum class btrfs_key_type : uint8_t {
+    INODE_ITEM = 0x01,
+    INODE_REF = 0x0C,
+    INODE_EXTREF = 0x0D,
+    XATTR_ITEM = 0x18,
+    ORPHAN_INODE = 0x30,
+    DIR_ITEM = 0x54,
+    DIR_INDEX = 0x60,
+    EXTENT_DATA = 0x6C,
+    EXTENT_CSUM = 0x80,
+    ROOT_ITEM = 0x84,
+    ROOT_BACKREF = 0x90,
+    ROOT_REF = 0x9C,
+    EXTENT_ITEM = 0xA8,
+    METADATA_ITEM = 0xA9,
+    TREE_BLOCK_REF = 0xB0,
+    EXTENT_DATA_REF = 0xB2,
+    EXTENT_REF_V0 = 0xB4,
+    SHARED_BLOCK_REF = 0xB6,
+    SHARED_DATA_REF = 0xB8,
+    BLOCK_GROUP_ITEM = 0xC0,
+    FREE_SPACE_INFO = 0xC6,
+    FREE_SPACE_EXTENT = 0xC7,
+    FREE_SPACE_BITMAP = 0xC8,
+    DEV_EXTENT = 0xCC,
+    DEV_ITEM = 0xD8,
+    CHUNK_ITEM = 0xE4,
+    TEMP_ITEM = 0xF8,
+    DEV_STATS = 0xF9,
+    SUBVOL_UUID = 0xFB,
+    SUBVOL_REC_UUID = 0xFC
+};
 
 #define BTRFS_ROOT_ROOT         1
 #define BTRFS_ROOT_EXTENT       2
@@ -141,7 +143,7 @@
 
 typedef struct {
     uint64_t obj_id;
-    uint8_t obj_type;
+    btrfs_key_type obj_type;
     uint64_t offset;
 } KEY;
 
@@ -437,8 +439,8 @@
     uint32_t count;
 } SHARED_DATA_REF;
 
-#define FREE_SPACE_EXTENT 1
-#define FREE_SPACE_BITMAP 2
+static const uint8_t FREE_SPACE_EXTENT = 1;
+static const uint8_t FREE_SPACE_BITMAP = 2;
 
 typedef struct {
     uint64_t offset;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ntfs2btrfs-20220812/src/ntfs.cpp 
new/ntfs2btrfs-20230501/src/ntfs.cpp
--- old/ntfs2btrfs-20220812/src/ntfs.cpp        2022-08-12 02:07:00.000000000 
+0200
+++ new/ntfs2btrfs-20230501/src/ntfs.cpp        2023-05-01 22:59:36.000000000 
+0200
@@ -32,7 +32,7 @@
 
 using namespace std;
 
-void process_fixups(MULTI_SECTOR_HEADER* header, uint64_t length, unsigned int 
sector_size) {
+static void process_fixups(MULTI_SECTOR_HEADER* header, uint64_t length, 
unsigned int sector_size) {
     uint64_t sectors;
     uint16_t* seq;
     uint8_t* ptr;
@@ -465,7 +465,7 @@
 }
 
 static void walk_btree(const index_root& ir, const list<mapping>& mappings, 
const index_node_header& inh, ntfs& dev,
-                       const function<void(const index_entry&, string_view)>& 
func, unsigned int level) {
+                       const invocable<const index_entry&, string_view> auto& 
func, unsigned int level) {
     auto ent = reinterpret_cast<const index_entry*>((uint8_t*)&inh + 
inh.first_entry);
 
     do {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ntfs2btrfs-20220812/src/ntfs.h 
new/ntfs2btrfs-20230501/src/ntfs.h
--- old/ntfs2btrfs-20220812/src/ntfs.h  2022-08-12 02:07:00.000000000 +0200
+++ new/ntfs2btrfs-20230501/src/ntfs.h  2023-05-01 22:59:36.000000000 +0200
@@ -81,7 +81,7 @@
     INDEX_ROOT = 0x90,
     INDEX_ALLOCATION = 0xA0,
     BITMAP = 0xB0,
-    SYMBOLIC_LINK = 0xC0,
+    REPARSE_POINT = 0xC0,
     EA_INFORMATION = 0xD0,
     EA = 0xE0,
     PROPERTY_SET = 0xF0,
@@ -135,8 +135,8 @@
             case ntfs_attribute::BITMAP:
                 return fmt::format_to(ctx.out(), "BITMAP");
 
-            case ntfs_attribute::SYMBOLIC_LINK:
-                return fmt::format_to(ctx.out(), "SYMBOLIC_LINK");
+            case ntfs_attribute::REPARSE_POINT:
+                return fmt::format_to(ctx.out(), "REPARSE_POINT");
 
             case ntfs_attribute::EA_INFORMATION:
                 return fmt::format_to(ctx.out(), "EA_INFORMATION");
@@ -551,4 +551,3 @@
 void read_nonresident_mappings(const ATTRIBUTE_RECORD_HEADER& att, 
std::list<mapping>& mappings,
                                uint32_t cluster_size, uint64_t vdl);
 void populate_skip_list(ntfs& dev, uint64_t inode, std::list<uint64_t>& 
skiplist);
-void process_fixups(MULTI_SECTOR_HEADER* header, uint64_t length, unsigned int 
sector_size);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ntfs2btrfs-20220812/src/ntfs2btrfs.cpp 
new/ntfs2btrfs-20230501/src/ntfs2btrfs.cpp
--- old/ntfs2btrfs-20220812/src/ntfs2btrfs.cpp  2022-08-12 02:07:00.000000000 
+0200
+++ new/ntfs2btrfs-20230501/src/ntfs2btrfs.cpp  2023-05-01 22:59:36.000000000 
+0200
@@ -451,29 +451,29 @@
     last_chunk_end = chunks.back().offset - chunk_virt_offset + 
chunks.back().length;
 }
 
-static void add_item(root& r, uint64_t obj_id, uint8_t obj_type, uint64_t 
offset, const buffer_t& buf) {
+static void add_item(root& r, uint64_t obj_id, btrfs_key_type obj_type, 
uint64_t offset, const buffer_t& buf) {
     auto ret = r.items.emplace(KEY{obj_id, obj_type, offset}, buf);
 
     if (!ret.second)
-        throw formatted_error("Could not insert entry ({:x}, {:x}, {:x}) into 
root items list.", obj_id, obj_type, offset);
+        throw formatted_error("Could not insert entry ({:x}, {}, {:x}) into 
root items list.", obj_id, obj_type, offset);
 }
 
-static void add_item_move(root& r, uint64_t obj_id, uint8_t obj_type, uint64_t 
offset, buffer_t& buf) {
+static void add_item_move(root& r, uint64_t obj_id, btrfs_key_type obj_type, 
uint64_t offset, buffer_t& buf) {
     auto ret = r.items.emplace(KEY{obj_id, obj_type, offset}, buffer_t{});
 
     if (!ret.second)
-        throw formatted_error("Could not insert entry ({:x}, {:x}, {:x}) into 
root items list.", obj_id, obj_type, offset);
+        throw formatted_error("Could not insert entry ({:x}, {}, {:x}) into 
root items list.", obj_id, obj_type, offset);
 
     auto& it = ret.first->second;
 
     it.swap(buf);
 }
 
-static void add_item(root& r, uint64_t obj_id, uint8_t obj_type, uint64_t 
offset, const void* data, uint16_t len) {
+static void add_item(root& r, uint64_t obj_id, btrfs_key_type obj_type, 
uint64_t offset, const void* data, uint16_t len) {
     auto ret = r.items.emplace(KEY{obj_id, obj_type, offset}, buffer_t(len));
 
     if (!ret.second)
-        throw formatted_error("Could not insert entry ({:x}, {:x}, {:x}) into 
root items list.", obj_id, obj_type, offset);
+        throw formatted_error("Could not insert entry ({:x}, {}, {:x}) into 
root items list.", obj_id, obj_type, offset);
 
     auto& it = ret.first->second;
 
@@ -500,7 +500,7 @@
     ci1s.stripe.offset = c.disk_start;
     ci1s.stripe.dev_uuid = dev_uuid;
 
-    add_item(chunk_root, 0x100, TYPE_CHUNK_ITEM, c.offset, &ci1s, 
sizeof(ci1s));
+    add_item(chunk_root, 0x100, btrfs_key_type::CHUNK_ITEM, c.offset, &ci1s, 
sizeof(ci1s));
 
     de.chunktree = BTRFS_ROOT_CHUNK;
     de.objid = 0x100;
@@ -508,13 +508,13 @@
     de.length = c.length;
     de.chunktree_uuid = chunk_uuid;
 
-    add_item(devtree_root, 1, TYPE_DEV_EXTENT, c.disk_start, &de, 
sizeof(DEV_EXTENT));
+    add_item(devtree_root, 1, btrfs_key_type::DEV_EXTENT, c.disk_start, &de, 
sizeof(DEV_EXTENT));
 
     bgi.chunk_tree = 0x100;
     bgi.flags = c.type;
     // bgi.used gets set in update_extent_root
 
-    add_item(extent_root, c.offset, TYPE_BLOCK_GROUP_ITEM, c.length, &bgi, 
sizeof(BLOCK_GROUP_ITEM));
+    add_item(extent_root, c.offset, btrfs_key_type::BLOCK_GROUP_ITEM, 
c.length, &bgi, sizeof(BLOCK_GROUP_ITEM));
 }
 
 static uint64_t allocate_metadata(uint64_t r, root& extent_root, uint8_t 
level) {
@@ -526,7 +526,7 @@
     mi.extent_item.refcount = 1;
     mi.extent_item.generation = 1;
     mi.extent_item.flags = EXTENT_ITEM_TREE_BLOCK;
-    mi.type = TYPE_TREE_BLOCK_REF;
+    mi.type = btrfs_key_type::TREE_BLOCK_REF;
     mi.tbr.offset = r;
 
     for (auto& c : chunks) {
@@ -544,7 +544,7 @@
 
                     c.used += tree_size;
 
-                    add_item(extent_root, addr, TYPE_METADATA_ITEM, level, 
&mi, sizeof(metadata_item));
+                    add_item(extent_root, addr, btrfs_key_type::METADATA_ITEM, 
level, &mi, sizeof(metadata_item));
 
                     return addr;
                 }
@@ -594,7 +594,7 @@
 
             c.used = tree_size;
 
-            add_item(extent_root, addr, TYPE_METADATA_ITEM, level, &mi, 
sizeof(metadata_item));
+            add_item(extent_root, addr, btrfs_key_type::METADATA_ITEM, level, 
&mi, sizeof(metadata_item));
 
             return addr;
         }
@@ -713,21 +713,39 @@
     th.tree_id = id;
     th.level = 0;
 
+    auto get_address = [this](root& extent_root, uint8_t level) {
+        uint64_t addr;
+
+        if (!old_addresses.empty()) {
+            addr = old_addresses.front().first;
+
+            if (level != old_addresses.front().second) { // change metadata 
level in extent tree
+                if (auto f = extent_root.items.find(KEY{addr, 
btrfs_key_type::METADATA_ITEM, old_addresses.front().second}); f != 
extent_root.items.end()) {
+                    auto d = move(f->second);
+
+                    extent_root.items.erase(f);
+                    extent_root.items.emplace(make_pair(KEY{addr, 
btrfs_key_type::METADATA_ITEM, level}, d));
+                }
+            }
+
+            old_addresses.pop_front();
+        } else {
+            addr = allocate_metadata(id, extent_root, level);
+            allocations_done = true;
+        }
+
+        addresses.emplace_back(addr, level);
+
+        return addr;
+    };
+
     {
         auto ln = (leaf_node*)((uint8_t*)buf.data() + sizeof(tree_header));
         uint32_t data_off = tree_size - (uint32_t)sizeof(tree_header);
 
         for (const auto& i : items) {
             if (sizeof(leaf_node) + i.second.size() > space_left) { // tree 
complete, add to list
-                if (!old_addresses.empty()) {
-                    th.address = old_addresses.front();
-                    old_addresses.pop_front();
-                } else {
-                    th.address = allocate_metadata(id, extent_root, th.level);
-                    allocations_done = true;
-                }
-
-                addresses.push_back(th.address);
+                th.address = get_address(extent_root, 0);
                 th.num_items = num_items;
 
                 calc_tree_hash(th, csum_type);
@@ -769,15 +787,7 @@
     }
 
     if (num_items > 0 || items.size() == 0) { // flush remaining tree
-        if (!old_addresses.empty()) {
-            th.address = old_addresses.front();
-            old_addresses.pop_front();
-        } else {
-            th.address = allocate_metadata(id, extent_root, th.level);
-            allocations_done = true;
-        }
-
-        addresses.push_back(th.address);
+        th.address = get_address(extent_root, 0);
         th.num_items = num_items;
 
         calc_tree_hash(th, csum_type);
@@ -825,15 +835,7 @@
                 continue;
 
             if (sizeof(internal_node) > space_left) { // tree complete, add to 
list
-                if (!old_addresses.empty()) {
-                    th.address = old_addresses.front();
-                    old_addresses.pop_front();
-                } else {
-                    th.address = allocate_metadata(id, extent_root, th.level);
-                    allocations_done = true;
-                }
-
-                addresses.push_back(th.address);
+                th.address = get_address(extent_root, level);
                 th.num_items = num_items;
 
                 calc_tree_hash(th, csum_type);
@@ -870,15 +872,7 @@
         }
 
         if (num_items > 0) { // flush remaining tree
-            if (!old_addresses.empty()) {
-                th.address = old_addresses.front();
-                old_addresses.pop_front();
-            } else {
-                th.address = allocate_metadata(id, extent_root, th.level);
-                allocations_done = true;
-            }
-
-            addresses.push_back(th.address);
+            th.address = get_address(extent_root, level);
             th.num_items = num_items;
 
             calc_tree_hash(th, csum_type);
@@ -894,8 +888,6 @@
     } while (true);
 
     tree_addr = ((tree_header*)trees.back().data())->address;
-
-    // FIXME - make sure level of METADATA_ITEMs is correct
 }
 
 void root::write_trees(ntfs& dev) {
@@ -970,7 +962,7 @@
 
     sys_chunk_size = 0;
     for (const auto& c : chunk_root.items) {
-        if (c.first.obj_type == TYPE_CHUNK_ITEM) {
+        if (c.first.obj_type == btrfs_key_type::CHUNK_ITEM) {
             auto& ci = *(CHUNK_ITEM*)c.second.data();
 
             if (ci.type & BLOCK_FLAG_SYSTEM) {
@@ -1018,7 +1010,7 @@
     set_volume_label(sb, dev);
 
     for (const auto& c : chunk_root.items) {
-        if (c.first.obj_type == TYPE_DEV_ITEM) {
+        if (c.first.obj_type == btrfs_key_type::DEV_ITEM) {
             memcpy(&sb.dev_item, c.second.data(), sizeof(DEV_ITEM));
             break;
         }
@@ -1030,7 +1022,7 @@
         uint8_t* ptr = sb.sys_chunk_array;
 
         for (const auto& c : chunk_root.items) {
-            if (c.first.obj_type == TYPE_CHUNK_ITEM) {
+            if (c.first.obj_type == btrfs_key_type::CHUNK_ITEM) {
                 auto& ci = *(CHUNK_ITEM*)c.second.data();
 
                 if (ci.type & BLOCK_FLAG_SYSTEM) {
@@ -1097,7 +1089,7 @@
     di.device_uuid = dev_uuid;
     di.fs_uuid = fs_uuid;
 
-    add_item(chunk_root, 1, TYPE_DEV_ITEM, 1, &di, sizeof(DEV_ITEM));
+    add_item(chunk_root, 1, btrfs_key_type::DEV_ITEM, 1, &di, 
sizeof(DEV_ITEM));
 }
 
 static void add_to_root_root(const root& r, root& root_root) {
@@ -1121,7 +1113,7 @@
 
     // block_number, bytes_used, and root_level are set in update_root_root
 
-    add_item(root_root, r.id, TYPE_ROOT_ITEM, 0, &ri, sizeof(ROOT_ITEM));
+    add_item(root_root, r.id, btrfs_key_type::ROOT_ITEM, 0, &ri, 
sizeof(ROOT_ITEM));
 }
 
 static void update_root_root(root& root_root, enum btrfs_csum_type csum_type) {
@@ -1135,7 +1127,7 @@
         bool changed = true;
 
         for (unsigned int i = 0; i < th.num_items; i++) {
-            if (ln[i].key.obj_type == TYPE_ROOT_ITEM) {
+            if (ln[i].key.obj_type == btrfs_key_type::ROOT_ITEM) {
                 auto& ri = *(ROOT_ITEM*)((uint8_t*)t.data() + 
sizeof(tree_header) + ln[i].offset);
 
                 for (const auto& r : roots) {
@@ -1160,7 +1152,7 @@
 
     memset(ds, 0, sizeof(ds));
 
-    add_item(r, 0, TYPE_DEV_STATS, 1, &ds, sizeof(ds));
+    add_item(r, 0, btrfs_key_type::DEV_STATS, 1, &ds, sizeof(ds));
 }
 
 static BTRFS_UUID generate_uuid(default_random_engine& gen) {
@@ -1185,7 +1177,7 @@
         bool changed = true;
 
         for (unsigned int i = 0; i < th.num_items; i++) {
-            if (ln[i].key.obj_type == TYPE_BLOCK_GROUP_ITEM) {
+            if (ln[i].key.obj_type == btrfs_key_type::BLOCK_GROUP_ITEM) {
                 auto& bgi = *(BLOCK_GROUP_ITEM*)((uint8_t*)t.data() + 
sizeof(tree_header) + ln[i].offset);
 
                 for (const auto& c : chunks) {
@@ -1204,8 +1196,8 @@
 }
 
 static void add_inode_ref(root& r, uint64_t inode, uint64_t parent, uint64_t 
index, string_view name) {
-    if (r.items.count(KEY{inode, TYPE_INODE_REF, parent}) != 0) { // 
collision, append to the end
-        auto& old = r.items.at(KEY{inode, TYPE_INODE_REF, parent});
+    if (r.items.count(KEY{inode, btrfs_key_type::INODE_REF, parent}) != 0) { 
// collision, append to the end
+        auto& old = r.items.at(KEY{inode, btrfs_key_type::INODE_REF, parent});
 
         size_t irlen = offsetof(INODE_REF, name[0]) + name.length();
 
@@ -1229,7 +1221,7 @@
     ir.n = (uint16_t)name.length();
     memcpy(ir.name, name.data(), name.length());
 
-    add_item_move(r, inode, TYPE_INODE_REF, parent, buf);
+    add_item_move(r, inode, btrfs_key_type::INODE_REF, parent, buf);
 }
 
 static void populate_fstree(root& r) {
@@ -1243,7 +1235,7 @@
     ii.st_mode = __S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | 
S_IROTH | S_IXOTH;
     ii.sequence = 1;
 
-    add_item(r, SUBVOL_ROOT_INODE, TYPE_INODE_ITEM, 0, &ii, 
sizeof(INODE_ITEM));
+    add_item(r, SUBVOL_ROOT_INODE, btrfs_key_type::INODE_ITEM, 0, &ii, 
sizeof(INODE_ITEM));
 
     add_inode_ref(r, SUBVOL_ROOT_INODE, SUBVOL_ROOT_INODE, 0, "..");
 }
@@ -1258,7 +1250,7 @@
         auto ln = (leaf_node*)((uint8_t*)t.data() + sizeof(tree_header));
 
         for (unsigned int i = 0; i < th.num_items; i++) {
-            if (ln[i].key.obj_id == 1 && ln[i].key.obj_type == TYPE_DEV_ITEM 
&& ln[i].key.offset == 1) {
+            if (ln[i].key.obj_id == 1 && ln[i].key.obj_type == 
btrfs_key_type::DEV_ITEM && ln[i].key.offset == 1) {
                 auto& di = *(DEV_ITEM*)((uint8_t*)t.data() + 
sizeof(tree_header) + ln[i].offset);
 
                 di.bytes_used = 0;
@@ -1294,8 +1286,8 @@
         rr.n = sizeof(subvol_name) - 1;
         memcpy(rr.name, subvol_name, sizeof(subvol_name) - 1);
 
-        add_item(root_root, BTRFS_ROOT_FSTREE, TYPE_ROOT_REF, image_subvol_id, 
buf);
-        add_item_move(root_root, image_subvol_id, TYPE_ROOT_BACKREF, 
BTRFS_ROOT_FSTREE, buf);
+        add_item(root_root, BTRFS_ROOT_FSTREE, btrfs_key_type::ROOT_REF, 
image_subvol_id, buf);
+        add_item_move(root_root, image_subvol_id, 
btrfs_key_type::ROOT_BACKREF, BTRFS_ROOT_FSTREE, buf);
     }
 
     // add DIR_ITEM and DIR_INDEX
@@ -1305,7 +1297,7 @@
         auto& di = *(DIR_ITEM*)buf.data();
 
         di.key.obj_id = image_subvol_id;
-        di.key.obj_type = TYPE_ROOT_ITEM;
+        di.key.obj_type = btrfs_key_type::ROOT_ITEM;
         di.key.offset = 0xffffffffffffffff;
         di.transid = 1;
         di.m = 0;
@@ -1315,8 +1307,8 @@
 
         auto hash = calc_crc32c(0xfffffffe, (const uint8_t*)subvol_name, 
sizeof(subvol_name) - 1);
 
-        add_item(fstree_root, SUBVOL_ROOT_INODE, TYPE_DIR_ITEM, hash, buf);
-        add_item_move(fstree_root, SUBVOL_ROOT_INODE, TYPE_DIR_INDEX, 2, buf);
+        add_item(fstree_root, SUBVOL_ROOT_INODE, btrfs_key_type::DIR_ITEM, 
hash, buf);
+        add_item_move(fstree_root, SUBVOL_ROOT_INODE, 
btrfs_key_type::DIR_INDEX, 2, buf);
     }
 
     // increase st_size in parent dir
@@ -1361,7 +1353,7 @@
         }
     }
 
-    add_item(r, inode, TYPE_INODE_ITEM, 0, &ii, sizeof(INODE_ITEM));
+    add_item(r, inode, btrfs_key_type::INODE_ITEM, 0, &ii, sizeof(INODE_ITEM));
 
     // add DIR_ITEM and DIR_INDEX
 
@@ -1370,7 +1362,7 @@
         auto& di = *(DIR_ITEM*)buf.data();
 
         di.key.obj_id = inode;
-        di.key.obj_type = TYPE_INODE_ITEM;
+        di.key.obj_type = btrfs_key_type::INODE_ITEM;
         di.key.offset = 0;
         di.transid = 1;
         di.m = 0;
@@ -1380,8 +1372,8 @@
 
         auto hash = calc_crc32c(0xfffffffe, (const uint8_t*)image_filename, 
sizeof(image_filename) - 1);
 
-        add_item(r, SUBVOL_ROOT_INODE, TYPE_DIR_ITEM, hash, buf);
-        add_item_move(r, SUBVOL_ROOT_INODE, TYPE_DIR_INDEX, 2, buf);
+        add_item(r, SUBVOL_ROOT_INODE, btrfs_key_type::DIR_ITEM, hash, buf);
+        add_item_move(r, SUBVOL_ROOT_INODE, btrfs_key_type::DIR_INDEX, 2, buf);
     }
 
     // add INODE_REF
@@ -1391,7 +1383,7 @@
     // increase st_size in parent dir
 
     for (auto& it : r.items) {
-        if (it.first.obj_id == SUBVOL_ROOT_INODE && it.first.obj_type == 
TYPE_INODE_ITEM) {
+        if (it.first.obj_id == SUBVOL_ROOT_INODE && it.first.obj_type == 
btrfs_key_type::INODE_ITEM) {
             auto& ii2 = *(INODE_ITEM*)it.second.data();
 
             ii2.st_size += (sizeof(image_filename) - 1) * 2;
@@ -1434,7 +1426,7 @@
 
             ed2.offset = 0;
 
-            add_item(r, inode, TYPE_EXTENT_DATA, addr, buf);
+            add_item(r, inode, btrfs_key_type::EXTENT_DATA, addr, buf);
 
             data_size += ed2.size;
         }
@@ -1690,7 +1682,7 @@
         auto& di = *(DIR_ITEM*)buf.data();
 
         di.key.obj_id = inode;
-        di.key.obj_type = TYPE_INODE_ITEM;
+        di.key.obj_type = btrfs_key_type::INODE_ITEM;
         di.key.offset = 0;
         di.transid = 1;
         di.m = 0;
@@ -1700,10 +1692,10 @@
 
         auto hash = calc_crc32c(0xfffffffe, (const uint8_t*)name.data(), 
(uint32_t)name.length());
 
-        if (r.items.count(KEY{dir, TYPE_DIR_ITEM, hash}) == 0)
-            add_item(r, dir, TYPE_DIR_ITEM, hash, buf);
+        if (r.items.count(KEY{dir, btrfs_key_type::DIR_ITEM, hash}) == 0)
+            add_item(r, dir, btrfs_key_type::DIR_ITEM, hash, buf);
         else { // hash collision
-            auto& ent = r.items.at(KEY{dir, TYPE_DIR_ITEM, hash});
+            auto& ent = r.items.at(KEY{dir, btrfs_key_type::DIR_ITEM, hash});
 
             if (!ent.empty()) {
                 ent.resize(ent.size() + buf.size());
@@ -1714,7 +1706,7 @@
             }
         }
 
-        add_item_move(r, dir, TYPE_DIR_INDEX, seq, buf);
+        add_item_move(r, dir, btrfs_key_type::DIR_INDEX, seq, buf);
     }
 
     // add INODE_REF
@@ -1978,7 +1970,7 @@
     auto& di = *(DIR_ITEM*)buf.data();
 
     di.key.obj_id = di.key.offset = 0;
-    di.key.obj_type = 0;
+    di.key.obj_type = (btrfs_key_type)0;
     di.transid = 1;
     di.m = (uint16_t)data.size();
     di.n = (uint16_t)name.size();
@@ -1986,7 +1978,7 @@
     memcpy(di.name, name.data(), name.size());
     memcpy(di.name + name.size(), data.data(), data.size());
 
-    add_item_move(r, inode, TYPE_XATTR_ITEM, hash, buf);
+    add_item_move(r, inode, btrfs_key_type::XATTR_ITEM, hash, buf);
 }
 
 static void clear_line() {
@@ -2181,6 +2173,11 @@
 
                     auto name2 = xattr_prefix + ads_name;
 
+                    if (name2.size() > 255) {
+                        add_warning("Skipping ADS :{} as name too long", 
ads_name);
+                        break;
+                    }
+
                     uint32_t hash = calc_crc32c(0xfffffffe, (const 
uint8_t*)name2.data(), (uint32_t)name2.length());
 
                     if (att.FormCode == NTFS_ATTRIBUTE_FORM::RESIDENT_FORM && 
(ads_name != "WofCompressedData" || !processed_wof_data)) {
@@ -2300,12 +2297,25 @@
                 break;
             }
 
-            case ntfs_attribute::SYMBOLIC_LINK: {
-                if (att.FormCode == NTFS_ATTRIBUTE_FORM::NONRESIDENT_FORM)
-                    throw formatted_error("Error - SYMBOLIC_LINK is 
non-resident"); // FIXME - can this happen?
+            case ntfs_attribute::REPARSE_POINT: {
+                if (att.FormCode == NTFS_ATTRIBUTE_FORM::RESIDENT_FORM) {
+                    reparse_point.resize(res_data.size());
+                    memcpy(reparse_point.data(), res_data.data(), 
res_data.size());
+                } else {
+                    list<mapping> rp_mappings;
+
+                    read_nonresident_mappings(att, rp_mappings, cluster_size, 
att.Form.Nonresident.ValidDataLength);
 
-                reparse_point.resize(res_data.size());
-                memcpy(reparse_point.data(), res_data.data(), res_data.size());
+                    
reparse_point.resize((size_t)sector_align(att.Form.Nonresident.FileSize, 
cluster_size));
+                    memset(reparse_point.data(), 0, reparse_point.size());
+
+                    for (const auto& m : rp_mappings) {
+                        dev.seek(m.lcn * cluster_size);
+                        dev.read(reparse_point.data() + (m.vcn * 
cluster_size), (size_t)(m.length * cluster_size));
+                    }
+
+                    
reparse_point.resize((size_t)att.Form.Nonresident.FileSize);
+                }
 
                 symlink.clear();
 
@@ -2607,12 +2617,37 @@
             memcpy(v2.data(), v.data() + lxea.length(), v2.size());
 
             xattrs.emplace(EA_CAP, make_pair(EA_CAP_HASH, v2));
-        } else if (n != "$KERNEL.PURGE.APPXFICACHE" && n != 
"$KERNEL.PURGE.ESBCACHE" && n != "$CI.CATALOGHINT" &&
-                   n != "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.DATABASE" && 
n != "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.DATABASEEX1" &&
-                   n != "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.EPOCHEA" && 
n != "APPLICENSING" &&
-                   n != "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.COMMON" && n 
!= "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.COMMONEX" &&
-                   n != "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.COMMONEX_1" 
&& n != "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.USER") {
-            add_warning("Unrecognized EA {}", ea.first);
+        } else {
+            static const string_view recognized_eas[] = {
+                "$KERNEL.PURGE.APPXFICACHE",
+                "$KERNEL.PURGE.ESBCACHE",
+                "$CI.CATALOGHINT",
+                "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.DATABASE",
+                "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.DATABASEEX1",
+                "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.EPOCHEA",
+                "APPLICENSING",
+                "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.COMMON",
+                "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.COMMONEX",
+                "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.COMMONEX_1"
+                "C8A05BC0-3FA8-49E9-8148-61EE14A67687.CSC.USER",
+                "$KERNEL.PURGE.SMARTLOCKER.VALID",
+                "$KERNEL.SMARTLOCKER.ORIGINCLAIM",
+                "$KERNEL.PURGE.APPID.HASHINFO",
+                "$KERNEL.SMARTLOCKER.HASH",
+                "$KERNEL.PURGE.CIPCACHE",
+                "$KERNEL.SMARTLOCKER.UNINSTALLSTRINGS"
+            };
+
+            bool found = false;
+            for (const auto& r : recognized_eas) {
+                if (r == n) {
+                    found = true;
+                    break;
+                }
+            }
+
+            if (!found)
+                add_warning("Unrecognized EA {}", n);
         }
     }
 
@@ -2796,7 +2831,7 @@
                                       rph->ReparseDataLength, 
sizeof(wof_external_info) + sizeof(file_provider_external_info_v0));
             }
 
-            auto fpei = *(file_provider_external_info_v0*)&wofei[1];
+            const auto& fpei = *(file_provider_external_info_v0*)&wofei[1];
 
             if (fpei.Version != FILE_PROVIDER_CURRENT_VERSION) {
                 throw formatted_error("rph->FILE_PROVIDER_EXTERNAL_INFO_V0 
Version was {}, expected {}.",
@@ -2944,7 +2979,7 @@
                 ed2.address = (m.lcn * dev.boot_sector->BytesPerSector * 
dev.boot_sector->SectorsPerCluster) + chunk_virt_offset;
                 ed2.offset = 0;
 
-                add_item(r, inode, TYPE_EXTENT_DATA, m.vcn * 
dev.boot_sector->BytesPerSector * dev.boot_sector->SectorsPerCluster, buf);
+                add_item(r, inode, btrfs_key_type::EXTENT_DATA, m.vcn * 
dev.boot_sector->BytesPerSector * dev.boot_sector->SectorsPerCluster, buf);
             }
         }
     } else if (!inline_data.empty()) {
@@ -3050,7 +3085,7 @@
                 else
                     dev.write(compdata.data(), compdata.size());
 
-                add_item(r, inode, TYPE_EXTENT_DATA, pos, buf);
+                add_item(r, inode, btrfs_key_type::EXTENT_DATA, pos, buf);
 
                 lcn = (ed2.address - chunk_virt_offset) / cluster_size;
                 cl = ed2.size / cluster_size;
@@ -3099,13 +3134,13 @@
             if (vdl < inline_data.size())
                 memset(ed.data + vdl, 0, (size_t)(inline_data.size() - vdl));
 
-            add_item_move(r, inode, TYPE_EXTENT_DATA, 0, buf);
+            add_item_move(r, inode, btrfs_key_type::EXTENT_DATA, 0, buf);
 
             ii.st_blocks = inline_data.size();
         }
     }
 
-    add_item(r, inode, TYPE_INODE_ITEM, 0, &ii, sizeof(INODE_ITEM));
+    add_item(r, inode, btrfs_key_type::INODE_ITEM, 0, &ii, sizeof(INODE_ITEM));
 
     if (item_type == btrfs_inode_type::unknown) {
         if (is_dir)
@@ -3207,6 +3242,16 @@
     fmt::print("\n");
 }
 
+static uint64_t get_extent_data_ref_hash2(uint64_t root, uint64_t objid, 
uint64_t offset) {
+    uint32_t high_crc = 0xffffffff, low_crc = 0xffffffff;
+
+    high_crc = calc_crc32c(high_crc, (uint8_t*)&root, sizeof(uint64_t));
+    low_crc = calc_crc32c(low_crc, (uint8_t*)&objid, sizeof(uint64_t));
+    low_crc = calc_crc32c(low_crc, (uint8_t*)&offset, sizeof(uint64_t));
+
+    return ((uint64_t)high_crc << 31) ^ (uint64_t)low_crc;
+}
+
 static void create_data_extent_items(root& extent_root, const runs_t& runs, 
uint32_t cluster_size, uint64_t image_subvol_id,
                                      uint64_t image_inode) {
     for (const auto& rs : runs) {
@@ -3232,13 +3277,13 @@
                 di.extent_item.refcount = 1;
                 di.extent_item.generation = 1;
                 di.extent_item.flags = EXTENT_ITEM_DATA;
-                di.type = TYPE_EXTENT_DATA_REF;
+                di.type = btrfs_key_type::EXTENT_DATA_REF;
                 di.edr.root = image_subvol_id;
                 di.edr.objid = image_inode;
                 di.edr.count = 1;
                 di.edr.offset = img_addr;
 
-                add_item(extent_root, (r.offset * cluster_size) + 
chunk_virt_offset, TYPE_EXTENT_ITEM, r.length * cluster_size,
+                add_item(extent_root, (r.offset * cluster_size) + 
chunk_virt_offset, btrfs_key_type::EXTENT_ITEM, r.length * cluster_size,
                          &di, sizeof(data_item));
             } else if (r.not_in_img) {
                 data_item di;
@@ -3246,32 +3291,46 @@
                 di.extent_item.refcount = 1;
                 di.extent_item.generation = 1;
                 di.extent_item.flags = EXTENT_ITEM_DATA;
-                di.type = TYPE_EXTENT_DATA_REF;
+                di.type = btrfs_key_type::EXTENT_DATA_REF;
                 di.edr.root = BTRFS_ROOT_FSTREE;
                 di.edr.objid = r.inode;
                 di.edr.count = 1;
                 di.edr.offset = r.file_offset * cluster_size;
 
-                add_item(extent_root, (r.offset * cluster_size) + 
chunk_virt_offset, TYPE_EXTENT_ITEM, r.length * cluster_size,
+                add_item(extent_root, (r.offset * cluster_size) + 
chunk_virt_offset, btrfs_key_type::EXTENT_ITEM, r.length * cluster_size,
                          &di, sizeof(data_item));
             } else {
                 data_item2 di2;
+                EXTENT_DATA_REF* e1;
+                EXTENT_DATA_REF* e2;
 
                 di2.extent_item.refcount = 2;
                 di2.extent_item.generation = 1;
                 di2.extent_item.flags = EXTENT_ITEM_DATA;
-                di2.type1 = TYPE_EXTENT_DATA_REF;
-                di2.edr1.root = image_subvol_id;
-                di2.edr1.objid = image_inode;
-                di2.edr1.count = 1;
-                di2.edr1.offset = img_addr;
-                di2.type2 = TYPE_EXTENT_DATA_REF;
-                di2.edr2.root = BTRFS_ROOT_FSTREE;
-                di2.edr2.objid = r.inode;
-                di2.edr2.count = 1;
-                di2.edr2.offset = r.file_offset * cluster_size;
+                di2.type1 = btrfs_key_type::EXTENT_DATA_REF;
+                di2.type2 = btrfs_key_type::EXTENT_DATA_REF;
+
+                auto hash1 = get_extent_data_ref_hash2(image_subvol_id, 
image_inode, img_addr);
+                auto hash2 = get_extent_data_ref_hash2(BTRFS_ROOT_FSTREE, 
r.inode, r.file_offset * cluster_size);
+
+                if (hash2 > hash1) {
+                    e1 = &di2.edr2;
+                    e2 = &di2.edr1;
+                } else {
+                    e1 = &di2.edr1;
+                    e2 = &di2.edr2;
+                }
+
+                e1->root = image_subvol_id;
+                e1->objid = image_inode;
+                e1->count = 1;
+                e1->offset = img_addr;
+                e2->root = BTRFS_ROOT_FSTREE;
+                e2->objid = r.inode;
+                e2->count = 1;
+                e2->offset = r.file_offset * cluster_size;
 
-                add_item(extent_root, (r.offset * cluster_size) + 
chunk_virt_offset, TYPE_EXTENT_ITEM, r.length * cluster_size,
+                add_item(extent_root, (r.offset * cluster_size) + 
chunk_virt_offset, btrfs_key_type::EXTENT_ITEM, r.length * cluster_size,
                          &di2, sizeof(data_item2));
             }
         }
@@ -3476,7 +3535,7 @@
             }
         }
 
-        add_item(csum_root, EXTENT_CSUM_ID, TYPE_EXTENT_CSUM, (r.offset * 
cluster_size) + chunk_virt_offset, &csums[0], (uint16_t)(r.length * 
cluster_size * csum_size / sector_size));
+        add_item(csum_root, EXTENT_CSUM_ID, btrfs_key_type::EXTENT_CSUM, 
(r.offset * cluster_size) + chunk_virt_offset, &csums[0], (uint16_t)(r.length * 
cluster_size * csum_size / sector_size));
     }
 
     fmt::print("\n");
@@ -3616,7 +3675,7 @@
     ii.st_nlink = 1;
     ii.st_mode = __S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | 
S_IROTH | S_IXOTH;
 
-    add_item(root_root, BTRFS_ROOT_TREEDIR, TYPE_INODE_ITEM, 0, &ii, 
sizeof(INODE_ITEM));
+    add_item(root_root, BTRFS_ROOT_TREEDIR, btrfs_key_type::INODE_ITEM, 0, 
&ii, sizeof(INODE_ITEM));
 
     add_inode_ref(root_root, BTRFS_ROOT_TREEDIR, BTRFS_ROOT_TREEDIR, 0, "..");
 
@@ -3624,7 +3683,7 @@
     auto& di = *(DIR_ITEM*)buf.data();
 
     di.key.obj_id = BTRFS_ROOT_FSTREE;
-    di.key.obj_type = TYPE_ROOT_ITEM;
+    di.key.obj_type = btrfs_key_type::ROOT_ITEM;
     di.key.offset = 0xffffffffffffffff;
     di.transid = 0;
     di.m = 0;
@@ -3632,17 +3691,17 @@
     di.type = btrfs_inode_type::directory;
     memcpy(di.name, default_subvol, sizeof(default_subvol) - 1);
 
-    add_item_move(root_root, BTRFS_ROOT_TREEDIR, TYPE_DIR_ITEM, default_hash, 
buf);
+    add_item_move(root_root, BTRFS_ROOT_TREEDIR, btrfs_key_type::DIR_ITEM, 
default_hash, buf);
 }
 
 static void add_subvol_uuid(root& r) {
-    add_item(r, *(uint64_t*)&subvol_uuid, TYPE_SUBVOL_UUID, 
*(uint64_t*)&subvol_uuid.uuid[sizeof(uint64_t)],
+    add_item(r, *(uint64_t*)&subvol_uuid, btrfs_key_type::SUBVOL_UUID, 
*(uint64_t*)&subvol_uuid.uuid[sizeof(uint64_t)],
              &image_subvol_id, sizeof(image_subvol_id));
 }
 
 static void update_dir_sizes(root& r) {
     for (auto& it : r.items) {
-        if (it.first.obj_type == TYPE_INODE_ITEM && 
r.dir_size.count(it.first.obj_id) != 0) {
+        if (it.first.obj_type == btrfs_key_type::INODE_ITEM && 
r.dir_size.count(it.first.obj_id) != 0) {
             auto& ii = *(INODE_ITEM*)it.second.data();
 
             // FIXME - would it speed things up if we removed the entry from 
dir_size map here?
@@ -3795,7 +3854,7 @@
 
         for (auto& r : roots) {
             if (r.id == BTRFS_ROOT_EXTENT || r.id == BTRFS_ROOT_CHUNK || r.id 
== BTRFS_ROOT_DEVTREE) {
-                r.old_addresses = r.addresses;
+                r.old_addresses.swap(r.addresses);
                 r.addresses.clear();
 
                 // FIXME - unallocate metadata and changed used value in chunks
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ntfs2btrfs-20220812/src/ntfs2btrfs.h 
new/ntfs2btrfs-20230501/src/ntfs2btrfs.h
--- old/ntfs2btrfs-20220812/src/ntfs2btrfs.h    2022-08-12 02:07:00.000000000 
+0200
+++ new/ntfs2btrfs-20230501/src/ntfs2btrfs.h    2023-05-01 22:59:36.000000000 
+0200
@@ -205,7 +205,7 @@
     uint64_t tree_addr;
     uint8_t level;
     uint64_t metadata_size = 0;
-    std::list<uint64_t> addresses, old_addresses;
+    std::list<std::pair<uint64_t, uint8_t>> addresses, old_addresses;
     bool allocations_done = false;
     bool readonly = false;
     std::map<uint64_t, uint64_t> dir_seqs;
@@ -284,21 +284,21 @@
 
 typedef struct {
     EXTENT_ITEM extent_item;
-    uint8_t type;
+    btrfs_key_type type;
     TREE_BLOCK_REF tbr;
 } metadata_item;
 
 typedef struct {
     EXTENT_ITEM extent_item;
-    uint8_t type;
+    btrfs_key_type type;
     EXTENT_DATA_REF edr;
 } data_item;
 
 typedef struct {
     EXTENT_ITEM extent_item;
-    uint8_t type1;
+    btrfs_key_type type1;
     EXTENT_DATA_REF edr1;
-    uint8_t type2;
+    btrfs_key_type type2;
     EXTENT_DATA_REF edr2;
 } data_item2;
 
@@ -316,6 +316,86 @@
     return ((v + s - 1) / s) * s;
 }
 
+template<>
+struct fmt::formatter<enum btrfs_key_type> {
+    constexpr auto parse(format_parse_context& ctx) {
+        auto it = ctx.begin();
+
+        if (it != ctx.end() && *it != '}')
+            throw format_error("invalid format");
+
+        return it;
+    }
+
+    template<typename format_context>
+    auto format(enum btrfs_key_type k, format_context& ctx) const {
+        switch (k) {
+            case btrfs_key_type::INODE_ITEM:
+                return fmt::format_to(ctx.out(), "INODE_ITEM");
+            case btrfs_key_type::INODE_REF:
+                return fmt::format_to(ctx.out(), "INODE_REF");
+            case btrfs_key_type::INODE_EXTREF:
+                return fmt::format_to(ctx.out(), "INODE_EXTREF");
+            case btrfs_key_type::XATTR_ITEM:
+                return fmt::format_to(ctx.out(), "XATTR_ITEM");
+            case btrfs_key_type::ORPHAN_INODE:
+                return fmt::format_to(ctx.out(), "ORPHAN_INODE");
+            case btrfs_key_type::DIR_ITEM:
+                return fmt::format_to(ctx.out(), "DIR_ITEM");
+            case btrfs_key_type::DIR_INDEX:
+                return fmt::format_to(ctx.out(), "DIR_INDEX");
+            case btrfs_key_type::EXTENT_DATA:
+                return fmt::format_to(ctx.out(), "EXTENT_DATA");
+            case btrfs_key_type::EXTENT_CSUM:
+                return fmt::format_to(ctx.out(), "EXTENT_CSUM");
+            case btrfs_key_type::ROOT_ITEM:
+                return fmt::format_to(ctx.out(), "ROOT_ITEM");
+            case btrfs_key_type::ROOT_BACKREF:
+                return fmt::format_to(ctx.out(), "ROOT_BACKREF");
+            case btrfs_key_type::ROOT_REF:
+                return fmt::format_to(ctx.out(), "ROOT_REF");
+            case btrfs_key_type::EXTENT_ITEM:
+                return fmt::format_to(ctx.out(), "EXTENT_ITEM");
+            case btrfs_key_type::METADATA_ITEM:
+                return fmt::format_to(ctx.out(), "METADATA_ITEM");
+            case btrfs_key_type::TREE_BLOCK_REF:
+                return fmt::format_to(ctx.out(), "TREE_BLOCK_REF");
+            case btrfs_key_type::EXTENT_DATA_REF:
+                return fmt::format_to(ctx.out(), "EXTENT_DATA_REF");
+            case btrfs_key_type::EXTENT_REF_V0:
+                return fmt::format_to(ctx.out(), "EXTENT_REF_V0");
+            case btrfs_key_type::SHARED_BLOCK_REF:
+                return fmt::format_to(ctx.out(), "SHARED_BLOCK_REF");
+            case btrfs_key_type::SHARED_DATA_REF:
+                return fmt::format_to(ctx.out(), "SHARED_DATA_REF");
+            case btrfs_key_type::BLOCK_GROUP_ITEM:
+                return fmt::format_to(ctx.out(), "BLOCK_GROUP_ITEM");
+            case btrfs_key_type::FREE_SPACE_INFO:
+                return fmt::format_to(ctx.out(), "FREE_SPACE_INFO");
+            case btrfs_key_type::FREE_SPACE_EXTENT:
+                return fmt::format_to(ctx.out(), "FREE_SPACE_EXTENT");
+            case btrfs_key_type::FREE_SPACE_BITMAP:
+                return fmt::format_to(ctx.out(), "FREE_SPACE_BITMAP");
+            case btrfs_key_type::DEV_EXTENT:
+                return fmt::format_to(ctx.out(), "DEV_EXTENT");
+            case btrfs_key_type::DEV_ITEM:
+                return fmt::format_to(ctx.out(), "DEV_ITEM");
+            case btrfs_key_type::CHUNK_ITEM:
+                return fmt::format_to(ctx.out(), "CHUNK_ITEM");
+            case btrfs_key_type::TEMP_ITEM:
+                return fmt::format_to(ctx.out(), "TEMP_ITEM");
+            case btrfs_key_type::DEV_STATS:
+                return fmt::format_to(ctx.out(), "DEV_STATS");
+            case btrfs_key_type::SUBVOL_UUID:
+                return fmt::format_to(ctx.out(), "SUBVOL_UUID");
+            case btrfs_key_type::SUBVOL_REC_UUID:
+                return fmt::format_to(ctx.out(), "SUBVOL_REC_UUID");
+            default:
+                return fmt::format_to(ctx.out(), "{:x}", (uint8_t)k);
+        }
+    }
+};
+
 static const uint64_t image_subvol_id = 0x100;
 static const char image_filename[] = "ntfs.img";
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ntfs2btrfs-20220812/src/rollback.cpp 
new/ntfs2btrfs-20230501/src/rollback.cpp
--- old/ntfs2btrfs-20220812/src/rollback.cpp    2022-08-12 02:07:00.000000000 
+0200
+++ new/ntfs2btrfs-20230501/src/rollback.cpp    2023-05-01 22:59:36.000000000 
+0200
@@ -304,7 +304,7 @@
     do {
         auto& key = *(KEY*)ptr;
 
-        if (key.obj_type != TYPE_CHUNK_ITEM)
+        if (key.obj_type != btrfs_key_type::CHUNK_ITEM)
             break;
 
         auto& ci = *(CHUNK_ITEM*)(ptr + sizeof(key));
@@ -336,7 +336,7 @@
     chunks_t chunks2;
 
     walk_tree(sb.chunk_tree_addr, [&](const KEY& key, string_view data) {
-        if (key.obj_type != TYPE_CHUNK_ITEM)
+        if (key.obj_type != btrfs_key_type::CHUNK_ITEM)
             return true;
 
         chunks2.emplace(key.offset, buffer_t{data.data(), data.data() + 
data.size()});
@@ -351,7 +351,7 @@
     optional<uint64_t> ret;
 
     walk_tree(sb.root_tree_addr, [&](const KEY& key, string_view data) {
-        if (key.obj_id != root || key.obj_type != TYPE_ROOT_ITEM)
+        if (key.obj_id != root || key.obj_type != btrfs_key_type::ROOT_ITEM)
             return true;
 
         const auto& ri = *(ROOT_ITEM*)data.data();
@@ -378,17 +378,17 @@
     uint32_t hash = calc_crc32c(0xfffffffe, (const uint8_t*)image_filename, 
sizeof(image_filename) - 1);
 
     b.walk_tree(img_root_addr, [&](const KEY& key, string_view data) {
-        if (key.obj_id > SUBVOL_ROOT_INODE || (key.obj_id == SUBVOL_ROOT_INODE 
&& key.obj_type > TYPE_DIR_ITEM))
+        if (key.obj_id > SUBVOL_ROOT_INODE || (key.obj_id == SUBVOL_ROOT_INODE 
&& key.obj_type > btrfs_key_type::DIR_ITEM))
             return false;
 
-        if (key.obj_id == SUBVOL_ROOT_INODE && key.obj_type == TYPE_DIR_ITEM 
&& key.offset == hash) {
+        if (key.obj_id == SUBVOL_ROOT_INODE && key.obj_type == 
btrfs_key_type::DIR_ITEM && key.offset == hash) {
             auto& di = *(DIR_ITEM*)data.data();
 
             // FIXME - handle hash collisions
 
             if (di.n == sizeof(image_filename) - 1 && !memcmp(di.name, 
image_filename, di.n)) {
-                if (di.key.obj_type != TYPE_INODE_ITEM)
-                    throw formatted_error("DIR_ITEM for {} pointed to object 
type {:x}, expected TYPE_INODE_ITEM.",
+                if (di.key.obj_type != btrfs_key_type::INODE_ITEM)
+                    throw formatted_error("DIR_ITEM for {} pointed to object 
type {}, expected INODE_ITEM.",
                                           string_view(di.name, di.n), 
di.key.obj_type);
 
                 inode = di.key.obj_id;
@@ -408,10 +408,10 @@
     map<uint64_t, pair<uint64_t, uint64_t>> extents;
 
     b.walk_tree(img_root_addr, [&](const KEY& key, string_view data) {
-        if (key.obj_id > inode || (key.obj_id == inode && key.obj_type > 
TYPE_EXTENT_DATA))
+        if (key.obj_id > inode || (key.obj_id == inode && key.obj_type > 
btrfs_key_type::EXTENT_DATA))
             return false;
 
-        if (key.obj_id != inode || key.obj_type != TYPE_EXTENT_DATA)
+        if (key.obj_id != inode || key.obj_type != btrfs_key_type::EXTENT_DATA)
             return true;
 
         const auto& ed = *(EXTENT_DATA*)data.data();

Reply via email to