ReactOS.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2024
December
November
October
September
August
July
June
May
April
March
February
January
2023
December
November
October
September
August
July
June
May
April
March
February
January
2022
December
November
October
September
August
July
June
May
April
March
February
January
2021
December
November
October
September
August
July
June
May
April
March
February
January
2020
December
November
October
September
August
July
June
May
April
March
February
January
2019
December
November
October
September
August
July
June
May
April
March
February
January
2018
December
November
October
September
August
July
June
May
April
March
February
January
2017
December
November
October
September
August
July
June
May
April
March
February
January
2016
December
November
October
September
August
July
June
May
April
March
February
January
2015
December
November
October
September
August
July
June
May
April
March
February
January
2014
December
November
October
September
August
July
June
May
April
March
February
January
2013
December
November
October
September
August
July
June
May
April
March
February
January
2012
December
November
October
September
August
July
June
May
April
March
February
January
2011
December
November
October
September
August
July
June
May
April
March
February
January
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008
December
November
October
September
August
July
June
May
April
March
February
January
2007
December
November
October
September
August
July
June
May
April
March
February
January
2006
December
November
October
September
August
July
June
May
April
March
February
January
2005
December
November
October
September
August
July
June
May
April
March
February
January
2004
December
November
October
September
August
July
June
May
April
March
February
List overview
Download
Ros-diffs
August 2018
----- 2024 -----
December 2024
November 2024
October 2024
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
----- 2012 -----
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
May 2012
April 2012
March 2012
February 2012
January 2012
----- 2011 -----
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
----- 2010 -----
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
----- 2009 -----
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
----- 2008 -----
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
----- 2007 -----
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
----- 2006 -----
December 2006
November 2006
October 2006
September 2006
August 2006
July 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
----- 2005 -----
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
May 2005
April 2005
March 2005
February 2005
January 2005
----- 2004 -----
December 2004
November 2004
October 2004
September 2004
August 2004
July 2004
June 2004
May 2004
April 2004
March 2004
February 2004
ros-diffs@reactos.org
32 participants
304 discussions
Start a n
N
ew thread
04/04: [BTRFSTOOLS] Added python scripts for inspecting BTRFS filesystem internals
by Victor Perevertkin
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=d0847939e4a0fddd1be25…
commit d0847939e4a0fddd1be253265be3e09c18adcf28 Author: Victor Perevertkin <victor(a)perevertkin.ru> AuthorDate: Tue Aug 14 17:51:03 2018 +0300 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Mon Aug 20 08:26:56 2018 +0200 [BTRFSTOOLS] Added python scripts for inspecting BTRFS filesystem internals --- .../devutils/btrfstools/btrfs_playground.py | 40 + .../devutils/btrfstools/btrfs_structures.py | 1292 ++++++++++++++++++++ .../applications/devutils/btrfstools/crc32c.py | 105 ++ 3 files changed, 1437 insertions(+) diff --git a/modules/rosapps/applications/devutils/btrfstools/btrfs_playground.py b/modules/rosapps/applications/devutils/btrfstools/btrfs_playground.py new file mode 100644 index 0000000000..2a861e3af5 --- /dev/null +++ b/modules/rosapps/applications/devutils/btrfstools/btrfs_playground.py @@ -0,0 +1,40 @@ +# PROJECT: Python tools for traversing BTRFS structures +# LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+
) +# PURPOSE: Script for obtaining freeldr.sys from BTRFS disk image +# COPYRIGHT: Copyright 2018 Victor Perevertkin (victor(a)perevertkin.ru) + +from btrfs_structures import * +import crc32c + +fs = FileSystem('btrfs-big.bin', 0x7e00) + +fs.print_chunk_map() + + +freeldr_dir_key = Key(256, DIR_ITEM_KEY, crc32c.name_hash('freeldr.sys')) # 256 - root dir objectid crc32c.name_hash('freeldr.sys') +print(freeldr_dir_key) + +print('!!!!!!!!!!!!!!!!!!!! fs tree 1') +fs_level, fs_root = fs.fs_root +freeldr_dir_key, freeldr_dir_item = fs.search_tree(fs_level, fs_root, freeldr_dir_key) +fs.search_tree(fs_level, fs_root, freeldr_dir_key, fs.print_node) + +freeldr_item, = (x for x in freeldr_dir_item if x.name.decode('utf-8') == 'freeldr.sys') +freeldr_extent_data_key = Key(freeldr_item.location.objectid, EXTENT_DATA_KEY, 0) + +print('!!!!!!!!!!!!!!!!!!!! fs tree 2') +freeldr_extent_data_key, freeldr_extent_data_item = fs.search_tree(fs_level, fs_root, freeldr_extent_data_key) +fs.search_tree(fs_level, fs_root, freeldr_extent_data_key, fs.print_node) + +# # exploring extent tree +print('!!!!!!!!!!!!!!!!!!!! extent tree') +extent_level, extent_root = fs.extent_root +exkey, extent_item = fs.search_tree(extent_level, extent_root, Key(freeldr_extent_data_item.disk_bytenr, EXTENT_ITEM_KEY, freeldr_extent_data_item.disk_num_bytes)) + +print(freeldr_extent_data_item) +fs.fd.seek(fs.logical_to_physical(extent_item.vaddr)) +freeldr = fs.fd.read(freeldr_extent_data_item.num_bytes) + +file = open("readed_freeldr.sys", "wb") +file.write(freeldr) +print(crc32c.name_hash('freeldr.sys')) diff --git a/modules/rosapps/applications/devutils/btrfstools/btrfs_structures.py b/modules/rosapps/applications/devutils/btrfstools/btrfs_structures.py new file mode 100644 index 0000000000..726a23cf58 --- /dev/null +++ b/modules/rosapps/applications/devutils/btrfstools/btrfs_structures.py @@ -0,0 +1,1292 @@ +# PROJECT: Python tools for traversing BTRFS structures +# LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+
) +# PURPOSE: Classes and structures for BTRFS on-disk layout +# COPYRIGHT: Copyright 2018 Victor Perevertkin (victor(a)perevertkin.ru) + +# some code was taken from
https://github.com/knorrie/python-btrfs
+ +from btrfs_constants import * +import struct +from collections import namedtuple, OrderedDict +import collections.abc +import copy +import datetime +import os +import uuid +import crc32c + +ULLONG_MAX = (1 << 64) - 1 +ULONG_MAX = (1 << 32) - 1 + + +def ULL(n): + return n & ULLONG_MAX + + +ROOT_TREE_OBJECTID = 1 +EXTENT_TREE_OBJECTID = 2 +CHUNK_TREE_OBJECTID = 3 +DEV_TREE_OBJECTID = 4 +FS_TREE_OBJECTID = 5 +ROOT_TREE_DIR_OBJECTID = 6 +CSUM_TREE_OBJECTID = 7 +QUOTA_TREE_OBJECTID = 8 +UUID_TREE_OBJECTID = 9 +FREE_SPACE_TREE_OBJECTID = 10 + +DEV_STATS_OBJECTID = 0 +BALANCE_OBJECTID = ULL(-4) +ORPHAN_OBJECTID = ULL(-5) +TREE_LOG_OBJECTID = ULL(-6) +TREE_LOG_FIXUP_OBJECTID = ULL(-7) +TREE_RELOC_OBJECTID = ULL(-8) +DATA_RELOC_TREE_OBJECTID = ULL(-9) +EXTENT_CSUM_OBJECTID = ULL(-10) +FREE_SPACE_OBJECTID = ULL(-11) +FREE_INO_OBJECTID = ULL(-12) +MULTIPLE_OBJECTIDS = ULL(-255) + +FIRST_FREE_OBJECTID = 256 +LAST_FREE_OBJECTID = ULL(-256) +FIRST_CHUNK_TREE_OBJECTID = 256 + +DEV_ITEMS_OBJECTID = 1 + +BTRFS_SYSTEM_CHUNK_ARRAY_SIZE = 2048 + + +INODE_ITEM_KEY = 1 +INODE_REF_KEY = 12 +INODE_EXTREF_KEY = 13 +XATTR_ITEM_KEY = 24 +ORPHAN_ITEM_KEY = 48 +DIR_LOG_ITEM_KEY = 60 +DIR_LOG_INDEX_KEY = 72 +DIR_ITEM_KEY = 84 +DIR_INDEX_KEY = 96 +EXTENT_DATA_KEY = 108 +EXTENT_CSUM_KEY = 128 +ROOT_ITEM_KEY = 132 +ROOT_BACKREF_KEY = 144 +ROOT_REF_KEY = 156 +EXTENT_ITEM_KEY = 168 +METADATA_ITEM_KEY = 169 +TREE_BLOCK_REF_KEY = 176 +EXTENT_DATA_REF_KEY = 178 +SHARED_BLOCK_REF_KEY = 182 +SHARED_DATA_REF_KEY = 184 +BLOCK_GROUP_ITEM_KEY = 192 +FREE_SPACE_INFO_KEY = 198 +FREE_SPACE_EXTENT_KEY = 199 +FREE_SPACE_BITMAP_KEY = 200 +DEV_EXTENT_KEY = 204 +DEV_ITEM_KEY = 216 +CHUNK_ITEM_KEY = 228 +QGROUP_STATUS_KEY = 240 +QGROUP_INFO_KEY = 242 +QGROUP_LIMIT_KEY = 244 +QGROUP_RELATION_KEY = 246 +BALANCE_ITEM_KEY = 248 +DEV_STATS_KEY = 249 +DEV_REPLACE_KEY = 250 +UUID_KEY_SUBVOL = 251 +UUID_KEY_RECEIVED_SUBVOL = 252 +STRING_ITEM_KEY = 253 + +BLOCK_GROUP_SINGLE = 0 +BLOCK_GROUP_DATA = 1 << 0 +BLOCK_GROUP_SYSTEM = 1 << 1 +BLOCK_GROUP_METADATA = 1 << 2 +BLOCK_GROUP_RAID0 = 1 << 3 +BLOCK_GROUP_RAID1 = 1 << 4 +BLOCK_GROUP_DUP = 1 << 5 +BLOCK_GROUP_RAID10 = 1 << 6 +BLOCK_GROUP_RAID5 = 1 << 7 +BLOCK_GROUP_RAID6 = 1 << 8 + +BLOCK_GROUP_TYPE_MASK = ( + BLOCK_GROUP_DATA | + BLOCK_GROUP_SYSTEM | + BLOCK_GROUP_METADATA +) + +BLOCK_GROUP_PROFILE_MASK = ( + BLOCK_GROUP_RAID0 | + BLOCK_GROUP_RAID1 | + BLOCK_GROUP_RAID5 | + BLOCK_GROUP_RAID6 | + BLOCK_GROUP_DUP | + BLOCK_GROUP_RAID10 +) + +AVAIL_ALLOC_BIT_SINGLE = 1 << 48 # used in balance_args +SPACE_INFO_GLOBAL_RSV = 1 << 49 + + +_block_group_flags_str_map = { + BLOCK_GROUP_DATA: 'DATA', + BLOCK_GROUP_METADATA: 'METADATA', + BLOCK_GROUP_SYSTEM: 'SYSTEM', + BLOCK_GROUP_RAID0: 'RAID0', + BLOCK_GROUP_RAID1: 'RAID1', + BLOCK_GROUP_DUP: 'DUP', + BLOCK_GROUP_RAID10: 'RAID10', + BLOCK_GROUP_RAID5: 'RAID5', + BLOCK_GROUP_RAID6: 'RAID6', +} + +_balance_args_profiles_str_map = { + BLOCK_GROUP_RAID0: 'RAID0', + BLOCK_GROUP_RAID1: 'RAID1', + BLOCK_GROUP_DUP: 'DUP', + BLOCK_GROUP_RAID10: 'RAID10', + BLOCK_GROUP_RAID5: 'RAID5', + BLOCK_GROUP_RAID6: 'RAID6', + AVAIL_ALLOC_BIT_SINGLE: 'SINGLE', +} + +QGROUP_LEVEL_SHIFT = 48 + +EXTENT_FLAG_DATA = 1 << 0 +EXTENT_FLAG_TREE_BLOCK = 1 << 1 +BLOCK_FLAG_FULL_BACKREF = 1 << 8 + +_extent_flags_str_map = { + EXTENT_FLAG_DATA: 'DATA', + EXTENT_FLAG_TREE_BLOCK: 'TREE_BLOCK', + BLOCK_FLAG_FULL_BACKREF: 'FULL_BACKREF', +} + +INODE_NODATASUM = 1 << 0 +INODE_NODATACOW = 1 << 1 +INODE_READONLY = 1 << 2 +INODE_NOCOMPRESS = 1 << 3 +INODE_PREALLOC = 1 << 4 +INODE_SYNC = 1 << 5 +INODE_IMMUTABLE = 1 << 6 +INODE_APPEND = 1 << 7 +INODE_NODUMP = 1 << 8 +INODE_NOATIME = 1 << 9 +INODE_DIRSYNC = 1 << 10 +INODE_COMPRESS = 1 << 11 + +_inode_flags_str_map = { + INODE_NODATASUM: 'NODATASUM', + INODE_READONLY: 'READONLY', + INODE_NOCOMPRESS: 'NOCOMPRESS', + INODE_PREALLOC: 'PREALLOC', + INODE_SYNC: 'SYNC', + INODE_IMMUTABLE: 'IMMUTABLE', + INODE_APPEND: 'APPEND', + INODE_NODUMP: 'NODUMP', + INODE_NOATIME: 'NOATIME', + INODE_DIRSYNC: 'DIRSYNC', + INODE_COMPRESS: 'COMPRESS', +} + +ROOT_SUBVOL_RDONLY = 1 << 0 + +_root_flags_str_map = { + ROOT_SUBVOL_RDONLY: 'RDONLY', +} + +FT_UNKNOWN = 0 +FT_REG_FILE = 1 +FT_DIR = 2 +FT_CHRDEV = 3 +FT_BLKDEV = 4 +FT_FIFO = 5 +FT_SOCK = 6 +FT_SYMLINK = 7 +FT_XATTR = 8 +FT_MAX = 9 + +_dir_item_type_str_map = { + FT_UNKNOWN: 'UNKNOWN', + FT_REG_FILE: 'FILE', + FT_DIR: 'DIR', + FT_CHRDEV: 'CHRDEV', + FT_BLKDEV: 'BLKDEV', + FT_FIFO: 'FIFO', + FT_SOCK: 'SOCK', + FT_SYMLINK: 'SYMLINK', + FT_XATTR: 'XATTR', +} + +COMPRESS_NONE = 0 +COMPRESS_ZLIB = 1 +COMPRESS_LZO = 2 +COMPRESS_ZSTD = 3 + +_compress_type_str_map = { + COMPRESS_NONE: 'none', + COMPRESS_ZLIB: 'zlib', + COMPRESS_LZO: 'lzo', + COMPRESS_ZSTD: 'zstd', +} + +FILE_EXTENT_INLINE = 0 +FILE_EXTENT_REG = 1 +FILE_EXTENT_PREALLOC = 2 + +_file_extent_type_str_map = { + FILE_EXTENT_INLINE: 'inline', + FILE_EXTENT_REG: 'regular', + FILE_EXTENT_PREALLOC: 'prealloc', +} + + +def qgroup_level(objectid): + return objectid >> QGROUP_LEVEL_SHIFT + + +def qgroup_subvid(objectid): + return objectid & ((1 << QGROUP_LEVEL_SHIFT) - 1) + + +_key_objectid_str_map = { + ROOT_TREE_OBJECTID: 'ROOT_TREE', + EXTENT_TREE_OBJECTID: 'EXTENT_TREE', + CHUNK_TREE_OBJECTID: 'CHUNK_TREE', + DEV_TREE_OBJECTID: 'DEV_TREE', + FS_TREE_OBJECTID: 'FS_TREE', + ROOT_TREE_DIR_OBJECTID: 'ROOT_TREE_DIR', + CSUM_TREE_OBJECTID: 'CSUM_TREE', + QUOTA_TREE_OBJECTID: 'QUOTA_TREE', + UUID_TREE_OBJECTID: 'UUID_TREE', + FREE_SPACE_TREE_OBJECTID: 'FREE_SPACE_TREE', + BALANCE_OBJECTID: 'BALANCE', + ORPHAN_OBJECTID: 'ORPHAN', + TREE_LOG_OBJECTID: 'TREE_LOG', + TREE_LOG_FIXUP_OBJECTID: 'TREE_LOG_FIXUP', + TREE_RELOC_OBJECTID: 'TREE_RELOC', + DATA_RELOC_TREE_OBJECTID: 'DATA_RELOC_TREE', + EXTENT_CSUM_OBJECTID: 'EXTENT_CSUM', + FREE_SPACE_OBJECTID: 'FREE_SPACE', + FREE_INO_OBJECTID: 'FREE_INO', + MULTIPLE_OBJECTIDS: 'MULTIPLE', +} + + +def key_objectid_str(objectid, _type): + if _type == DEV_EXTENT_KEY: + return str(objectid) + if _type == QGROUP_RELATION_KEY: + return "{}/{}".format(qgroup_level(objectid), qgroup_subvid(objectid)) + if _type == UUID_KEY_SUBVOL or _type == UUID_KEY_RECEIVED_SUBVOL: + return "0x{:0>16x}".format(objectid) + + if objectid == ROOT_TREE_OBJECTID and _type == DEV_ITEM_KEY: + return 'DEV_ITEMS' + if objectid == DEV_STATS_OBJECTID and _type == DEV_STATS_KEY: + return 'DEV_STATS' + if objectid == FIRST_CHUNK_TREE_OBJECTID and _type == CHUNK_ITEM_KEY: + return 'FIRST_CHUNK_TREE' + if objectid == ULLONG_MAX: + return '-1' + + return _key_objectid_str_map.get(objectid, str(objectid)) + + +_key_type_str_map = { + INODE_ITEM_KEY: 'INODE_ITEM', + INODE_REF_KEY: 'INODE_REF', + INODE_EXTREF_KEY: 'INODE_EXTREF', + XATTR_ITEM_KEY: 'XATTR_ITEM', + ORPHAN_ITEM_KEY: 'ORPHAN_ITEM', + DIR_LOG_ITEM_KEY: 'DIR_LOG_ITEM', + DIR_LOG_INDEX_KEY: 'DIR_LOG_INDEX', + DIR_ITEM_KEY: 'DIR_ITEM', + DIR_INDEX_KEY: 'DIR_INDEX', + EXTENT_DATA_KEY: 'EXTENT_DATA', + EXTENT_CSUM_KEY: 'EXTENT_CSUM', + ROOT_ITEM_KEY: 'ROOT_ITEM', + ROOT_BACKREF_KEY: 'ROOT_BACKREF', + ROOT_REF_KEY: 'ROOT_REF', + EXTENT_ITEM_KEY: 'EXTENT_ITEM', + METADATA_ITEM_KEY: 'METADATA_ITEM', + TREE_BLOCK_REF_KEY: 'TREE_BLOCK_REF', + EXTENT_DATA_REF_KEY: 'EXTENT_DATA_REF', + SHARED_BLOCK_REF_KEY: 'SHARED_BLOCK_REF', + SHARED_DATA_REF_KEY: 'SHARED_DATA_REF', + BLOCK_GROUP_ITEM_KEY: 'BLOCK_GROUP_ITEM', + FREE_SPACE_INFO_KEY: 'FREE_SPACE_INFO', + FREE_SPACE_EXTENT_KEY: 'FREE_SPACE_EXTENT', + FREE_SPACE_BITMAP_KEY: 'FREE_SPACE_BITMAP', + DEV_EXTENT_KEY: 'DEV_EXTENT', + DEV_ITEM_KEY: 'DEV_ITEM', + CHUNK_ITEM_KEY: 'CHUNK_ITEM', + QGROUP_STATUS_KEY: 'QGROUP_STATUS', + QGROUP_INFO_KEY: 'QGROUP_INFO', + QGROUP_LIMIT_KEY: 'QGROUP_LIMIT', + QGROUP_RELATION_KEY: 'QGROUP_RELATION', + BALANCE_ITEM_KEY: 'BALANCE_ITEM', + DEV_STATS_KEY: 'DEV_STATS', + DEV_REPLACE_KEY: 'DEV_REPLACE', + UUID_KEY_SUBVOL: 'UUID_SUBVOL', + UUID_KEY_RECEIVED_SUBVOL: 'RECEIVED_SUBVOL', + STRING_ITEM_KEY: 'STRING_ITEM', +} + +# === Helper functions + +def key_type_str(_type): + return _key_type_str_map.get(_type, str(_type)) + + +def key_offset_str(offset, _type): + if _type == QGROUP_RELATION_KEY or _type == QGROUP_INFO_KEY or _type == QGROUP_LIMIT_KEY: + return "{}/{}".format(qgroup_level(offset), qgroup_subvid(offset)) + if _type == UUID_KEY_SUBVOL or _type == UUID_KEY_RECEIVED_SUBVOL: + return "0x{:0>16x}".format(offset) + if _type == ROOT_ITEM_KEY: + return _key_objectid_str_map.get(offset, str(offset)) + if offset == ULLONG_MAX: + return '-1' + + return str(offset) + + +def flags_str(flags, flags_str_map): + ret = [] + for flag in sorted(flags_str_map.keys()): + if flags & flag: + ret.append(flags_str_map[flag]) + if len(ret) == 0: + ret.append("none") + return '|'.join(ret) + + +def embedded_text_for_str(text): + try: + return "utf-8 {}".format(text.decode('utf-8')) + except UnicodeDecodeError: + return "raw {}".format(repr(text)) + + +# === Basic structures + + +class TimeSpec(object): + sstruct = struct.Struct('<QL') + + @staticmethod + def from_values(sec, nsec): + t = TimeSpec.__new__(TimeSpec) + t.sec = sec + t.nsec = nsec + return t + + def __init__(self, data): + self.sec, self.nsec = TimeSpec.sstruct.unpack_from(data) + + @property + def iso8601(self): + return datetime.datetime.utcfromtimestamp( + float("{self.sec}.{self.nsec}".format(self=self)) + ).isoformat() + + def __str__(self): + return "{self.sec}.{self.nsec} ({self.iso8601})".format(self=self) + + +class Key(object): + def __init__(self, objectid, _type, offset): + self._objectid = objectid + self._type = _type + self._offset = offset + self._pack() + + @property + def objectid(self): + return self._objectid + + @objectid.setter + def objectid(self, _objectid): + self._objectid = _objectid + self._pack() + + @property + def type(self): + return self._type + + @type.setter + def type(self, _type): + self._type = _type + self._pack() + + @property + def offset(self): + return self._offset + + @offset.setter + def offset(self, _offset): + self._offset = _offset + self._pack() + + @property + def key(self): + return self._key + + @key.setter + def key(self, _key): + self._key = _key + self._unpack() + + def _pack(self): + self._key = (self.objectid << 72) + (self._type << 64) + self.offset + + def _unpack(self): + self._objectid = self._key >> 72 + self._type = (self._key & ((1 << 72) - 1)) >> 64 + self._offset = (self._key & ((1 << 64) - 1)) + + def __lt__(self, other): + if isinstance(other, Key): + return self._key < other._key + return self._key < other + + def __le__(self, other): + if isinstance(other, Key): + return self._key <= other._key + return self._key <= other + + def __eq__(self, other): + if isinstance(other, Key): + return self._key == other._key + return self._key == other + + def __ge__(self, other): + if isinstance(other, Key): + return self._key >= other._key + return self._key >= other + + def __gt__(self, other): + if isinstance(other, Key): + return self._key > other._key + return self._key > other + + def __str__(self): + return "({} {} {})".format( + key_objectid_str(self._objectid, self._type), + key_type_str(self._type), + key_offset_str(self._offset, self._type), + ) + + def __add__(self, amount): + new_key = copy.copy(self) + new_key.key += amount + return new_key + + def __sub__(self, amount): + new_key = copy.copy(self) + new_key.key -= amount + return new_key + +class DiskKey(Key): + sstruct = struct.Struct('<QBQ') + + def __init__(self, data): + super(DiskKey, self).__init__(*DiskKey.sstruct.unpack_from(data)) + +class InnerKey(Key): + sstruct = struct.Struct('<QBQQQ') + + def __init__(self, data): + unpacked_data = InnerKey.sstruct.unpack_from(data) + super().__init__(*unpacked_data[:3]) + self.block_num = unpacked_data[3] + self.generation = unpacked_data[4] + + def __str__(self): + return "(inner_key {} {} {} block_num {}, generation {})".format( + key_objectid_str(self._objectid, self._type), + key_type_str(self._type), + key_offset_str(self._offset, self._type), + self.block_num, + self.generation, + ) + +class LeafKey(Key): + sstruct = struct.Struct('<QBQLL') + + def __init__(self, data): + unpacked_data = LeafKey.sstruct.unpack_from(data) + super().__init__(*unpacked_data[:3]) + self.data_offset = unpacked_data[3] + self.data_size = unpacked_data[4] + + def __str__(self): + return "(leaf_key {} {} {} data_offset {:#x} data_size {})".format( + key_objectid_str(self._objectid, self._type), + key_type_str(self._type), + key_offset_str(self._offset, self._type), + self.data_offset, + self.data_size, + ) + +class ItemData(object): + def __init__(self, key): + self.key = key + + def setattr_from_key(self, objectid_attr=None, type_attr=None, offset_attr=None): + if objectid_attr is not None: + setattr(self, objectid_attr, self.key.objectid) + if type_attr is not None: + setattr(self, type_attr, self.key.type) + if offset_attr is not None: + setattr(self, offset_attr, self.key.offset) + self._key_attrs = objectid_attr, type_attr, offset_attr + + @property + def key_attrs(self): + try: + return self._key_attrs + except AttributeError: + return None, None, None + + def __lt__(self, other): + return self.key < other.key + + +superblock = struct.Struct('<32x16s2Q8s9Q5L4QH2B611x2048s') +# NOTE: the structure is not complete +# FS UUID +# Physical block address +# Flags +# Signature (_BHRfS_M) +# generation +# Log. address of root of tree roots +# Log. address of chunk tree root +# Log. address of log tree root +# log_root_transid +# total_bytes +# bytes_used +# root_dir_objectid (usually 6) +# num_devices +# sectorsize +# nodesize +# __unused_leafsize +# stripesize +# sys_chunk_array_size +# chunk_root_generation +# compat_flags +# compat_ro_flags +# incompat_flags +# csum_type +# root_level 23 +# chunk_root_level 24 +# --- +# sys_chunk_array + + +_node_header_struct = struct.Struct('<32x16sQQ16sQQLB') +NodeHeader = namedtuple('NodeHeader', 'FS_UUID node_addr flags chunk_tree_uuid generation tree_id items_num level') + +# === Items + +class InodeItem(ItemData): + _inode_item = [ + struct.Struct('<5Q4L3Q32x'), + TimeSpec.sstruct, + TimeSpec.sstruct, + TimeSpec.sstruct, + TimeSpec.sstruct, + ] + sstruct = struct.Struct('<' + ''.join([s.format[1:].decode() for s in _inode_item])) + + def __init__(self, key, data): + super().__init__(key) + self.generation, self.transid, self.size, self.nbytes, self.block_group, \ + self.nlink, self.uid, self.gid, self.mode, self.rdev, self.flags, self.sequence = \ + InodeItem._inode_item[0].unpack_from(data) + pos = InodeItem._inode_item[0].size + next_pos = pos + TimeSpec.sstruct.size + self.atime = TimeSpec(data[pos:next_pos]) + pos, next_pos = next_pos, next_pos + TimeSpec.sstruct.size + self.ctime = TimeSpec(data[pos:next_pos]) + pos, next_pos = next_pos, next_pos + TimeSpec.sstruct.size + self.mtime = TimeSpec(data[pos:next_pos]) + pos, next_pos = next_pos, next_pos + TimeSpec.sstruct.size + self.otime = TimeSpec(data[pos:next_pos]) + + @property + def flags_str(self): + return flags_str(self.flags, _inode_flags_str_map) + + def __str__(self): + return "inode generation {self.generation} transid {self.transid} size {self.size} " \ + "nbytes {self.nbytes} block_group {self.block_group} mode {self.mode:05o} " \ + "nlink {self.nlink} uid {self.uid} gid {self.gid} rdev {self.rdev} " \ + "flags {self.flags:#x}({self.flags_str})".format(self=self) + + +class RootItem(ItemData): + _root_item = [ + InodeItem.sstruct, + struct.Struct('<7QL'), + DiskKey.sstruct, + struct.Struct('<BBQ16s16s16s4Q'), + TimeSpec.sstruct, + TimeSpec.sstruct, + TimeSpec.sstruct, + TimeSpec.sstruct, + ] + sstruct = struct.Struct('<' + ''.join([s.format[1:].decode() for s in _root_item])) + + def __init__(self, key, data): + super().__init__(key) + self.inode = InodeItem(None, data[:InodeItem.sstruct.size]) + pos = InodeItem.sstruct.size + self.generation, self.dirid, self.bytenr, self.byte_limit, self.bytes_used, \ + self.last_snapshot, self.flags, self.refs = \ + RootItem._root_item[1].unpack_from(data, pos) + pos += RootItem._root_item[1].size + self.drop_progress = DiskKey(data[pos:pos+DiskKey.sstruct.size]) + pos += DiskKey.sstruct.size + self.drop_level, self.level, self.generation_v2, uuid_bytes, parent_uuid_bytes, \ + received_uuid_bytes, self.ctransid, self.otransid, self.stransid, self.rtransid = \ + RootItem._root_item[3].unpack_from(data, pos) + self.uuid = uuid.UUID(bytes=uuid_bytes) + self.parent_uuid = uuid.UUID(bytes=parent_uuid_bytes) + self.received_uuid = uuid.UUID(bytes=received_uuid_bytes) + pos += RootItem._root_item[3].size + next_pos = pos + TimeSpec.sstruct.size + self.ctime = TimeSpec(data[pos:next_pos]) + pos, next_pos = next_pos, next_pos + TimeSpec.sstruct.size + self.otime = TimeSpec(data[pos:next_pos]) + pos, next_pos = next_pos, next_pos + TimeSpec.sstruct.size + self.stime = TimeSpec(data[pos:next_pos]) + pos, next_pos = next_pos, next_pos + TimeSpec.sstruct.size + self.rtime = TimeSpec(data[pos:next_pos]) + + @property + def flags_str(self): + return flags_str(self.flags, _root_flags_str_map) + + def __str__(self): + return "root {self.key.objectid} uuid {self.uuid} " \ + "generation {self.generation} last_snapshot {self.last_snapshot} " \ + "bytenr {self.bytenr:#x} level {self.level} " \ + "flags {self.flags:#x}({self.flags_str})".format(self=self) + + +class Chunk(ItemData): + sstruct = struct.Struct('<4Q3L2H') + + def __init__(self, key, data): + super().__init__(key) + self.setattr_from_key(offset_attr='vaddr') + self.length, self.owner, self.stripe_len, self.type, self.io_align, \ + self.io_width, self.sector_size, self.num_stripes, self.sub_stripes = \ + Chunk.sstruct.unpack_from(data) + self.stripes = [] + pos = Chunk.sstruct.size + for i in range(self.num_stripes): + next_pos = pos + Stripe.sstruct.size + self.stripes.append(Stripe(data[pos:next_pos])) + pos = next_pos + + @property + def size(self): + return Chunk.sstruct.size + self.num_stripes * Stripe.sstruct.size + + @property + def type_str(self): + return flags_str(self.type, _block_group_flags_str_map) + + def __str__(self): + return "chunk vaddr {self.vaddr:#x} type {self.type_str} length {self.length} " \ + "num_stripes {self.num_stripes}".format(self=self) + + +class Stripe(object): + sstruct = struct.Struct('<2Q16s') + + def __init__(self, data): + self.devid, self.offset, uuid_bytes = Stripe.sstruct.unpack(data) + self.uuid = uuid.UUID(bytes=uuid_bytes) + + def __str__(self): + return "stripe devid {self.devid} offset {self.offset:#x}".format(self=self) + + +class InodeRefList(ItemData, collections.abc.MutableSequence): + def __init__(self, header, data): + super().__init__(header) + self._list = [] + pos = 0 + while pos < header.len: + inode_ref = InodeRef(data, pos) + self._list.append(inode_ref) + pos += len(inode_ref) + + def __getitem__(self, index): + return self._list[index] + + def __setitem__(self, index, value): + self._list[index] = value + + def __delitem__(self, index): + del self._list[index] + + def __len__(self): + return len(self._list) + + def insert(self, index, value): + self._list.insert(index, value) + + def __str__(self): + return "inode ref list size {}".format(len(self)) + + +class InodeRef(ItemData): + sstruct = struct.Struct('<QH') + + def __init__(self, key, data): + super().__init__(key) + self.index, self.name_len = InodeRef.sstruct.unpack_from(data) + self.name, = struct.Struct('<{}s'.format(self.name_len)).unpack_from(data, InodeRef.sstruct.size) + self._len = InodeRef.sstruct.size + self.name_len + + @property + def name_str(self): + return embedded_text_for_str(self.name) + + def __len__(self): + return self._len + + def __str__(self): + return "inode ref index {self.index} name {self.name_str}".format(self=self) + + +class DirItemList(ItemData, collections.abc.MutableSequence): + def __init__(self, key, data): + super().__init__(key) + self._list = [] + pos = 0 + while pos < key.data_size: + cls = {DIR_ITEM_KEY: DirItem, XATTR_ITEM_KEY: XAttrItem} + dir_item = cls[self.key.type](data, pos) + self._list.append(dir_item) + pos += len(dir_item) + + def __getitem__(self, index): + return self._list[index] + + def __setitem__(self, index, value): + self._list[index] = value + + def __delitem__(self, index): + del self._list[index] + + def __len__(self): + return len(self._list) + + def insert(self, index, value): + self._list.insert(index, value) + + def __str__(self): + return "dir item list hash {self.key.offset} size {}".format(len(self), self=self) + + +class XAttrItemList(DirItemList): + def __str__(self): + return "xattr item list hash {self.key.offset} size {}".format(len(self), self=self) + + +class DirItem(object): + _dir_item = [ + DiskKey.sstruct, + struct.Struct('<QHHB') + ] + sstruct = struct.Struct('<' + ''.join([s.format[1:].decode() for s in _dir_item])) + + def __init__(self, data, pos): + next_pos = pos + DiskKey.sstruct.size + self.location = DiskKey(data[pos:next_pos]) + pos = next_pos + self.transid, self.data_len, self.name_len, self.type = \ + DirItem._dir_item[1].unpack_from(data, pos) + pos += DirItem._dir_item[1].size + self.name, = struct.Struct('<{}s'.format(self.name_len)).unpack_from(data, pos) + pos += self.name_len + self.data, = struct.Struct('<{}s'.format(self.data_len)).unpack_from(data, pos) + pos += self.data_len + self._len = DirItem.sstruct.size + self.name_len + self.data_len + + @property + def type_str(self): + return _dir_item_type_str_map[self.type] + + @property + def name_str(self): + return embedded_text_for_str(self.name) + + @property + def data_str(self): + return embedded_text_for_str(self.data) + + def __len__(self): + return self._len + + def __str__(self): + return "dir item location {self.location} type {self.type_str} " \ + "name {self.name_str}".format(self=self) + + +class XAttrItem(DirItem): + def __str__(self): + return "xattr item name {self.name_str} data {self.data_str}".format(self=self) + + +class DirIndex(ItemData): + def __init__(self, header, data): + super().__init__(header) + self.location = DiskKey(data[:DiskKey.sstruct.size]) + pos = DiskKey.sstruct.size + self.transid, self.data_len, self.name_len, self.type = \ + DirItem._dir_item[1].unpack_from(data, pos) + pos += DirItem._dir_item[1].size + self.name, = struct.Struct('<{}s'.format(self.name_len)).unpack_from(data, pos) + + @property + def type_str(self): + return _dir_item_type_str_map[self.type] + + @property + def name_str(self): + return embedded_text_for_str(self.name) + + def __str__(self): + return "dir index {self.key.offset} location {self.location} type {self.type_str} " \ + "name {self.name_str}".format(self=self) + + +class FileExtentItem(ItemData): + _file_extent_item = [ + struct.Struct('<QQBB2xB'), + struct.Struct('<4Q'), + ] + sstruct = struct.Struct('<' + ''.join([s.format[1:].decode() + for s in _file_extent_item])) + + def __init__(self, key, data): + super().__init__(key) + self.logical_offset = key.offset + self.generation, self.ram_bytes, self.compression, self.encryption, self.type = \ + FileExtentItem._file_extent_item[0].unpack_from(data) + if self.type != FILE_EXTENT_INLINE: + # These are confusing, so they deserve a comment in the code: + # (disk_bytenr EXTENT_ITEM disk_num_bytes) is the tree key of + # the extent item storing the actual data. + # + # The third one, offset is the offset inside that extent where the + # data we need starts. num_bytes is the amount of bytes to be used + # from that offset onwards. + # + # Remember that these numbers always be multiples of disk block + # sizes, because that's how it gets cowed. We don't just use 1 or 2 + # bytes from another extent. + pos = FileExtentItem._file_extent_item[0].size + self.disk_bytenr, self.disk_num_bytes, self.offset, self.num_bytes = \ + FileExtentItem._file_extent_item[1].unpack_from(data, pos) + else: + self._inline_encoded_nbytes = key.data_size - FileExtentItem._file_extent_item[0].size + + @property + def compression_str(self): + return _compress_type_str_map.get(self.compression, 'unknown') + + @property + def type_str(self): + return _file_extent_type_str_map.get(self.type, 'unknown') + + def __str__(self): + ret = ["extent data at {self.logical_offset} generation {self.generation} " + "ram_bytes {self.ram_bytes} " + "compression {self.compression_str} type {self.type_str}".format(self=self)] + if self.type != FILE_EXTENT_INLINE: + ret.append("disk_bytenr {self.disk_bytenr} disk_num_bytes {self.disk_num_bytes} " + "offset {self.offset} num_bytes {self.num_bytes}".format(self=self)) + else: + ret.append("inline_encoded_nbytes {self._inline_encoded_nbytes}".format(self=self)) + return ' '.join(ret) + + +class ExtentItem(ItemData): + sstruct = struct.Struct('<3Q') + extent_inline_ref = struct.Struct('<BQ') + + def __init__(self, header, data, load_data_refs=True, load_metadata_refs=True): + super().__init__(header) + self.setattr_from_key(objectid_attr='vaddr', offset_attr='length') + pos = 0 + self.refs, self.generation, self.flags = ExtentItem.sstruct.unpack_from(data, pos) + pos += ExtentItem.sstruct.size + if self.flags == EXTENT_FLAG_DATA and load_data_refs: + self.extent_data_refs = [] + self.shared_data_refs = [] + while pos < len(data): + inline_ref_type, inline_ref_offset = \ + ExtentItem.extent_inline_ref.unpack_from(data, pos) + if inline_ref_type == EXTENT_DATA_REF_KEY: + pos += 1 + next_pos = pos + InlineExtentDataRef.sstruct.size + self.extent_data_refs.append(InlineExtentDataRef(data[pos:next_pos])) + pos = next_pos + elif inline_ref_type == SHARED_DATA_REF_KEY: + pos += 1 + next_pos = pos + InlineSharedDataRef.inline_shared_data_ref.size + self.shared_data_refs.append(InlineSharedDataRef(data[pos:next_pos])) + pos = next_pos + elif self.flags & EXTENT_FLAG_TREE_BLOCK and load_metadata_refs: + next_pos = pos + TreeBlockInfo.tree_block_info.size + self.tree_block_info = TreeBlockInfo(data[pos:next_pos]) + pos = next_pos + self.tree_block_refs = [] + self.shared_block_refs = [] + while pos < len(data): + inline_ref_type, inline_ref_offset = \ + ExtentItem.extent_inline_ref.unpack_from(data, pos) + if inline_ref_type == TREE_BLOCK_REF_KEY: + self.tree_block_refs.append(InlineTreeBlockRef(inline_ref_offset)) + elif inline_ref_type == SHARED_BLOCK_REF_KEY: + self.shared_block_refs.append(InlineSharedBlockRef(inline_ref_offset)) + else: + raise Exception("BUG: expected inline TREE_BLOCK_REF or SHARED_BLOCK_REF_KEY " + "but got inline_ref_type {}".format(inline_ref_type)) + pos += ExtentItem.extent_inline_ref.size + + def append_extent_data_ref(self, ref): + self.extent_data_refs.append(ref) + + def append_shared_data_ref(self, ref): + self.shared_data_refs.append(ref) + + def append_tree_block_ref(self, ref): + self.tree_block_refs.append(ref) + + def append_shared_block_ref(self, ref): + self.shared_block_refs.append(ref) + + @property + def flags_str(self): + return flags_str(self.flags, _extent_flags_str_map) + + def __str__(self): + return "extent vaddr {self.vaddr} length {self.length} refs {self.refs} " \ + "gen {self.generation} flags {self.flags_str}".format(self=self) + + +class ExtentDataRef(ItemData): + sstruct = struct.Struct('<3QL') + + def __init__(self, header, data): + super().__init__(header) + self.root, self.objectid, self.offset, self.count = \ + ExtentDataRef.sstruct.unpack(data) + + def __str__(self): + return "extent data backref root {self.root} objectid {self.objectid} " \ + "offset {self.offset} count {self.count}".format(self=self) + + +class InlineExtentDataRef(ExtentDataRef): + sstruct = ExtentDataRef.sstruct + + def __init__(self, data): + self.root, self.objectid, self.offset, self.count = \ + InlineExtentDataRef.sstruct.unpack(data) + + def __str__(self): + return "inline extent data backref root {self.root} objectid {self.objectid} " \ + "offset {self.offset} count {self.count}".format(self=self) + + +class SharedDataRef(ItemData): + sstruct = struct.Struct('<L') + + def __init__(self, header, data): + super().__init__(header) + self.setattr_from_key(offset_attr='parent') + self.count, = SharedDataRef.sstruct.unpack(data) + + def __str__(self): + return "shared data backref parent {self.parent} count {self.count}".format(self=self) + + +class InlineSharedDataRef(SharedDataRef): + sstruct = struct.Struct('<QL') + + def __init__(self, data): + self.parent, self.count = InlineSharedDataRef.sstruct.unpack(data) + + def __str__(self): + return "inline shared data backref parent {self.parent} " \ + "count {self.count}".format(self=self) + + +class TreeBlockInfo(object): + sstruct = struct.Struct('<QBQB') + + def __init__(self, data): + tb_objectid, tb_type, tb_offset, self.level = \ + TreeBlockInfo.sstruct.unpack(data) + self.key = Key(tb_objectid, tb_type, tb_offset) + + def __str__(self): + return "tree block key {self.key} level {self.level}".format(self=self) + +class TreeBlockRef(ItemData): + def __init__(self, header): + super().__init__(header) + self.setattr_from_key(offset_attr='root') + + def __str__(self): + return "tree block backref root {}".format(key_objectid_str(self.root, None)) + + +class InlineTreeBlockRef(TreeBlockRef): + def __init__(self, root): + self.root = root + + def __str__(self): + return "inline tree block backref root {}".format(key_objectid_str(self.root, None)) + + +class SharedBlockRef(ItemData): + def __init__(self, header): + super().__init__(header) + self.setattr_from_key(offset_attr='parent') + + def __str__(self): + return "shared block backref parent {}".format(self.parent) + + +class InlineSharedBlockRef(SharedBlockRef): + def __init__(self, parent): + self.parent = parent + + def __str__(self): + return "inline shared block backref parent {}".format(self.parent) + +# === Main FileSystem class + +def key_bin_search(fd, base_offset, item_size, cmp_item, min, max): + low = min + high = max + + while low < high: + mid = (low + high) // 2 + offset = base_offset + mid * item_size + + fd.seek(offset) + key1 = DiskKey(fd.read(item_size)) + if key1 > cmp_item: + high = mid + elif key1 < cmp_item: + low = mid + 1 + else: + return True, mid + + return False, low + + +chunk_map_item = namedtuple('chunk_map_item', 'logical physical length devid') + + +class FileSystem(object): + def __init__(self, path, part_offset): + self._chunk_map = OrderedDict() + self.path = path + self.part_offset = part_offset + self.fd = open(path, 'rb') + self.fd.seek(part_offset + 0x10000) # going to superblock + + sb_bytes = self.fd.read(superblock.size) + sb_tuple = superblock.unpack(sb_bytes) + + if sb_tuple[3] != b'_BHRfS_M': + raise "No signature found" + + # setting base FS information + self.fsid = sb_tuple[0] + self.nodesize = sb_tuple[14] + self.sectorsize = sb_tuple[13] + + self._chunk_root = sb_tuple[6] + self._chunk_root_level = sb_tuple[24] + self._tree_roots_root = sb_tuple[5] + self._tree_roots_root_level = sb_tuple[23] + + # setting chunk map + sys_chunk_array_size = sb_tuple[17] + sys_chunk = sb_tuple[25][:sys_chunk_array_size] + + pos = 0 + while pos < sys_chunk_array_size: + key = DiskKey(sys_chunk[pos:]) + pos += DiskKey.sstruct.size + chunk = Chunk(key, sys_chunk[pos:]) + for st in chunk.stripes: + self._insert_chunk(chunk_map_item(chunk.vaddr, st.offset, chunk.length, st.devid)) + pos += chunk.size + + # setting tree roots + _, fs_tree_root_item = self.search_tree(self._tree_roots_root_level, self._tree_roots_root, Key(FS_TREE_OBJECTID, ROOT_ITEM_KEY, 0)) + _, extent_tree_root_item = self.search_tree(self._tree_roots_root_level, self._tree_roots_root, Key(EXTENT_TREE_OBJECTID, ROOT_ITEM_KEY, 0)) + self._fs_root_level = fs_tree_root_item.level + self._fs_root = fs_tree_root_item.bytenr + self._extent_root_level = extent_tree_root_item.level + self._extent_root = extent_tree_root_item.bytenr + + @property + def chunk_root(self): + return self._chunk_root_level, self._chunk_root + + @property + def tree_roots_root(self): + return self._tree_roots_root_level, self._tree_roots_root + + @property + def fs_root(self): + return self._fs_root_level, self._fs_root + + @property + def extent_root(self): + return self._extent_root_level, self._extent_root + + def logical_to_physical(self, log): + cur_logical = next(iter(self._chunk_map)) # first item + + for logical, cmi in self._chunk_map.items(): + if logical > log: + break + cur_logical = logical + + # if there is no address in chunk_map, searching in chunk_tree + if cur_logical + self._chunk_map[cur_logical].length < log: + def process_func(header, offset): + for i in range(header.items_num): + self.fd.seek(offset + i * LeafKey.sstruct.size) + k = LeafKey(self.fd.read(LeafKey.sstruct.size)) + self.fd.seek(offset + k.data_offset) + if k.type == CHUNK_ITEM_KEY: + item = _key_type_class_map[k.type](k, self.fd.read(k.data_size)) + for st in item.stripes: + self._insert_chunk(chunk_map_item(item.vaddr, st.offset, item.length, st.devid)) + + self.search_tree(self._chunk_root_level, self._chunk_root, Key(FIRST_CHUNK_TREE_OBJECTID, CHUNK_ITEM_KEY, log), process_func) + + cur_logical = next(iter(self._chunk_map)) # first item + if cur_logical > log: + raise Exception(f'Cannot translate address {log:#x}') + + for logical, cmi in self._chunk_map.items(): + if logical > log: + break + cur_logical = logical + + if cur_logical + self._chunk_map[cur_logical].length < log: + raise Exception(f'Cannot translate address {log:#x}') + + print('address translation: {:#x} -> {:#x}'.format(log, self._chunk_map[cur_logical].physical + log - cur_logical)) + return self.part_offset + self._chunk_map[cur_logical].physical + log - cur_logical + + def search_tree(self, level, root_offset, key, process_node_func = None): + for lvl in range(level, 0, -1): + # inner node + root_offset = self.logical_to_physical(root_offset) + self.fd.seek(root_offset) + header = NodeHeader._make(_node_header_struct.unpack(self.fd.read(_node_header_struct.size))) + if header.level != lvl: + raise Exception('Invalid inner node level') + + found, itemnr = key_bin_search( + self.fd, + root_offset + _node_header_struct.size, + InnerKey.sstruct.size, + key, + 0, + header.items_num + ) + + # TODO: better understand this + if not found and itemnr > 0: + itemnr -= 1 + + self.fd.seek(root_offset + _node_header_struct.size + itemnr * InnerKey.sstruct.size) + k = InnerKey(self.fd.read(InnerKey.sstruct.size)) + root_offset = k.block_num + else: + # we are in leaf node + root_offset = self.logical_to_physical(root_offset) + self.fd.seek(root_offset) + header = NodeHeader._make(_node_header_struct.unpack(self.fd.read(_node_header_struct.size))) + if header.level != 0: + raise Exception('Invalid leaf level') + + if process_node_func: + process_node_func(header, root_offset + _node_header_struct.size) + return root_offset + + found, itemnr = key_bin_search( + self.fd, + root_offset + _node_header_struct.size, + LeafKey.sstruct.size, + key, + 0, + header.items_num + ) + + self.fd.seek(root_offset + _node_header_struct.size + itemnr * LeafKey.sstruct.size) + k = LeafKey(self.fd.read(LeafKey.sstruct.size)) + self.fd.seek(root_offset + _node_header_struct.size + k.data_offset) + + if k.type in _key_type_class_map: + return k, _key_type_class_map[k.type](k, self.fd.read(k.data_size)) + else: + return k, False + + def print_node(self, header, offset): + print(header) + root_paddr = self.logical_to_physical(header.node_addr) + key_size = InnerKey.sstruct.size if header.level > 0 else LeafKey.sstruct.size + key_struct = InnerKey if header.level > 0 else LeafKey + for i in range(header.items_num): + self.fd.seek(root_paddr + _node_header_struct.size + i * key_size) + k = key_struct(self.fd.read(key_size)) + print(k) + self.fd.seek(root_paddr + _node_header_struct.size + k.data_offset) + if k.type in _key_type_class_map and header.level == 0: + item = _key_type_class_map[k.type](k, self.fd.read(k.data_size)) + print(item) + if k.type == DIR_ITEM_KEY: + for it in item: + print(it) + print('============================') + + def print_chunk_map(self): + print('=== chunk map ===') + for logical, cmi in self._chunk_map.items(): + print(f'{cmi.logical:#x}..{cmi.logical+cmi.length:#x} -> {cmi.physical:#x}..{cmi.physical+cmi.length:#x}') + print('=================') + + def _insert_chunk(self, chunk): + if not chunk.logical in self._chunk_map: + cm = dict(self._chunk_map) + cm[chunk.logical] = chunk + self._chunk_map = OrderedDict(sorted(cm.items())) + + +_key_type_class_map = { + INODE_ITEM_KEY: InodeItem, + INODE_REF_KEY: InodeRef, + DIR_ITEM_KEY: DirItemList, + DIR_INDEX_KEY: DirIndex, + EXTENT_DATA_KEY: FileExtentItem, + ROOT_ITEM_KEY: RootItem, + EXTENT_ITEM_KEY: ExtentItem, + CHUNK_ITEM_KEY: Chunk, +} diff --git a/modules/rosapps/applications/devutils/btrfstools/crc32c.py b/modules/rosapps/applications/devutils/btrfstools/crc32c.py new file mode 100644 index 0000000000..0bb00dc828 --- /dev/null +++ b/modules/rosapps/applications/devutils/btrfstools/crc32c.py @@ -0,0 +1,105 @@ +# Copyright (C) 2017 Hans van Kranenburg <hans(a)knorrie.org> +# +# This file is part of the python-btrfs module. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public +# License v2 as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +table = ( + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, + 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, + 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, + 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, + 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, + 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, + 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, + 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, + 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, + 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, + 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, + 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, + 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, + 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, + 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, + 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, + 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, + 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, + 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, + 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, + 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, + 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351, +) + + +def crc32c(crc, data): + if not isinstance(data, (bytes, bytearray)): + data = bytes(data, 'utf-8') + crc = crc & 0xffffffff + for char in data: + crc = table[(crc ^ char) & 0xff] ^ (crc >> 8) + return crc & 0xffffffff + + +def crc32c_data(data): + return 0xffffffff ^ crc32c(~0, data) + + +def name_hash(name): + return crc32c(~1, name) + + +def extref_hash(parent_objectid, name): + return crc32c(parent_objectid, name)
6 years, 4 months
1
0
0
0
03/04: [BTRFS] Applied upstream pull-requests before they are merged
by Victor Perevertkin
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0e61b570e78c7490d36ae…
commit 0e61b570e78c7490d36ae2dc573e6af9c1b226d2 Author: Victor Perevertkin <victor(a)perevertkin.ru> AuthorDate: Sun Aug 12 19:31:15 2018 +0300 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Mon Aug 20 08:26:56 2018 +0200 [BTRFS] Applied upstream pull-requests before they are merged --- drivers/filesystems/btrfs/btrfs.c | 69 +++++++++++++++++++++++++++++++++++++ drivers/filesystems/btrfs/dirctrl.c | 4 +++ 2 files changed, 73 insertions(+) diff --git a/drivers/filesystems/btrfs/btrfs.c b/drivers/filesystems/btrfs/btrfs.c index c4960cd421..05db8c0e29 100644 --- a/drivers/filesystems/btrfs/btrfs.c +++ b/drivers/filesystems/btrfs/btrfs.c @@ -4892,6 +4892,9 @@ static NTSTATUS drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { NTSTATUS Status; BOOL top_level; device_extension* Vcb = DeviceObject->DeviceExtension; +#ifdef __REACTOS__ + LIST_ENTRY *Vcble, *le; +#endif FsRtlEnterFileSystem(); @@ -4909,6 +4912,7 @@ static NTSTATUS drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { shutting_down = TRUE; KeSetEvent(&mountmgr_thread_event, 0, FALSE); +#ifndef __REACTOS__ while (!IsListEmpty(&VcbList)) { Vcb = CONTAINING_RECORD(VcbList.Flink, device_extension, list_entry); @@ -4916,6 +4920,71 @@ static NTSTATUS drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { uninit(Vcb, TRUE); } +#else + Vcble = VcbList.Flink; + while (Vcble != &VcbList) { + Vcb = CONTAINING_RECORD(Vcble, device_extension, list_entry); + + TRACE("shutting down Vcb %p\n", Vcb); + + if (Vcb->balance.thread) { + Vcb->balance.paused = FALSE; + Vcb->balance.stopping = TRUE; + KeSetEvent(&Vcb->balance.event, 0, FALSE); + KeWaitForSingleObject(&Vcb->balance.finished, Executive, KernelMode, FALSE, NULL); + } + + if (Vcb->scrub.thread) { + Vcb->scrub.paused = FALSE; + Vcb->scrub.stopping = TRUE; + KeSetEvent(&Vcb->scrub.event, 0, FALSE); + KeWaitForSingleObject(&Vcb->scrub.finished, Executive, KernelMode, FALSE, NULL); + } + + if (Vcb->running_sends != 0) { + BOOL send_cancelled = FALSE; + + ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE); + + le = Vcb->send_ops.Flink; + while (le != &Vcb->send_ops) { + send_info* send = CONTAINING_RECORD(le, send_info, list_entry); + + if (!send->cancelling) { + send->cancelling = TRUE; + send_cancelled = TRUE; + send->ccb = NULL; + KeSetEvent(&send->cleared_event, 0, FALSE); + } + + le = le->Flink; + } + + ExReleaseResourceLite(&Vcb->send_load_lock); + + if (send_cancelled) { + while (Vcb->running_sends != 0) { + ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE); + ExReleaseResourceLite(&Vcb->send_load_lock); + } + } + } + + ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); + + if (Vcb->need_write && !Vcb->readonly) { + Status = do_write(Vcb, Irp); + + if (!NT_SUCCESS(Status)) + ERR("do_write returned %08x\n", Status); + } + + Vcb->removing = TRUE; + + ExReleaseResourceLite(&Vcb->tree_lock); + Vcble = Vcble->Flink; + } +#endif #ifdef _DEBUG if (comfo) { diff --git a/drivers/filesystems/btrfs/dirctrl.c b/drivers/filesystems/btrfs/dirctrl.c index 0ae95d636c..25c9e9cc83 100644 --- a/drivers/filesystems/btrfs/dirctrl.c +++ b/drivers/filesystems/btrfs/dirctrl.c @@ -675,7 +675,11 @@ static NTSTATUS query_directory(PIRP Irp) { if (IrpSp->Parameters.QueryDirectory.FileName && IrpSp->Parameters.QueryDirectory.FileName->Length > 1) { TRACE("QD filename: %.*S\n", IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR), IrpSp->Parameters.QueryDirectory.FileName->Buffer); +#ifndef __REACTOS__ if (IrpSp->Parameters.QueryDirectory.FileName->Buffer[0] != '*') { +#else + if (IrpSp->Parameters.QueryDirectory.FileName->Length > sizeof(WCHAR) || IrpSp->Parameters.QueryDirectory.FileName->Buffer[0] != L'*') { +#endif specific_file = TRUE; if (FsRtlDoesNameContainWildCards(IrpSp->Parameters.QueryDirectory.FileName)) {
6 years, 4 months
1
0
0
0
02/04: [FREELDR][BTRFS] Implemented BTRFS support in Free Loader. Now it supports case-insensitive path lookup, symlink folowing and reading uncompressed files. Volume boot record is also implemented, it supports reading BTRFS tree structures with upto 64k node size. This support required to change all path in Free Loader to lowercase for better performance. CORE-13769
by Victor Perevertkin
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3b69eee7a65fc7b768b5a…
commit 3b69eee7a65fc7b768b5a92cbf5955f1e6f79068 Author: Victor Perevertkin <victor(a)perevertkin.ru> AuthorDate: Tue Jun 19 04:00:52 2018 +0300 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Mon Aug 20 08:26:56 2018 +0200 [FREELDR][BTRFS] Implemented BTRFS support in Free Loader. Now it supports case-insensitive path lookup, symlink folowing and reading uncompressed files. Volume boot record is also implemented, it supports reading BTRFS tree structures with upto 64k node size. This support required to change all path in Free Loader to lowercase for better performance. CORE-13769 --- boot/freeldr/bootsect/CMakeLists.txt | 2 + boot/freeldr/bootsect/btrfs.S | 773 ++++++++++++++++++ boot/freeldr/freeldr/CMakeLists.txt | 1 + boot/freeldr/freeldr/arch/i386/hwdisk.c | 2 +- boot/freeldr/freeldr/include/freeldr.h | 1 + boot/freeldr/freeldr/include/fs/btrfs.h | 418 ++++++++++ boot/freeldr/freeldr/include/fs/crc32c.h | 52 ++ boot/freeldr/freeldr/lib/fs/btrfs.c | 1283 ++++++++++++++++++++++++++++++ boot/freeldr/freeldr/lib/fs/fs.c | 2 + boot/freeldr/freeldr/ntldr/winldr.c | 12 +- boot/freeldr/freeldr/ntldr/wlregistry.c | 4 +- 11 files changed, 2541 insertions(+), 9 deletions(-) diff --git a/boot/freeldr/bootsect/CMakeLists.txt b/boot/freeldr/bootsect/CMakeLists.txt index f76ac7a95b..ddcbf96801 100644 --- a/boot/freeldr/bootsect/CMakeLists.txt +++ b/boot/freeldr/bootsect/CMakeLists.txt @@ -6,6 +6,7 @@ if(ARCH STREQUAL "i386" OR ARCH STREQUAL "amd64") CreateBootSectorTarget(fat ${CMAKE_CURRENT_SOURCE_DIR}/fat.S ${CMAKE_CURRENT_BINARY_DIR}/fat.bin 7c00) CreateBootSectorTarget(fat32 ${CMAKE_CURRENT_SOURCE_DIR}/fat32.S ${CMAKE_CURRENT_BINARY_DIR}/fat32.bin 7c00) + CreateBootSectorTarget(btrfsvbr ${CMAKE_CURRENT_SOURCE_DIR}/btrfs.S ${CMAKE_CURRENT_BINARY_DIR}/btrfs.bin 7c00) ## New versions using FATY.S (experimental) # add_definitions(-DFAT12) @@ -24,6 +25,7 @@ if(ARCH STREQUAL "i386" OR ARCH STREQUAL "amd64") add_cd_file(TARGET dosmbr DESTINATION loader NO_CAB FILE ${CMAKE_CURRENT_BINARY_DIR}/dosmbr.bin FOR bootcd regtest) add_cd_file(TARGET ext2 DESTINATION loader NO_CAB FILE ${CMAKE_CURRENT_BINARY_DIR}/ext2.bin FOR bootcd regtest) + add_cd_file(TARGET btrfsvbr DESTINATION loader NO_CAB FILE ${CMAKE_CURRENT_BINARY_DIR}/btrfs.bin FOR bootcd regtest) add_cd_file(TARGET fat DESTINATION loader NO_CAB FILE ${CMAKE_CURRENT_BINARY_DIR}/fat.bin FOR bootcd regtest) add_cd_file(TARGET fat32 DESTINATION loader NO_CAB FILE ${CMAKE_CURRENT_BINARY_DIR}/fat32.bin FOR bootcd regtest) add_cd_file(TARGET isoboot DESTINATION loader NO_CAB NOT_IN_HYBRIDCD FILE ${CMAKE_CURRENT_BINARY_DIR}/isoboot.bin FOR all hybridcd) diff --git a/boot/freeldr/bootsect/btrfs.S b/boot/freeldr/bootsect/btrfs.S new file mode 100644 index 0000000000..7e1ffa16ea --- /dev/null +++ b/boot/freeldr/bootsect/btrfs.S @@ -0,0 +1,773 @@ +/* + * PROJECT: FreeLoader + * LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+
) + * PURPOSE: BTRFS volume boot sector for FreeLoader + * COPYRIGHT: Copyright 2018 Victor Perevertkin (victor(a)perevertkin.ru) + */ + +#include <asm.inc> +#include <freeldr/include/arch/pc/x86common.h> + +.code16 + +CHUNK_MAP_OFFSET = HEX(8200) // max - 256 chunks (chunk is 24 bytes) +DATA_BUFFER_SEGMENT = HEX(9a0) // here we will store FS structures read from disk + +FIRST_SUPERBLOCK_OFFSET = HEX(80) //in sectors + +ROOT_TREE_OBJECTID = 1 +EXTENT_TREE_OBJECTID = 2 +CHUNK_TREE_OBJECTID = 3 +DEV_TREE_OBJECTID = 4 +FS_TREE_OBJECTID = 5 +FIRST_CHUNK_TREE_OBJECTID = 256 + +DIR_ITEM_KEY = 84 +EXTENT_DATA_KEY = 108 +ROOT_ITEM_KEY = 132 +EXTENT_ITEM_KEY = 168 +CHUNK_ITEM_KEY = 228 + +BTRFS_FT_REG_FILE = 1 + +KEY_SIZE = 17 +MAX_CHUNK_ITEMS = 255 + +start: + jmp short main + nop +// globals +ChunkMapSize: + .byte 0 +BootDrive: + .byte 0 +PartitionStartLBA: + .quad HEX(3f) // default value. Setup tool have to overwrite it upon installation + +TreeRootAddress: + .quad 0 +ChunkRootAddress: + .quad 0 +FsRootAddress: + .quad 0 + +NodeSize: + .long 0 +LeafSize: + .long 0 +StripeSize: + .long 0 +SysChunkSize: + .long 0 + +TreeRootLevel: + .byte 0 +ChunkRootLevel: + .byte 0 +FsRootLevel: + .byte 0 + +main: + xor eax, eax // Setup segment registers + mov ds, ax // Make DS correct + mov es, ax // Make ES correct + mov ss, ax // Make SS correct + mov sp, HEX(7c00) // Setup a stack + mov bp, sp + + mov byte ptr [BootDrive], dl + +// Now check if this computer supports extended reads. This boot sector will not work without it +CheckInt13hExtensions: + mov ah, HEX(41) // AH = 41h + mov bx, HEX(55aa) // BX = 55AAh + int HEX(13) // IBM/MS INT 13 Extensions - INSTALLATION CHECK + jc PrintDiskError // CF set on error (extensions not supported) + cmp bx, HEX(aa55) // BX = AA55h if installed + jne PrintDiskError + test cl, 1 // si = API subset support bitmap + jz PrintDiskError // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported + +LoadExtraBootCode: + // First we have to load our extra boot code into into memory at [0000:7e00h] + xor edx, edx + mov eax, 1 // read from the second sector - the first was already read + mov cx, 2 + mov bx, HEX(7e00) // Read sector to [0000:7e00h] + call ReadSectors + + mov ax, DATA_BUFFER_SEGMENT + mov es, ax + +// reading superblock + xor edx, edx + mov eax, FIRST_SUPERBLOCK_OFFSET + mov cx, 8 // superblock is 0x1000 bytes - 8 sectors + xor bx, bx + call ReadSectors + + push es // swapping segments for memory operations with superblock + push ds // ds must be DATA_BUFFER_SEGMENT + pop es + pop ds + + mov si, HEX(40) + lea di, [btrfsSignature] + mov cx, 4 // magic string size (words) + repe cmpsw + je SignatureOk + + mov si, wrongSignatureError + call PrintCustomError + +SignatureOk: +// signature is ok - reading superblock data + add si, 8 // logical address of the root tree root + lea di, [TreeRootAddress] + mov cx, 8 // read both root tree root and chunk tree root + rep movsw +// read sizes + add si, HEX(34) // now pointing to nodesize field + lea di, [NodeSize] // read all 4 values + mov cx, 8 + rep movsw +// read both levels + add si, 34 + movsw // di is on the right place + + push es + push ds + pop es + pop ds + +// read sys chunk array + mov ax, HEX(32b) // sys_chunk_start +ReadSysChunk: + mov bx, ax + add bx, KEY_SIZE + push bx // start of the chunk + call InsertChunk + + pop si + mov bx, word ptr es:[si+44] // number of stripes + shl bx, 5 // one stripe entry is 32 bytes + lea si, [si+bx+48] // 48 - size of the chunk + mov ax, si // save for next iteration + sub si, HEX(32b) + cmp si, word ptr [SysChunkSize] // the size cannot be more than 0xFFFF here so use word ptr + jb ReadSysChunk + + jmp SetTreeRoots + + +// Reads logical sectors from disk +// INPUT: +// - ES:[BX] address at which the data will be stored +// - EDX:EAX logical sector number from which to read +// - CX number of sectors to read +// OUTPUT: +// - 512*CX bytes of memory at ES:[BX] +// LOCALS: +// - [bp-2] - LBASectorsRead +ReadSectors: + push bp + mov bp, sp + sub sp, 2 + push es // we will spoil es register here + + add eax, dword ptr [PartitionStartLBA] + adc edx, dword ptr [PartitionStartLBA+4] +ReadSectors_loop: + pushad // Save logical sector number & sector count + + cmp cx, 8 // Maximum sectors per call is 0x7F, but VirtualBox correctly works with only 8 + jbe ReadSectorsSetupDiskAddressPacket // If we are reading less than 9 sectors then just do the read + mov cx, 8 // Otherwise read only 8 sectors on this loop iteration + +ReadSectorsSetupDiskAddressPacket: + mov word ptr [bp-2], cx + push edx + push eax // Put 64-bit logical block address on stack + push es // Put transfer segment on stack + push bx // Put transfer offset on stack + push cx // Set transfer count + push 16 // Set size of packet to 10h + mov si, sp // Setup disk address packet on stack + + mov dl, byte ptr [BootDrive] // Drive number + mov ah, HEX(42) // Int 13h, AH = 42h - Extended Read + int HEX(13) // Call BIOS + jc PrintDiskError // If the read failed then abort + + add sp, 16 // Remove disk address packet from stack + + popad // Restore sector count & logical sector number + + push bx + movzx ebx, word ptr [bp-2] + add eax, ebx // Increment sector to read + adc edx, 0 + shl ebx, 5 // Multiplying by 512=2^9 here. + // Shifting only by 5, because it goes to segment + // (segment will be shifter by another 4 when converted to real addr) + mov si, es + add si, bx // Setup read buffer for next sector + mov es, si + pop bx + + sub cx, word ptr [bp-2] + jnz ReadSectors_loop // Read next sector + + pop es + leave + ret + +// Displays a disk error message +// And reboots +PrintDiskError: + mov si, msgDiskError // Bad boot disk message +PrintCustomError: + call PutChars // Display it + +Reboot: + lea si, [msgAnyKey] // Press any key message + call PutChars // Display it + xor ax,ax + int HEX(16) // Wait for a keypress + int HEX(19) // Reboot + +PutChars: + lodsb + or al,al + jz short Done + call PutCharsCallBios + jmp short PutChars +PutCharsCallBios: + mov ah, HEX(0e) + mov bx, HEX(07) + int HEX(10) + ret +Done: + mov al, HEX(0d) + call PutCharsCallBios + mov al, HEX(0a) + call PutCharsCallBios + ret + + +msgDiskError: + .asciz "Disk error" +msgAnyKey: + .asciz "Press any key to restart" + +.org 510 + .word HEX(aa55) // BootSector signature + +SetTreeRoots: + // converting sizes to sectors. We dont need this sizes in bytes + shr dword ptr [NodeSize], 9 + shr dword ptr [LeafSize], 9 // leafsize is deprecated + + // finding FS_TREE root + + // put the key on stack + xor eax, eax + push eax + push eax + dec sp + mov byte ptr [esp], ROOT_ITEM_KEY + push eax + push 0 + push FS_TREE_OBJECTID + + mov eax, dword ptr [TreeRootAddress] + mov edx, dword ptr [TreeRootAddress+4] + mov cl, byte ptr [TreeRootLevel] + + call SearchTree + add sp, 17 // setting stack back + + // bx - pointer to ROOT_ITEM + mov al, byte ptr es:[bx+238] // moving level + mov byte ptr [FsRootLevel], al + cld + + mov eax, dword ptr es:[bx+176] + mov dword ptr [FsRootAddress], eax + mov eax, dword ptr es:[bx+176+4] + mov dword ptr [FsRootAddress+4], eax + + // now we need to find DIR_ITEM_KEY with freeldr.sys hash + xor eax, eax + push eax + push dword ptr [filenameCrc] + dec sp + mov byte ptr [esp], DIR_ITEM_KEY + push eax + push 0 + push 256 // root dir objectid + + mov eax, dword ptr [FsRootAddress] + mov edx, dword ptr [FsRootAddress+4] + mov cl, byte ptr [FsRootLevel] + + call SearchTree + add sp, 17 // setting stack back + + // parsing DIR_ITEM + // bx - item addr + // cx - item length + mov ax, cx + + push ds + push es + pop ds + pop es +ParseDirItem_loop: + cmp byte ptr [bx+29], BTRFS_FT_REG_FILE // checking dir_item type + jne ParseDirItem_loop_2 + cmp word ptr [bx+27], 11 // checking name length + jne ParseDirItem_loop_2 + lea si, [bx+30] + lea di, [freeldrFilename] + mov cx, 11 + repe cmpsb + je FreeLdrFound + +ParseDirItem_loop_2: + mov dx, 30 + add dx, word ptr [bx+27] + cmp dx, ax + jae FreeLdrNotFound + add bx, dx + jmp ParseDirItem_loop + +FreeLdrNotFound: + lea si, [notFoundError] + call PrintCustomError + +FreeLdrFound: + // freeldr objectid is the first qword of DIR_ITEM structure + xor eax, eax + push eax + push eax + dec sp + mov byte ptr [esp], EXTENT_DATA_KEY + push dword ptr [bx+4] + push dword ptr [bx] + + push es + pop ds + + mov eax, dword ptr [FsRootAddress] + mov edx, dword ptr [FsRootAddress+4] + mov cl, byte ptr [FsRootLevel] + + call SearchTree + add sp, 17 + + // here we have an EXTENT_ITEM with freeldr.sys + mov eax, dword ptr es:[bx+29] + shr eax, 9 // getting the number of clusters + mov cx, ax + push cx + + lea di, [bx+21] + call ConvertAddress + pop cx + + xor bx, bx + mov ds, bx + mov es, bx + mov bx, FREELDR_BASE + call ReadSectors + + mov dl, byte ptr [BootDrive] // Load boot drive into DL + //mov dh, 0 // Load boot partition into DH (not needed, FreeLbr detects it itself) + + /* Transfer execution to the bootloader */ + ljmp16 0, FREELDR_BASE + + +// Insert chunk into chunk map (located at DS:[CHUNK_MAP_OFFSET]) +// INPUT: +// - ES:[AX] chunk key address +// - ES:[BX] chunk item address +// TODO: add max items checking +InsertChunk: + push bx + push ax + push es + + xor ecx, ecx // index +InsertChunk_loop: + std // numbers are little-engian, going right-to-left + mov si, CHUNK_MAP_OFFSET + lea si, [esi+ecx*8] + lea si, [esi+ecx*8] + lea si, [esi+ecx*8] // shift by 24 bytes + + inc cx + cmp cl, byte ptr [ChunkMapSize] + ja InsertChunk_insert + + lea si, [si+4] // set to the high dword of the 8-byte number + lea di, [eax+KEY_SIZE-4] // set to high dword of key's offset field (offset=logical addr) + + cmpsd + jb InsertChunk_loop + cmpsd + jb InsertChunk_loop + lea si, [si+4] // set back to the beginning of key + + // numbers are greater - need to insert Here + // shifting all to right by one element +InsertChunk_insert: + push si // here we will store new chunk + dec cx // because we increased it before comparison + + mov dx, ds + mov es, dx + + movzx eax, byte ptr [ChunkMapSize] // number of elements + + mov si, CHUNK_MAP_OFFSET + lea si, [esi+eax*8] + lea si, [esi+eax*8] + lea si, [esi+eax*8-4] // setting to the high dword of the last element + + mov di, si + add di, 20 // last byte of the last + 1 element (-4 bytes) + + sub ax, cx + mov bx, 6 + mul bx // 24/4 because of dwords + mov cx, ax // number of elements to shift + rep movsd + + // finally we can write the element + cld + pop di // here we will store new chunk + + pop ds // key-to-insert address segment + pop si // key-to-insert address + add si, 9 // move to 'offset' field + movsd + movsd // logical address loaded! + + // time for stripes + pop si // chunk item address, length is the first field + movsd + movsd + + add si, 48 // move to offset of the first stripe (we read only first one) + movsd + movsd + + push es // swapping segments back to original + push ds + pop es + pop ds + + inc byte ptr [ChunkMapSize] + ret + + +// Searches a key in a BTRFS tree +// INPUT: +// - [bp+4] BTRFS key to find +// - EDX:EAX logical address of root header +// - CL leaf node level +// OUTPUT: +// - ES:[SI] pointer to found item's key +// - ES:[BX] pointer to found item +// - ECX item length +// LOCALS: +// - [bp-8] - block number/current node offset +// - [bp-9] - current level +SearchTree: + push bp + mov bp, sp + sub sp, 9 // set stack frame + + mov dword ptr [bp-4], edx + mov dword ptr [bp-8], eax + mov byte ptr [bp-9], cl + +SearchTree_readHeader: + push ss + pop es + + lea di, [bp-8] + call ConvertAddress + // LBA is in edx:eax now + mov bx, DATA_BUFFER_SEGMENT + mov es, bx + xor bx, bx + + mov cl, byte ptr [bp-9] + test cl, cl + jz SearchTree_readLeaf +// read node + mov cx, word ptr [NodeSize] // word btr because we cannot read more than 65536 bytes yet + call ReadSectors // reading node to the memory + + // every node begins with header + //mov ax, word ptr [DATA_BUFFER_OFFSET + HEX(60)] // number of items in this leaf + mov cx, -1 // index + // finding the key +SearchTree_findLoop_1: + inc cx + cmp word ptr es:[HEX(60)], cx + je SearchTree_findLoop_1_equal // we are at the end - taking the last element + + lea si, [bp+4] // key to find + mov di, HEX(65) // first key in leaf + mov ax, 33 + call CompareKeys + jb SearchTree_findLoop_1 + je SearchTree_findLoop_1_equal + sub di, 33 // setting to previous element + + // we are here if key is equal or greater + // (si points to the start of the key) +SearchTree_findLoop_1_equal: + push ds + push es + pop ds + pop es + + lea si, [di+17] + lea di, [bp-8] + movsd + movsd + + push es + pop ds + + dec byte ptr [bp-9] // decrement level + jmp SearchTree_readHeader + +SearchTree_readLeaf: + mov cx, word ptr [LeafSize] + call ReadSectors + + // every node begins with header + //mov ax, word ptr [DATA_BUFFER_OFFSET + HEX(60)] // number of items in this leaf + mov cx, -1 // index + // finding the key +SearchTree_findLoop_2: + inc cx + cmp word ptr es:[HEX(60)], cx + je SearchTree_foundEqual + + lea si, [bp+4] // key to find + mov di, HEX(65) // first key in leaf + mov ax, 25 + call CompareKeys + jb SearchTree_findLoop_2 + je SearchTree_foundEqual + + // set pointer to previous element if greater + sub di, 25 + +SearchTree_foundEqual: + // found equal or greater key + mov bx, word ptr es:[di+17] // data offset relative to end of header + mov cx, word ptr es:[di+21] // data size + add bx, HEX(65) // end of header + mov si, di + + leave + ret + +SearchTree_notFound: + xor ecx, ecx // return ecx=0 if nothing found + + leave + ret + + +// Converts logical address into physical LBA addr using chunk map +// INPUT: +// - ES:[DI] pointer to logical addr +// OUTPUT: +// - EDX:EAX target LBA +// - sets ZF on failure +ConvertAddress: + // NOTE: SearchTree will overwrite data buffer area and our logical addr will be erased! + // so putting it on stack + push dword ptr es:[di+4] + push dword ptr es:[di] + + mov bl, 1 // indicates first try. On second try BL must be set to 0 +ConvertAddress_secondTry: + push ds + pop es + xor ecx, ecx // set index to 0 +ConvertAddress_loop: + cmp cl, byte ptr [ChunkMapSize] + jae ConvertAddress_checkInclusion // greater chunk is not found in chunk map - checking the last one + + std // numbers are little-engian, going right-to-left + mov si, CHUNK_MAP_OFFSET + lea si, [esi+ecx*8] + lea si, [esi+ecx*8] + lea si, [esi+ecx*8] // shift by 24 bytes + + lea di, [esp+4] // set to the second dword the 8-byte number + lea si, [si+4] + inc cl + + cmpsd + jb ConvertAddress_loop + cmpsd + jb ConvertAddress_loop + +ConvertAddress_checkInclusion: + dec cl + cld + // found chunk map item, checking inclusion with length + mov si, CHUNK_MAP_OFFSET + lea si, [esi+ecx*8] + lea si, [esi+ecx*8] + lea si, [esi+ecx*8] // shift by 24 bytes + + // logical_addr + length + mov eax, dword ptr [si] // low dword of address + mov edx, dword ptr [si+4] // high dword of address + add eax, dword ptr [si+8] // low dword of length + adc edx, dword ptr [si+12] // high dword of length + // edx:eax is the end of the chunk + + // (logical_addr + length) - addr_to_find + cmp edx, dword ptr [esp+4] + ja ConvertAddress_found + cmp eax, dword ptr [esp] + ja ConvertAddress_found // address is greater than end of the chunk + test bl, bl + jnz ConvertAddress_notFound + ret 8 + +ConvertAddress_found: + // found chunk. Calculating the address + // addr_to_find - logical_addr + pop eax // low dword of addr_to_find + pop edx // high dword of addr_to_find + sub eax, dword ptr [si] + sbb edx, dword ptr [si+4] + // (addr_to_find - logical_addr) + physical_addr + add eax, dword ptr [si+16] + adc edx, dword ptr [si+20] + + // edx:eax is physical address. Converting to LBA (shifting by 9 bits) + shrd eax, edx, 9 + shr edx, 9 + inc bl // clears ZF (bl is 0 or 1 here) + ret + +ConvertAddress_notFound: + // offset is alredy on stack + //push dword ptr [esp+4] + //push dword ptr [esp] + dec sp + mov byte ptr [esp], CHUNK_ITEM_KEY + data32 push 0 + push 0 + push FIRST_CHUNK_TREE_OBJECTID + + mov eax, dword ptr [ChunkRootAddress] + mov edx, dword ptr [ChunkRootAddress+4] + mov cl, byte ptr [ChunkRootLevel] + + call SearchTree + add sp, 9 // setting stack back + + mov ax, si // ES:[SI] - found key pointer + call InsertChunk + + mov bl, 0 // indicates second try + jmp ConvertAddress_secondTry + + +// Compare key (key1) with key in array identified by base and index (key2) +// INPUT: +// - DS:[SI] key1 pointer +// - ES:[DI] start of the array +// - AX size of one key in array +// - CX key index +// OUTPUT: +// - DS:[SI] key1 pointer +// - ES:[DI] key2 pointer +// - sets flags according to comparison +CompareKeys: + //xchg si, di + + mul cx + add di, ax + push ds + push si + push es + push di + + // must be replaced for proper flags after cmps + push ds + push es + pop ds + pop es + xchg si, di + + lea si, [si+4] // key in array + lea di, [di+4] // searchable key + std + + // comparing objectid + cmpsd + jne CompareKeys_end + cmpsd + jne CompareKeys_end + // comparing type + lea si, [si+12] + lea di, [di+12] + + cmpsb + jne CompareKeys_end + // comparing offset + lea si, [si+1+1+4] + lea di, [di+1+1+4] + + cmpsd + jne CompareKeys_end + cmpsd +CompareKeys_end: + cld + pop di + pop es + pop si + pop ds + ret + + + +btrfsSignature: + .ascii "_BHRfS_M" + +//.org 1022 +// .word HEX(aa55) + + +wrongSignatureError: + .asciz "BTRFS read error" +MaxItemsError: + .asciz "Max items error" +filenameCrc: + .long HEX(68cba33d) // computed hashsum of "freeldr.sys" +freeldrFilename: + .ascii "freeldr.sys" +notFoundError: + .asciz "NFE" +.org 1534 + .word HEX(aa55) +.endcode16 + +END diff --git a/boot/freeldr/freeldr/CMakeLists.txt b/boot/freeldr/freeldr/CMakeLists.txt index 63d985e920..762b53e396 100644 --- a/boot/freeldr/freeldr/CMakeLists.txt +++ b/boot/freeldr/freeldr/CMakeLists.txt @@ -37,6 +37,7 @@ list(APPEND FREELDR_BOOTLIB_COMMON_SOURCE lib/peloader.c lib/comm/rs232.c ## add KD support + lib/fs/btrfs.c lib/fs/ext2.c lib/fs/fat.c lib/fs/fs.c diff --git a/boot/freeldr/freeldr/arch/i386/hwdisk.c b/boot/freeldr/freeldr/arch/i386/hwdisk.c index f20ee62ce6..af86f62382 100644 --- a/boot/freeldr/freeldr/arch/i386/hwdisk.c +++ b/boot/freeldr/freeldr/arch/i386/hwdisk.c @@ -188,7 +188,7 @@ DiskSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode) if (Position->LowPart & (Context->SectorSize - 1)) return EINVAL; - Context->SectorNumber = (ULONG)(Position->QuadPart / Context->SectorSize); + Context->SectorNumber = Position->QuadPart / Context->SectorSize; return ESUCCESS; } diff --git a/boot/freeldr/freeldr/include/freeldr.h b/boot/freeldr/freeldr/include/freeldr.h index bb339cc852..b62d4e5600 100644 --- a/boot/freeldr/freeldr/include/freeldr.h +++ b/boot/freeldr/freeldr/include/freeldr.h @@ -89,6 +89,7 @@ #include <fs/ntfs.h> #include <fs/iso.h> #include <fs/pxe.h> +#include <fs/btrfs.h> /* UI support */ #include <ui/gui.h> diff --git a/boot/freeldr/freeldr/include/fs/btrfs.h b/boot/freeldr/freeldr/include/fs/btrfs.h new file mode 100644 index 0000000000..b8fddc773c --- /dev/null +++ b/boot/freeldr/freeldr/include/fs/btrfs.h @@ -0,0 +1,418 @@ +/* + * PROJECT: FreeLoader + * LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+
) + * PURPOSE: BTRFS support for FreeLoader + * COPYRIGHT: Copyright 2018 Victor Perevertkin (victor(a)perevertkin.ru) + */ + +/* Structures were taken from u-boot,
https://github.com/u-boot/u-boot/tree/master/fs/btrfs
*/ + +#pragma once + +typedef UCHAR u8; +typedef USHORT u16; +typedef ULONG32 u32; +typedef ULONG64 u64; +/* type that store on disk, but it is same as cpu type for i386 arch */ +typedef u8 __u8; +typedef u16 __u16; +typedef u32 __u32; +typedef u64 __u64; + +#include <fs/crc32c.h> +#define btrfs_crc32c(name, len) crc32c_le((u32)~1, name, len) + +#define BTRFS_SUPER_INFO_OFFSET (64 * 1024) +#define BTRFS_SUPER_INFO_SIZE 4096 +#define BTRFS_MAX_LEAF_SIZE 4096 +#define BTRFS_BLOCK_SHIFT 12 +#define BTRFS_BLOCK_SIZE (1 << BTRFS_BLOCK_SHIFT) + +#define BTRFS_SUPER_MIRROR_MAX 3 +#define BTRFS_SUPER_MIRROR_SHIFT 12 +#define BTRFS_CSUM_SIZE 32 +#define BTRFS_FSID_SIZE 16 +#define BTRFS_LABEL_SIZE 256 +#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048 +#define BTRFS_UUID_SIZE 16 + +#define BTRFS_VOL_NAME_MAX 255 +#define BTRFS_NAME_MAX 255 + +#define BTRFS_MAGIC "_BHRfS_M" +#define BTRFS_MAGIC_L 8 +#define BTRFS_MAGIC_N 0x4d5f53665248425fULL + +#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) + +#define BTRFS_DEV_ITEM_KEY 216 +#define BTRFS_CHUNK_ITEM_KEY 228 +#define BTRFS_ROOT_REF_KEY 156 +#define BTRFS_ROOT_ITEM_KEY 132 +#define BTRFS_EXTENT_DATA_KEY 108 +#define BTRFS_DIR_ITEM_KEY 84 +#define BTRFS_DIR_INDEX_KEY 96 +#define BTRFS_INODE_ITEM_KEY 1 +#define BTRFS_INODE_REF_KEY 12 + +#define BTRFS_EXTENT_TREE_OBJECTID 2ULL +#define BTRFS_FS_TREE_OBJECTID 5ULL + +#define BTRFS_FIRST_FREE_OBJECTID 256ULL +#define BTRFS_LAST_FREE_OBJECTID -256ULL +#define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL + +#define BTRFS_FILE_EXTENT_INLINE 0 +#define BTRFS_FILE_EXTENT_REG 1 +#define BTRFS_FILE_EXTENT_PREALLOC 2 + +#define BTRFS_MAX_LEVEL 8 +#define BTRFS_MAX_CHUNK_ENTRIES 256 + +#define BTRFS_DEV_ITEMS_OBJECTID 1ULL + +#define BTRFS_FT_REG_FILE 1 +#define BTRFS_FT_DIR 2 +#define BTRFS_FT_SYMLINK 7 +#define BTRFS_FT_XATTR 8 +#define BTRFS_FT_MAX 9 + +#define BTRFS_COMPRESS_NONE 0 +#define BTRFS_COMPRESS_ZLIB 1 +#define BTRFS_COMPRESS_LZO 2 + +#define ROOT_DIR_WORD 0x002f + +#include <pshpack1.h> + +struct btrfs_disk_key { + __u64 objectid; + __u8 type; + __u64 offset; +}; + +struct btrfs_header { + /* these first four must match the super block */ + __u8 csum[BTRFS_CSUM_SIZE]; + __u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ + __u64 bytenr; /* which block this node is supposed to live in */ + __u64 flags; + + /* allowed to be different from the super from here on down */ + __u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; + __u64 generation; + __u64 owner; + __u32 nritems; + __u8 level; +}; + +struct btrfs_item { + struct btrfs_disk_key key; + __u32 offset; + __u32 size; +}; + +struct btrfs_leaf { + struct btrfs_header header; + struct btrfs_item items[]; +}; + +struct btrfs_key_ptr { + struct btrfs_disk_key key; + __u64 blockptr; + __u64 generation; +}; + +struct btrfs_node { + struct btrfs_header header; + struct btrfs_key_ptr ptrs[]; +}; + +struct btrfs_dev_item { + /* the internal btrfs device id */ + __u64 devid; + + /* size of the device */ + __u64 total_bytes; + + /* bytes used */ + __u64 bytes_used; + + /* optimal io alignment for this device */ + __u32 io_align; + + /* optimal io width for this device */ + __u32 io_width; + + /* minimal io size for this device */ + __u32 sector_size; + + /* type and info about this device */ + __u64 type; + + /* expected generation for this device */ + __u64 generation; + + /* + * starting byte of this partition on the device, + * to allow for stripe alignment in the future + */ + __u64 start_offset; + + /* grouping information for allocation decisions */ + __u32 dev_group; + + /* seek speed 0-100 where 100 is fastest */ + __u8 seek_speed; + + /* bandwidth 0-100 where 100 is fastest */ + __u8 bandwidth; + + /* btrfs generated uuid for this device */ + __u8 uuid[BTRFS_UUID_SIZE]; + + /* uuid of FS who owns this device */ + __u8 fsid[BTRFS_UUID_SIZE]; +}; + +struct btrfs_stripe { + __u64 devid; + __u64 offset; + __u8 dev_uuid[BTRFS_UUID_SIZE]; +}; + +struct btrfs_chunk { + /* size of this chunk in bytes */ + __u64 length; + + /* objectid of the root referencing this chunk */ + __u64 owner; + + __u64 stripe_len; + __u64 type; + + /* optimal io alignment for this chunk */ + __u32 io_align; + + /* optimal io width for this chunk */ + __u32 io_width; + + /* minimal io size for this chunk */ + __u32 sector_size; + + /* 2^16 stripes is quite a lot, a second limit is the size of a single + * item in the btree + */ + __u16 num_stripes; + + /* sub stripes only matter for raid10 */ + __u16 sub_stripes; + struct btrfs_stripe stripe; + /* additional stripes go here */ +}; + +struct btrfs_inode_ref { + __u64 index; + __u16 name_len; + /* name goes here */ +}; + +struct btrfs_timespec { + __u64 sec; + __u32 nsec; +}; + +struct btrfs_inode_item { + /* nfs style generation number */ + __u64 generation; + /* transid that last touched this inode */ + __u64 transid; + __u64 size; + __u64 nbytes; + __u64 block_group; + __u32 nlink; + __u32 uid; + __u32 gid; + __u32 mode; + __u64 rdev; + __u64 flags; + + /* modification sequence number for NFS */ + __u64 sequence; + + /* + * a little future expansion, for more than this we can + * just grow the inode item and version it + */ + __u64 reserved[4]; + struct btrfs_timespec atime; + struct btrfs_timespec ctime; + struct btrfs_timespec mtime; + struct btrfs_timespec otime; +}; + + +struct btrfs_dir_item { + struct btrfs_disk_key location; + __u64 transid; + __u16 data_len; + __u16 name_len; + __u8 type; +}; + +struct btrfs_root_item { + struct btrfs_inode_item inode; + __u64 generation; + __u64 root_dirid; + __u64 bytenr; + __u64 byte_limit; + __u64 bytes_used; + __u64 last_snapshot; + __u64 flags; + __u32 refs; + struct btrfs_disk_key drop_progress; + __u8 drop_level; + __u8 level; +}; + +struct btrfs_root_ref { + __u64 dirid; + __u64 sequence; + __u16 name_len; +}; + +struct btrfs_file_extent_item { + /* + * transaction id that created this extent + */ + __u64 generation; + /* + * max number of bytes to hold this extent in ram + * when we split a compressed extent we can't know how big + * each of the resulting pieces will be. So, this is + * an upper limit on the size of the extent in ram instead of + * an exact limit. + */ + __u64 ram_bytes; + + /* + * 32 bits for the various ways we might encode the data, + * including compression and encryption. If any of these + * are set to something a given disk format doesn't understand + * it is treated like an incompat flag for reading and writing, + * but not for stat. + */ + __u8 compression; + __u8 encryption; + __u16 other_encoding; /* spare for later use */ + + /* are we inline data or a real extent? */ + __u8 type; + + /* + * disk space consumed by the extent, checksum blocks are included + * in these numbers + * + * At this offset in the structure, the inline extent data start. + */ + __u64 disk_bytenr; + __u64 disk_num_bytes; + /* + * the logical offset in file blocks (no csums) + * this extent record is for. This allows a file extent to point + * into the middle of an existing extent on disk, sharing it + * between two snapshots (useful if some bytes in the middle of the + * extent have changed + */ + __u64 offset; + /* + * the logical number of file blocks (no csums included). This + * always reflects the size uncompressed and without encoding. + */ + __u64 num_bytes; + +}; + +struct btrfs_super_block { + __u8 csum[BTRFS_CSUM_SIZE]; + /* the first 4 fields must match struct btrfs_header */ + __u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ + __u64 bytenr; /* this block number */ + __u64 flags; + + /* allowed to be different from the btrfs_header from here own down */ + __u64 magic; + __u64 generation; + __u64 root; + __u64 chunk_root; + __u64 log_root; + + /* this will help find the new super based on the log root */ + __u64 log_root_transid; + __u64 total_bytes; + __u64 bytes_used; + __u64 root_dir_objectid; + __u64 num_devices; + __u32 sectorsize; + __u32 nodesize; + __u32 __unused_leafsize; + __u32 stripesize; + __u32 sys_chunk_array_size; + __u64 chunk_root_generation; + __u64 compat_flags; + __u64 compat_ro_flags; + __u64 incompat_flags; + __u16 csum_type; + __u8 root_level; + __u8 chunk_root_level; + __u8 log_root_level; + struct btrfs_dev_item dev_item; + + char label[BTRFS_LABEL_SIZE]; + + __u64 cache_generation; + __u64 uuid_tree_generation; + + /* future expansion */ + __u64 reserved[30]; + __u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; +}; + +#include <poppack.h> + +union tree_buf { + struct btrfs_header header; + struct btrfs_node node; + struct btrfs_leaf leaf; +}; + +/* remember how we get to a node/leaf */ +struct btrfs_path { + u64 offsets[BTRFS_MAX_LEVEL]; + int itemsnr[BTRFS_MAX_LEVEL]; + int slots[BTRFS_MAX_LEVEL]; + /* remember whole last leaf */ + union tree_buf *tree_buf; +}; + +/* store logical offset to physical offset mapping */ +struct btrfs_chunk_map_item { + u64 logical; + u64 length; + u64 devid; + u64 physical; +}; + +struct btrfs_chunk_map { + struct btrfs_chunk_map_item *map; + u32 map_length; + u32 cur_length; +}; + +typedef struct { + u64 inr; + u64 position; + struct btrfs_inode_item inode; +} btrfs_file_info, * pbtrfs_file_info; + +const DEVVTBL* BtrFsMount(ULONG DeviceId); diff --git a/boot/freeldr/freeldr/include/fs/crc32c.h b/boot/freeldr/freeldr/include/fs/crc32c.h new file mode 100644 index 0000000000..2dc31000ae --- /dev/null +++ b/boot/freeldr/freeldr/include/fs/crc32c.h @@ -0,0 +1,52 @@ +/* + * Copied from Linux kernel crypto/crc32c.c + * Copyright (c) 2004 Cisco Systems, Inc. + * Copyright (c) 2008 Herbert Xu <herbert(a)gondor.apana.org.au> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#pragma once + +/* + * This is the CRC-32C table + * Generated with: + * width = 32 bits + * poly = 0x1EDC6F41 + * reflect input bytes = true + * reflect output bytes = true + */ + +static u32 crc32c_table[256]; + +/* + * Steps through buffer one byte at at time, calculates reflected + * crc using table. + */ + +static inline u32 crc32c_le(u32 crc, const char *data, size_t length) +{ + while (length--) + crc = crc32c_table[(u8)(crc ^ *data++)] ^ (crc >> 8); + + return crc; +} + +static inline void btrfs_init_crc32c(void) +{ + int i, j; + u32 v; + const u32 poly = 0x82F63B78; /* Bit-reflected CRC32C polynomial */ + + for (i = 0; i < 256; i++) { + v = i; + for (j = 0; j < 8; j++) { + v = (v >> 1) ^ ((v & 1) ? poly : 0); + } + crc32c_table[i] = v; + } +} diff --git a/boot/freeldr/freeldr/lib/fs/btrfs.c b/boot/freeldr/freeldr/lib/fs/btrfs.c new file mode 100644 index 0000000000..7c3aa5c4ce --- /dev/null +++ b/boot/freeldr/freeldr/lib/fs/btrfs.c @@ -0,0 +1,1283 @@ +/* + * PROJECT: FreeLoader + * LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+
) + * PURPOSE: BTRFS support for FreeLoader + * COPYRIGHT: Copyright 2018 Victor Perevertkin (victor(a)perevertkin.ru) + */ + +/* Some code was taken from u-boot,
https://github.com/u-boot/u-boot/tree/master/fs/btrfs
*/ + +#include <freeldr.h> +#include <debug.h> + +DBG_DEFAULT_CHANNEL(FILESYSTEM); + +#define TAG_BTRFS_INFO 'IftB' +#define TAG_BTRFS_CHUNK_MAP 'CftB' +#define TAG_BTRFS_NODE 'NftB' +#define TAG_BTRFS_FILE 'FftB' +#define TAG_BTRFS_LINK 'LftB' + +#define INVALID_INODE ((ULONGLONG)-1) + +struct BTRFS_INFO { + ULONG DeviceId; + struct btrfs_super_block SuperBlock; + struct btrfs_chunk_map ChunkMap; + struct btrfs_root_item FsRoot; + struct btrfs_root_item ExtentRoot; +}; + +struct BTRFS_INFO *BtrFsInfo; + +/* compare function used for bin_search */ +typedef int (*cmp_func)(const void *ptr1, const void *ptr2); + +/* simple but useful bin search, used for chunk search and btree search */ +static int bin_search(void *ptr, int item_size, void *cmp_item, cmp_func func, + int min, int max, int *slot) +{ + int low = min; + int high = max; + int mid; + int ret; + unsigned long offset; + UCHAR *item; + + while (low < high) + { + mid = (low + high) / 2; + offset = mid * item_size; + + item = (UCHAR *) ptr + offset; + ret = func((void *) item, cmp_item); + + if (ret < 0) + { + low = mid + 1; + } + else if (ret > 0) + { + high = mid; + } + else + { + *slot = mid; + return 0; + } + } + *slot = low; + return 1; +} + +static int btrfs_comp_chunk_map(struct btrfs_chunk_map_item *m1, + struct btrfs_chunk_map_item *m2) +{ + if (m1->logical > m2->logical) + return 1; + if (m1->logical < m2->logical) + return -1; + return 0; +} + +/* insert a new chunk mapping item */ +static void insert_chunk_item(struct btrfs_chunk_map_item *item) +{ + struct btrfs_chunk_map *chunk_map = &BtrFsInfo->ChunkMap; + int ret; + int slot; + int i; + + if (chunk_map->map == NULL) + { + /* first item */ + chunk_map->map_length = BTRFS_MAX_CHUNK_ENTRIES; + chunk_map->map = FrLdrTempAlloc(chunk_map->map_length * sizeof(chunk_map->map[0]), TAG_BTRFS_CHUNK_MAP); + chunk_map->map[0] = *item; + chunk_map->cur_length = 1; + return; + } + ret = bin_search(chunk_map->map, sizeof(*item), item, + (cmp_func) btrfs_comp_chunk_map, 0, + chunk_map->cur_length, &slot); + if (ret == 0)/* already in map */ + return; + + if (chunk_map->cur_length == BTRFS_MAX_CHUNK_ENTRIES) + { + /* should be impossible */ + TRACE("too many chunk items\n"); + return; + } + + for (i = chunk_map->cur_length; i > slot; i--) + chunk_map->map[i] = chunk_map->map[i - 1]; + + chunk_map->map[slot] = *item; + chunk_map->cur_length++; +} + +static inline void insert_map(const struct btrfs_disk_key *key, struct btrfs_chunk *chunk) +{ + struct btrfs_stripe *stripe = &chunk->stripe; + struct btrfs_stripe *stripe_end = stripe + chunk->num_stripes; + struct btrfs_chunk_map_item item; + + item.logical = key->offset; + item.length = chunk->length; + for (; stripe < stripe_end; stripe++) + { + TRACE("stripe: %p\n", stripe); + item.devid = stripe->devid; + item.physical = stripe->offset; + TRACE("inserting chunk log: %llx len: %llx devid: %llx phys: %llx\n", item.logical, item.length, item.devid, + item.physical); + insert_chunk_item(&item); + } + +#if 0 + struct btrfs_chunk_map *chunk_map = &BtrFsInfo->ChunkMap; + struct btrfs_chunk_map_item *itm; + int i; + + TRACE("insert finished. Printing chunk map:\n------------------------------\n"); + + for (i = 0; i < chunk_map->cur_length; i++) + { + itm = &chunk_map->map[i]; + TRACE("%llx..%llx -> %llx..%llx, devid: %llu\n", + itm->logical, + itm->logical + itm->length, + itm->physical, + itm->physical + itm->length, + itm->devid + ); + } +#endif +} + +static inline unsigned long btrfs_chunk_item_size(int num_stripes) +{ + return sizeof(struct btrfs_chunk) + + sizeof(struct btrfs_stripe) * (num_stripes - 1); +} + +static inline void init_path(struct btrfs_path *path) +{ + memset(path, 0, sizeof(*path)); + path->tree_buf = FrLdrTempAlloc(BtrFsInfo->SuperBlock.nodesize, TAG_BTRFS_NODE); +} + +static inline void free_path(struct btrfs_path *path) +{ + if (path->tree_buf) FrLdrTempFree(path->tree_buf, TAG_BTRFS_NODE); +} + +static inline struct btrfs_item *path_current_item(struct btrfs_path *path) +{ + return &path->tree_buf->leaf.items[path->slots[0]]; +} + +static inline UCHAR *path_current_data(struct btrfs_path *path) +{ + return (UCHAR *) path->tree_buf->leaf.items + path_current_item(path)->offset; +} + +static inline const struct btrfs_disk_key *path_current_disk_key(struct btrfs_path *path) +{ + return (const struct btrfs_disk_key *) &path_current_item(path)->key; +} + + +static int btrfs_comp_keys(const struct btrfs_disk_key *k1, + const struct btrfs_disk_key *k2) +{ + if (k1->objectid > k2->objectid) + return 1; + if (k1->objectid < k2->objectid) + return -1; + if (k1->type > k2->type) + return 1; + if (k1->type < k2->type) + return -1; + if (k1->offset > k2->offset) + return 1; + if (k1->offset < k2->offset) + return -1; + return 0; +} + +/* compare keys but ignore offset, is useful to enumerate all same kind keys */ +static int btrfs_comp_keys_type(const struct btrfs_disk_key *k1, + const struct btrfs_disk_key *k2) +{ + if (k1->objectid > k2->objectid) + return 1; + if (k1->objectid < k2->objectid) + return -1; + if (k1->type > k2->type) + return 1; + if (k1->type < k2->type) + return -1; + return 0; +} + +/* + * from sys_chunk_array or chunk_tree, we can convert a logical address to + * a physical address we can not support multi device case yet + */ +static u64 logical_physical(u64 logical) +{ + struct btrfs_chunk_map *chunk_map = &BtrFsInfo->ChunkMap; + struct btrfs_chunk_map_item item; + int slot, ret; + + item.logical = logical; + ret = bin_search(chunk_map->map, sizeof(chunk_map->map[0]), &item, + (cmp_func) btrfs_comp_chunk_map, 0, + chunk_map->cur_length, &slot); + if (ret == 0) + slot++; + else if (slot == 0) + return -1; + if (logical >= chunk_map->map[slot - 1].logical + chunk_map->map[slot - 1].length) + return -1; + + TRACE("Address translation: 0x%llx -> 0x%llx\n", logical, + chunk_map->map[slot - 1].physical + logical - chunk_map->map[slot - 1].logical); + + return chunk_map->map[slot - 1].physical + logical - chunk_map->map[slot - 1].logical; +} + +static BOOLEAN disk_read(u64 physical, void *dest, u32 count) +{ + LARGE_INTEGER Position; + ULONG Count; + ARC_STATUS Status; + + if (!dest) + return FALSE; + + Position.QuadPart = physical; + Status = ArcSeek(BtrFsInfo->DeviceId, &Position, SeekAbsolute); + if (Status != ESUCCESS) + { + ERR("ArcSeek returned status %lu\n", Status); + return FALSE; + } + + Status = ArcRead(BtrFsInfo->DeviceId, dest, count, &Count); + if (Status != ESUCCESS || Count != count) + { + ERR("ArcRead returned status %lu\n", Status); + return FALSE; + } + + return TRUE; +} + +static BOOLEAN _BtrFsSearchTree(u64 loffset, u8 level, struct btrfs_disk_key *key, + struct btrfs_path *path) +{ + struct btrfs_super_block *sb = &BtrFsInfo->SuperBlock; + union tree_buf *tree_buf = path->tree_buf; + int slot, ret, lvl; + u64 physical, logical = loffset; + TRACE("BtrFsSearchTree called: offset: 0x%llx, level: %u (%llu %u %llu)\n", + loffset, level, key->objectid, key->type, key->offset); + + if (!tree_buf) + { + ERR("Path struct is not allocated\n"); + return FALSE; + } + + for (lvl = level; lvl >= 0; lvl--) + { + physical = logical_physical(logical); + + if (!disk_read(physical, &tree_buf->header, sb->nodesize)) + { + ERR("Error when reading tree node, loffset: 0x%llx, poffset: 0x%llx, level: %u\n", logical, physical, lvl); + return FALSE; + } + + + if (tree_buf->header.level != lvl) + { + ERR("Error when searching in tree: expected lvl=%u but got %u\n", lvl, tree_buf->header.level); + return FALSE; + } + + TRACE("BtrFsSearchTree loop, level %u, loffset: 0x%llx\n", lvl, logical); + + if (lvl) + { + ret = bin_search(tree_buf->node.ptrs, + sizeof(struct btrfs_key_ptr), + key, (cmp_func) btrfs_comp_keys, + path->slots[lvl], + tree_buf->header.nritems, &slot); + TRACE("Inner node, min=%lu max=%lu\n", path->slots[0], tree_buf->header.nritems); + if (ret && slot > path->slots[lvl]) + --slot; + } + else + { + ret = bin_search(tree_buf->leaf.items, + sizeof(struct btrfs_item), + key, (cmp_func) btrfs_comp_keys, + path->slots[0], + tree_buf->header.nritems, &slot); + TRACE("Leaf node, min=%lu max=%lu\n", path->slots[0], tree_buf->header.nritems); + if (slot == tree_buf->header.nritems) + --slot; + } + + path->itemsnr[lvl] = tree_buf->header.nritems; + path->offsets[lvl] = logical; + path->slots[lvl] = slot; + + logical = tree_buf->node.ptrs[slot].blockptr; + } + + TRACE("Found slot no=%lu\n", slot); + + TRACE("BtrFsSearchTree found item (%llu %u %llu) offset: %lu, size: %lu, returning %lu\n", + path_current_disk_key(path)->objectid, path_current_disk_key(path)->type, path_current_disk_key(path)->offset, + path_current_item(path)->offset, path_current_item(path)->size, !ret); + + return !ret; +} + +static inline BOOLEAN +BtrFsSearchTree(const struct btrfs_root_item *root, struct btrfs_disk_key *key, struct btrfs_path *path) +{ + return _BtrFsSearchTree(root->bytenr, root->level, key, path); +} + +static inline BOOLEAN +BtrFsSearchTreeType(const struct btrfs_root_item *root, u64 objectid, u8 type, struct btrfs_path *path) +{ + struct btrfs_disk_key key; + + key.objectid = objectid; + key.type = type; + key.offset = 0; + + _BtrFsSearchTree(root->bytenr, root->level, &key, path); + + if (path_current_disk_key(path)->objectid && !btrfs_comp_keys_type(&key, path_current_disk_key(path))) + return TRUE; + else + return FALSE; +} + +/* return 0 if slot found */ +static int next_slot(struct btrfs_disk_key *key, + struct btrfs_path *path) +{ + int slot, level = 1; + + if (!path->itemsnr[0]) + return 1; + slot = path->slots[0] + 1; + if (slot >= path->itemsnr[0]) + { + /* jumping to next leaf */ + while (level < BTRFS_MAX_LEVEL) + { + if (!path->itemsnr[level]) /* no more nodes */ + return 1; + slot = path->slots[level] + 1; + if (slot >= path->itemsnr[level]) + { + level++; + continue;; + } + path->slots[level] = slot; + path->slots[level - 1] = 0; /* reset low level slots info */ + path->itemsnr[level - 1] = 0; + path->offsets[level - 1] = 0; + _BtrFsSearchTree(path->offsets[level], level, key, path); + break; + } + if (level == BTRFS_MAX_LEVEL) + return 1; + goto out; + } + path->slots[0] = slot; + + out: + if (path_current_disk_key(path)->objectid && !btrfs_comp_keys_type(key, path_current_disk_key(path))) + return 0; + else + return 1; +} + +static int prev_slot(struct btrfs_disk_key *key, + struct btrfs_path *path) +{ + if (!path->slots[0]) + return 1; + --path->slots[0]; + if (path_current_disk_key(path)->objectid && !btrfs_comp_keys_type(key, path_current_disk_key(path))) + return 0; + else + return 1; +} + +/* + * read chunk_array in super block + */ +static void btrfs_read_sys_chunk_array() +{ + struct btrfs_super_block *sb = &BtrFsInfo->SuperBlock; + struct btrfs_disk_key *key; + struct btrfs_chunk *chunk; + u16 cur; + + /* read chunk array in superblock */ + TRACE("reading chunk array\n-----------------------------\n"); + cur = 0; + while (cur < sb->sys_chunk_array_size) + { + key = (struct btrfs_disk_key *) (sb->sys_chunk_array + cur); + TRACE("chunk key objectid: %llx, offset: %llx, type: %u\n", key->objectid, key->offset, key->type); + cur += sizeof(*key); + chunk = (struct btrfs_chunk *) (sb->sys_chunk_array + cur); + TRACE("chunk length: %llx\n", chunk->length); + TRACE("chunk owner: %llu\n", chunk->owner); + TRACE("chunk stripe_len: %llx\n", chunk->stripe_len); + TRACE("chunk type: %llu\n", chunk->type); + TRACE("chunk io_align: %u\n", chunk->io_align); + TRACE("chunk io_width: %u\n", chunk->io_width); + TRACE("chunk sector_size: %u\n", chunk->sector_size); + TRACE("chunk num_stripes: %u\n", chunk->num_stripes); + TRACE("chunk sub_stripes: %u\n", chunk->sub_stripes); + + cur += btrfs_chunk_item_size(chunk->num_stripes); + TRACE("read_sys_chunk_array() cur=%d\n", cur); + insert_map((const struct btrfs_disk_key *) key, chunk); + } +} + + +/* + * read chunk items from chunk_tree and insert them to chunk map + * */ +static void btrfs_read_chunk_tree() +{ + struct btrfs_super_block *sb = &BtrFsInfo->SuperBlock; + struct btrfs_disk_key ignore_key; + struct btrfs_disk_key search_key; + struct btrfs_chunk *chunk; + struct btrfs_path path; + + if (!(sb->flags & BTRFS_SUPER_FLAG_METADUMP)) + { + if (sb->num_devices > 1) + TRACE("warning: only support single device btrfs\n"); + + ignore_key.objectid = BTRFS_DEV_ITEMS_OBJECTID; + ignore_key.type = BTRFS_DEV_ITEM_KEY; + + /* read chunk from chunk_tree */ + search_key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; + search_key.type = BTRFS_CHUNK_ITEM_KEY; + search_key.offset = 0; + init_path(&path); + _BtrFsSearchTree(sb->chunk_root, sb->chunk_root_level, &search_key, &path); + do + { + /* skip information about underlying block + * devices. + */ + if (!btrfs_comp_keys_type(&ignore_key, path_current_disk_key(&path))) + continue; + if (btrfs_comp_keys_type(&search_key, path_current_disk_key(&path))) + break; + + chunk = (struct btrfs_chunk *) (path_current_data(&path)); + insert_map(path_current_disk_key(&path), chunk); + } while (!next_slot(&search_key, &path)); + free_path(&path); + } +} + +//////////////////////////////////////// +///////////// DIR ITEM +//////////////////////////////////////// + +static BOOLEAN verify_dir_item(struct btrfs_dir_item *item, u32 start, u32 total) +{ + u16 max_len = BTRFS_NAME_MAX; + u32 end; + + if (item->type >= BTRFS_FT_MAX) + { + ERR("Invalid dir item type: %i\n", item->type); + return TRUE; + } + + if (item->type == BTRFS_FT_XATTR) + max_len = 255; /* XATTR_NAME_MAX */ + + end = start + sizeof(*item) + item->name_len; + if (item->name_len > max_len || end > total) + { + ERR("Invalid dir item name len: %u\n", item->name_len); + return TRUE; + } + + return FALSE; +} + + +static struct btrfs_dir_item *BtrFsMatchDirItemName(struct btrfs_path *path, const char *name, int name_len) +{ + struct btrfs_dir_item *item = (struct btrfs_dir_item *) path_current_data(path); + u32 cur = 0, this_len; + const char *name_ptr; + + while (cur < path_current_item(path)->size) + { + this_len = sizeof(*item) + item->name_len + item->data_len; + name_ptr = (const char *) item + sizeof(*item); + + if (verify_dir_item(item, cur, this_len)) + return NULL; + if (item->name_len == name_len && !memcmp(name_ptr, name, name_len)) + return item; + + cur += this_len; + item = (struct btrfs_dir_item *) ((u8 *) item + this_len); + } + + return NULL; +} + +static BOOLEAN BtrFsLookupDirItem(const struct btrfs_root_item *root, u64 dir, const char *name, int name_len, + struct btrfs_dir_item *item) +{ + struct btrfs_path path; + struct btrfs_disk_key key; + struct btrfs_dir_item *res = NULL; + + key.objectid = dir; + key.type = BTRFS_DIR_ITEM_KEY; + key.offset = btrfs_crc32c(name, name_len); + init_path(&path); + + if (!BtrFsSearchTree(root, &key, &path)) + { + free_path(&path); + return FALSE; + } + + res = BtrFsMatchDirItemName(&path, name, name_len); + if (res) + *item = *res; + free_path(&path); + + return res != NULL; +} + +static BOOLEAN BtrFsLookupDirItemI(const struct btrfs_root_item *root, u64 dir_haystack, const char *name, int name_len, + struct btrfs_dir_item *ret_item) +{ + struct btrfs_path path; + struct btrfs_disk_key key; + struct btrfs_dir_item *item; + char *name_buf; + BOOLEAN result = FALSE; + + key.objectid = dir_haystack; + key.type = BTRFS_DIR_INDEX_KEY; + key.offset = 0; + init_path(&path); + + BtrFsSearchTree(root, &key, &path); + + if (btrfs_comp_keys_type(&key, path_current_disk_key(&path))) + goto cleanup; + + do + { + item = (struct btrfs_dir_item *) path_current_data(&path); + // TRACE("slot: %ld, KEY (%llu %u %llu) %.*s\n", + // path.slots[0], path.item.key.objectid, path.item.key.type, + // path.item.key.offset, item->name_len, (char *)item + sizeof(*item)); + + if (verify_dir_item(item, 0, sizeof(*item) + item->name_len)) + continue; + if (item->type == BTRFS_FT_XATTR) + continue; + + name_buf = (char *) item + sizeof(*item); + TRACE("Compare names %.*s and %.*s\n", name_len, name, item->name_len, name_buf); + + if (_strnicmp(name, name_buf, name_len) == 0) + { + *ret_item = *item; + result = TRUE; + goto cleanup; + } + + } while (!next_slot(&key, &path)); + + cleanup: + free_path(&path); + return result; +} + +//////////////////////////////////////// +///////////// EXTENTS +//////////////////////////////////////// + +static u64 btrfs_read_extent_inline(struct btrfs_path *path, + struct btrfs_file_extent_item *extent, u64 offset, + u64 size, char *out) +{ + u32 dlen; + const char *cbuf; + const int data_off = offsetof( + struct btrfs_file_extent_item, disk_bytenr); + + cbuf = (const char *) extent + data_off; + dlen = extent->ram_bytes; + + TRACE("read_extent_inline offset=%llu size=%llu gener=%llu\n", offset, size, extent->generation); + + if (offset > dlen) + { + ERR("Tried to read offset (%llu) beyond extent length (%lu)\n", offset, dlen); + return INVALID_INODE; + } + + if (size > dlen - offset) + size = dlen - offset; + + if (extent->compression == BTRFS_COMPRESS_NONE) + { + TRACE("read_extent_inline %lu, \n", data_off); + memcpy(out, cbuf + offset, size); + return size; + } + + ERR("No compression supported right now\n"); + return INVALID_INODE; +} + +static u64 btrfs_read_extent_reg(struct btrfs_path *path, struct btrfs_file_extent_item *extent, + u64 offset, u64 size, char *out) +{ + u64 physical, dlen; + char *temp_out; + dlen = extent->num_bytes; + + if (offset > dlen) + { + ERR("Tried to read offset (%llu) beyond extent length (%lu)\n", offset, dlen); + return -1ULL; + } + + if (size > dlen - offset) + size = dlen - offset; + + physical = logical_physical(extent->disk_bytenr); + if (physical == -1ULL) + { + ERR("Unable to convert logical address to physical: %llu\n", extent->disk_bytenr); + return -1ULL; + } + + if (extent->compression == BTRFS_COMPRESS_NONE) + { + physical += extent->offset + offset; + if (physical & (512 - 1)) + { + /* If somebody tried to do unaligned access */ + physical -= offset; + temp_out = FrLdrTempAlloc(size + offset, TAG_BTRFS_FILE); + + if (!disk_read(physical, temp_out, size + offset)) + { + FrLdrTempFree(temp_out, TAG_BTRFS_FILE); + return -1ULL; + } + + memcpy(out, temp_out + offset, size); + FrLdrTempFree(temp_out, TAG_BTRFS_FILE); + } else + { + if (!disk_read(physical, out, size)) + return -1ULL; + } + + return size; + } + + ERR("No compression supported right now\n"); + return -1ULL; +} + +static u64 btrfs_file_read(const struct btrfs_root_item *root, u64 inr, u64 offset, u64 size, char *buf) +{ + struct btrfs_path path; + struct btrfs_disk_key key; + struct btrfs_file_extent_item *extent; + int res = 0; + u64 rd, seek_pointer = (u64) -1ULL, offset_in_extent; + BOOLEAN find_res; + + TRACE("btrfs_file_read inr=%llu offset=%llu size=%llu\n", inr, offset, size); + + key.objectid = inr; + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = offset; + init_path(&path); + + find_res = BtrFsSearchTree(root, &key, &path); + + /* if we found greater key, switch to the previous one */ + if (!find_res && btrfs_comp_keys(&key, path_current_disk_key(&path)) < 0) + { + if (prev_slot(&key, &path)) + goto out; + + } else if (btrfs_comp_keys_type(&key, path_current_disk_key(&path))) + { + goto out; + } + + seek_pointer = offset; + + do + { + TRACE("Current extent: (%llu %u %llu) \n", + path_current_disk_key(&path)->objectid, + path_current_disk_key(&path)->type, + path_current_disk_key(&path)->offset); + + extent = (struct btrfs_file_extent_item *) path_current_data(&path); + + offset_in_extent = seek_pointer; + /* check if we need clean extent offset when switching to the next extent */ + if ((seek_pointer) >= path_current_disk_key(&path)->offset) + offset_in_extent -= path_current_disk_key(&path)->offset; + + if (extent->type == BTRFS_FILE_EXTENT_INLINE) + { + rd = btrfs_read_extent_inline(&path, extent, offset_in_extent, size, buf); + } + else + { + rd = btrfs_read_extent_reg(&path, extent, offset_in_extent, size, buf); + } + + if (rd == -1ULL) + { + ERR("Error while reading extent\n"); + seek_pointer = (u64) -1ULL; + goto out; + } + + buf += rd; + seek_pointer += rd; + size -= rd; + TRACE("file_read size=%llu rd=%llu seek_pointer=%llu\n", size, rd, seek_pointer); + + if (!size) + break; + } while (!(res = next_slot(&key, &path))); + + if (res) + { + seek_pointer = (u64) -1ULL; + goto out; + } + + seek_pointer -= offset; + out: + free_path(&path); + return seek_pointer; +} + +//////////////////////////////////////// +///////////// INODE +//////////////////////////////////////// + + +static u64 btrfs_lookup_inode_ref(const struct btrfs_root_item *root, u64 inr, + struct btrfs_inode_ref *refp, char *name) +{ + struct btrfs_path path; + struct btrfs_inode_ref *ref; + u64 ret = -1ULL; + init_path(&path); + + if (BtrFsSearchTreeType(root, inr, BTRFS_INODE_REF_KEY, &path)) + { + ref = (struct btrfs_inode_ref *) path_current_data(&path); + + if (refp) + *refp = *ref; + ret = path_current_disk_key(&path)->offset; + } + + free_path(&path); + return ret; +} + +static int btrfs_lookup_inode(const struct btrfs_root_item *root, + struct btrfs_disk_key *location, + struct btrfs_inode_item *item, + struct btrfs_root_item *new_root) +{ + const struct btrfs_root_item tmp_root = *root; + struct btrfs_path path; + int res = -1; + +// if (location->type == BTRFS_ROOT_ITEM_KEY) { +// if (btrfs_find_root(location->objectid, &tmp_root, NULL)) +// return -1; +// +// location->objectid = tmp_root.root_dirid; +// location->type = BTRFS_INODE_ITEM_KEY; +// location->offset = 0; +// } + init_path(&path); + TRACE("Searching inode (%llu %u %llu)\n", location->objectid, location->type, location->offset); + + if (BtrFsSearchTree(&tmp_root, location, &path)) + { + if (item) + *item = *((struct btrfs_inode_item *) path_current_data(&path)); + + if (new_root) + *new_root = tmp_root; + + res = 0; + } + + free_path(&path); + return res; +} + +static BOOLEAN btrfs_readlink(const struct btrfs_root_item *root, u64 inr, char **target) +{ + struct btrfs_path path; + struct btrfs_file_extent_item *extent; + char *data_ptr; + BOOLEAN res = FALSE; + + init_path(&path); + + if (!BtrFsSearchTreeType(root, inr, BTRFS_EXTENT_DATA_KEY, &path)) + goto out; + + extent = (struct btrfs_file_extent_item *) path_current_data(&path); + if (extent->type != BTRFS_FILE_EXTENT_INLINE) + { + ERR("Extent for symlink %llu not of INLINE type\n", inr); + goto out; + } + + if (extent->compression != BTRFS_COMPRESS_NONE) + { + ERR("Symlink %llu extent data compressed!\n", inr); + goto out; + } + else if (extent->encryption != 0) + { + ERR("Symlink %llu extent data encrypted!\n", inr); + goto out; + } + else if (extent->ram_bytes >= BtrFsInfo->SuperBlock.sectorsize) + { + ERR("Symlink %llu extent data too long (%llu)!\n", inr, extent->ram_bytes); + goto out; + } + + data_ptr = (char *) extent + offsetof( + struct btrfs_file_extent_item, disk_bytenr); + + *target = FrLdrTempAlloc(extent->ram_bytes + 1, TAG_BTRFS_LINK); + if (!*target) + { + ERR("Cannot allocate %llu bytes\n", extent->ram_bytes + 1); + goto out; + } + + memcpy(*target, data_ptr, extent->ram_bytes); + (*target)[extent->ram_bytes] = '\0'; + + res = TRUE; + + out: + free_path(&path); + return res; +} + +/* inr must be a directory (for regular files with multiple hard links this + function returns only one of the parents of the file) */ +static u64 get_parent_inode(const struct btrfs_root_item *root, u64 inr, + struct btrfs_inode_item *inode_item) +{ + struct btrfs_disk_key key; + u64 res; + + if (inr == BTRFS_FIRST_FREE_OBJECTID) + { +// if (root->objectid != btrfs_info.fs_root.objectid) { +// u64 parent; +// struct btrfs_root_ref ref; +// +// parent = btrfs_lookup_root_ref(root->objectid, &ref, +// NULL); +// if (parent == -1ULL) +// return -1ULL; +// +// if (btrfs_find_root(parent, root, NULL)) +// return -1ULL; +// +// inr = ref.dirid; +// } + + if (inode_item) + { + key.objectid = inr; + key.type = BTRFS_INODE_ITEM_KEY; + key.offset = 0; + + if (btrfs_lookup_inode(root, &key, inode_item, NULL)) + return INVALID_INODE; + } + + return inr; + } + + res = btrfs_lookup_inode_ref(root, inr, NULL, NULL); + if (res == INVALID_INODE) + return INVALID_INODE; + + if (inode_item) + { + key.objectid = res; + key.type = BTRFS_INODE_ITEM_KEY; + key.offset = 0; + + if (btrfs_lookup_inode(root, &key, inode_item, NULL)) + return INVALID_INODE; + } + + return res; +} + +static inline int next_length(const char *path) +{ + int res = 0; + while (*path != '\0' && *path != '/' && *path != '\\' && res <= BTRFS_NAME_MAX) + ++res, ++path; + return res; +} + +static inline const char *skip_current_directories(const char *cur) +{ + while (1) + { + if (cur[0] == '/' || cur[0] == '\\') + ++cur; + else if (cur[0] == '.' && (cur[1] == '/' || cur[1] == '\\')) + cur += 2; + else + break; + } + + return cur; +} + +static u64 btrfs_lookup_path(const struct btrfs_root_item *root, u64 inr, const char *path, + u8 *type_p, struct btrfs_inode_item *inode_item_p, int symlink_limit) +{ + struct btrfs_dir_item item; + struct btrfs_inode_item inode_item; + u8 type = BTRFS_FT_DIR; + int len, have_inode = 0; + const char *cur = path; + struct btrfs_disk_key key; + char *link_target = NULL; + + if (*cur == '/' || *cur == '\\') + { + ++cur; + inr = root->root_dirid; + } + + do + { + cur = skip_current_directories(cur); + + len = next_length(cur); + if (len > BTRFS_NAME_MAX) + { + ERR("%s: Name too long at \"%.*s\"\n", BTRFS_NAME_MAX, cur); + return -1ULL; + } + + if (len == 1 && cur[0] == '.') + break; + + if (len == 2 && cur[0] == '.' && cur[1] == '.') + { + cur += 2; + inr = get_parent_inode(root, inr, &inode_item); + if (inr == INVALID_INODE) + return INVALID_INODE; + + type = BTRFS_FT_DIR; + continue; + } + + if (!*cur) + break; + + if (!BtrFsLookupDirItem(root, inr, cur, len, &item)) + { + TRACE("Try to find case-insensitive, path=%s inr=%llu s=%.*s\n", path, inr, len, cur); + if (!BtrFsLookupDirItemI(root, inr, cur, len, &item)) + return INVALID_INODE; + } + + type = item.type; + have_inode = 1; + if (btrfs_lookup_inode(root, &item.location, &inode_item, NULL)) + return INVALID_INODE; + + if (type == BTRFS_FT_SYMLINK && symlink_limit >= 0) + { + if (!symlink_limit) + { + TRACE("%s: Too much symlinks!\n"); + return INVALID_INODE; + } + + /* btrfs_readlink allocates link_target by itself */ + if (!btrfs_readlink(root, item.location.objectid, &link_target)) + return INVALID_INODE; + + inr = btrfs_lookup_path(root, inr, link_target, &type, &inode_item, symlink_limit - 1); + + FrLdrTempFree(link_target, TAG_BTRFS_LINK); + + if (inr == INVALID_INODE) + return INVALID_INODE; + } else if (type != BTRFS_FT_DIR && cur[len]) + { + TRACE("%s: \"%.*s\" not a directory\n", (int) (cur - path + len), path); + return INVALID_INODE; + } else + { + inr = item.location.objectid; + } + + cur += len; + } while (*cur); + + if (type_p) + *type_p = type; + + if (inode_item_p) + { + if (!have_inode) + { + key.objectid = inr; + key.type = BTRFS_INODE_ITEM_KEY; + key.offset = 0; + + if (btrfs_lookup_inode(root, &key, &inode_item, NULL)) + return INVALID_INODE; + } + + *inode_item_p = inode_item; + } + + return inr; +} + + +ARC_STATUS BtrFsClose(ULONG FileId) +{ + pbtrfs_file_info phandle = FsGetDeviceSpecific(FileId); + TRACE("BtrFsClose %lu\n", FileId); + + FrLdrTempFree(phandle, TAG_BTRFS_FILE); + + return ESUCCESS; +} + +ARC_STATUS BtrFsGetFileInformation(ULONG FileId, FILEINFORMATION *Information) +{ + pbtrfs_file_info phandle = FsGetDeviceSpecific(FileId); + + TRACE("BtrFsGetFileInformation %lu\n", FileId); + + RtlZeroMemory(Information, sizeof(FILEINFORMATION)); + Information->EndingAddress.QuadPart = phandle->inode.size; + Information->CurrentAddress.QuadPart = phandle->position; + + TRACE("BtrFsGetFileInformation() FileSize = %llu\n", + Information->EndingAddress.QuadPart); + TRACE("BtrFsGetFileInformation() FilePointer = %llu\n", + Information->CurrentAddress.QuadPart); + + return ESUCCESS; +} + +ARC_STATUS BtrFsOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId) +{ + u64 inr; + u8 type; + + btrfs_file_info temp_file_info; + pbtrfs_file_info phandle; + + TRACE("BtrFsOpen %s\n", Path); + + if (OpenMode != OpenReadOnly) + return EACCES; + + inr = btrfs_lookup_path(&BtrFsInfo->FsRoot, BtrFsInfo->FsRoot.root_dirid, Path, &type, &temp_file_info.inode, 40); + + if (inr == -1ULL) + { + TRACE("Cannot lookup file %s\n", Path); + return ENOENT; + } + + if (type != BTRFS_FT_REG_FILE) + { + TRACE("Not a regular file: %s\n", Path); + return EISDIR; + } + + TRACE("found inode inr=%llu size=%llu\n", inr, temp_file_info.inode.size); + + temp_file_info.inr = inr; + temp_file_info.position = 0; + + phandle = FrLdrTempAlloc(sizeof(btrfs_file_info), TAG_BTRFS_FILE); + if (!phandle) + return ENOMEM; + + memcpy(phandle, &temp_file_info, sizeof(btrfs_file_info)); + + FsSetDeviceSpecific(*FileId, phandle); + return ESUCCESS; +} + +ARC_STATUS BtrFsRead(ULONG FileId, VOID *Buffer, ULONG Size, ULONG *BytesRead) +{ + pbtrfs_file_info phandle = FsGetDeviceSpecific(FileId); + u64 rd; + + TRACE("BtrFsRead %lu, size=%lu \n", FileId, Size); + + if (!Size) + Size = phandle->inode.size; + + if (Size > phandle->inode.size) + Size = phandle->inode.size; + + rd = btrfs_file_read(&BtrFsInfo->FsRoot, phandle->inr, phandle->position, Size, Buffer); + if (rd == -1ULL) + { + TRACE("An error occured while reading file %lu\n", FileId); + return ENOENT; + } + + *BytesRead = rd; + return ESUCCESS; +} + +ARC_STATUS BtrFsSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode) +{ + pbtrfs_file_info phandle = FsGetDeviceSpecific(FileId); + + TRACE("BtrFsSeek %lu NewFilePointer = %llu\n", FileId, Position->QuadPart); + + if (SeekMode != SeekAbsolute) + return EINVAL; + if (Position->QuadPart >= phandle->inode.size) + return EINVAL; + + phandle->position = Position->QuadPart; + return ESUCCESS; +} + +const DEVVTBL BtrFsFuncTable = +{ + BtrFsClose, + BtrFsGetFileInformation, + BtrFsOpen, + BtrFsRead, + BtrFsSeek, + L"btrfs", +}; + +const DEVVTBL *BtrFsMount(ULONG DeviceId) +{ + struct btrfs_path path; + struct btrfs_root_item fs_root_item; + + TRACE("Enter BtrFsMount(), sizeof %d %d\n", sizeof(struct BTRFS_INFO), sizeof(struct btrfs_super_block)); + + BtrFsInfo = FrLdrTempAlloc(sizeof(struct BTRFS_INFO), TAG_BTRFS_INFO); + if (!BtrFsInfo) + return NULL; + RtlZeroMemory(BtrFsInfo, sizeof(struct BTRFS_INFO)); + + /* Read the SuperBlock */ + if (!disk_read(BTRFS_SUPER_INFO_OFFSET, &BtrFsInfo->SuperBlock, sizeof(struct btrfs_super_block))) + { + FrLdrTempFree(BtrFsInfo, TAG_BTRFS_INFO); + return NULL; + } + + /* Check if SuperBlock is valid. If yes, return Ext2 function table */ + if (BtrFsInfo->SuperBlock.magic == BTRFS_MAGIC_N) + { + BtrFsInfo->DeviceId = DeviceId; + TRACE("BtrFsMount() superblock magic ok\n"); + + btrfs_init_crc32c(); + + btrfs_read_sys_chunk_array(); + btrfs_read_chunk_tree(); + + /* setup roots */ + fs_root_item.bytenr = BtrFsInfo->SuperBlock.root; + fs_root_item.level = BtrFsInfo->SuperBlock.root_level; + + init_path(&path); + if (!BtrFsSearchTreeType(&fs_root_item, BTRFS_FS_TREE_OBJECTID, BTRFS_ROOT_ITEM_KEY, &path)) + { + FrLdrTempFree(BtrFsInfo, TAG_BTRFS_INFO); + free_path(&path); + return NULL; + } + + BtrFsInfo->FsRoot = *(struct btrfs_root_item *) path_current_data(&path); + + free_path(&path); + + TRACE("BtrFsMount success\n"); + + return &BtrFsFuncTable; + } + else + { + return NULL; + } +} diff --git a/boot/freeldr/freeldr/lib/fs/fs.c b/boot/freeldr/freeldr/lib/fs/fs.c index 74958d0427..b1de1603fd 100644 --- a/boot/freeldr/freeldr/lib/fs/fs.c +++ b/boot/freeldr/freeldr/lib/fs/fs.c @@ -152,6 +152,8 @@ ARC_STATUS ArcOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId) if (!FileData[DeviceId].FileFuncTable) #endif FileData[DeviceId].FileFuncTable = FatMount(DeviceId); + if (!FileData[DeviceId].FileFuncTable) + FileData[DeviceId].FileFuncTable = BtrFsMount(DeviceId); #ifndef _M_ARM if (!FileData[DeviceId].FileFuncTable) FileData[DeviceId].FileFuncTable = NtfsMount(DeviceId); diff --git a/boot/freeldr/freeldr/ntldr/winldr.c b/boot/freeldr/freeldr/ntldr/winldr.c index aaf1d9da56..b11015600a 100644 --- a/boot/freeldr/freeldr/ntldr/winldr.c +++ b/boot/freeldr/freeldr/ntldr/winldr.c @@ -488,15 +488,15 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion, /* Initialize SystemRoot\System32 path */ strcpy(DirPath, BootPath); - strcat(DirPath, "SYSTEM32\\"); + strcat(DirPath, "system32\\"); // // TODO: Parse also the separate INI values "Kernel=" and "Hal=" // /* Default KERNEL and HAL file names */ - strcpy(KernelFileName, "NTOSKRNL.EXE"); - strcpy(HalFileName , "HAL.DLL"); + strcpy(KernelFileName, "ntoskrnl.exe"); + strcpy(HalFileName , "hal.dll"); /* Find any /KERNEL= or /HAL= switch in the boot options */ Options = BootOptions; @@ -544,10 +544,10 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion, TRACE("Kernel file = '%s' ; HAL file = '%s'\n", KernelFileName, HalFileName); /* Load the Kernel */ - LoadModule(LoaderBlock, DirPath, KernelFileName, "NTOSKRNL.EXE", LoaderSystemCode, KernelDTE, 30); + LoadModule(LoaderBlock, DirPath, KernelFileName, "ntoskrnl.exe", LoaderSystemCode, KernelDTE, 30); /* Load the HAL */ - LoadModule(LoaderBlock, DirPath, HalFileName, "HAL.DLL", LoaderHalCode, &HalDTE, 45); + LoadModule(LoaderBlock, DirPath, HalFileName, "hal.dll", LoaderHalCode, &HalDTE, 45); /* Load the Kernel Debugger Transport DLL */ if (OperatingSystemVersion > _WIN32_WINNT_WIN2K) @@ -630,7 +630,7 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion, * Load the transport DLL. Override the base DLL name of the * loaded transport DLL to the default "KDCOM.DLL" name. */ - LoadModule(LoaderBlock, DirPath, KdTransportDllName, "KDCOM.DLL", LoaderSystemCode, &KdComDTE, 60); + LoadModule(LoaderBlock, DirPath, KdTransportDllName, "kdcom.dll", LoaderSystemCode, &KdComDTE, 60); } } diff --git a/boot/freeldr/freeldr/ntldr/wlregistry.c b/boot/freeldr/freeldr/ntldr/wlregistry.c index bf194027cf..40e297e9cb 100644 --- a/boot/freeldr/freeldr/ntldr/wlregistry.c +++ b/boot/freeldr/freeldr/ntldr/wlregistry.c @@ -126,7 +126,7 @@ BOOLEAN WinLdrInitSystemHive(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, // FIXME: For now we only try system strcpy(SearchPath, DirectoryPath); - strcat(SearchPath, "SYSTEM32\\CONFIG\\"); + strcat(SearchPath, "system32\\config\\"); Success = WinLdrLoadSystemHive(LoaderBlock, SearchPath, "SYSTEM"); // Fail if failed... @@ -173,7 +173,7 @@ BOOLEAN WinLdrScanSystemHive(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, // Load NLS data strcpy(SearchPath, DirectoryPath); - strcat(SearchPath, "SYSTEM32\\"); + strcat(SearchPath, "system32\\"); Success = WinLdrLoadNLSData(LoaderBlock, SearchPath, AnsiName, OemName, LangName); TRACE("NLS data loading %s\n", Success ? "successful" : "failed");
6 years, 4 months
1
0
0
0
01/04: [USETUP][SETUPLIB] Added support for formatting partition in BTRFS and installing ReactOS on it. Removed code related to EXT2 boot sector for now. CORE-13769
by Victor Perevertkin
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=07bc92f740a5e4f70a82c…
commit 07bc92f740a5e4f70a82c5835a5e9266c9967462 Author: Victor Perevertkin <victor(a)perevertkin.ru> AuthorDate: Thu Jun 14 02:30:06 2018 +0300 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Mon Aug 20 08:26:56 2018 +0200 [USETUP][SETUPLIB] Added support for formatting partition in BTRFS and installing ReactOS on it. Removed code related to EXT2 boot sector for now. CORE-13769 --- base/setup/lib/fsutil.c | 14 ++++-- base/setup/usetup/CMakeLists.txt | 2 +- base/setup/usetup/bootsup.c | 73 ++++++++++++++++++++++---------- boot/bootdata/txtsetup.sif | 1 + drivers/filesystems/btrfs/CMakeLists.txt | 2 +- 5 files changed, 63 insertions(+), 29 deletions(-) diff --git a/base/setup/lib/fsutil.c b/base/setup/lib/fsutil.c index bec91c4988..db1f3073be 100644 --- a/base/setup/lib/fsutil.c +++ b/base/setup/lib/fsutil.c @@ -24,6 +24,7 @@ #include "partlist.h" #include <fslib/vfatlib.h> +#include <fslib/btrfslib.h> // #include <fslib/ext2lib.h> // #include <fslib/ntfslib.h> @@ -42,7 +43,9 @@ FILE_SYSTEM RegisteredFileSystems[] = { L"EXT2" , Ext2Format, Ext2Chkdsk }, { L"EXT3" , Ext2Format, Ext2Chkdsk }, { L"EXT4" , Ext2Format, Ext2Chkdsk }, +#endif { L"BTRFS", BtrfsFormatEx, BtrfsChkdskEx }, +#if 0 { L"FFS" , FfsFormat , FfsChkdsk }, { L"REISERFS", ReiserfsFormat, ReiserfsChkdsk }, #endif @@ -283,11 +286,10 @@ GetFileSystem( { FileSystemName = L"FAT"; } - else if (PartEntry->PartitionType == PARTITION_EXT2) + else if (PartEntry->PartitionType == PARTITION_LINUX) { // WARNING: See the warning above. - FileSystemName = L"EXT2"; - // FIXME: We may have EXT3, 4 too... + FileSystemName = L"BTRFS"; } else if (PartEntry->PartitionType == PARTITION_IFS) { @@ -303,7 +305,7 @@ Quit: // For code temporarily disabled above // HACK: WARNING: We cannot write on this FS yet! if (FileSystemName) { - if (PartEntry->PartitionType == PARTITION_EXT2 || PartEntry->PartitionType == PARTITION_IFS) + if (PartEntry->PartitionType == PARTITION_IFS) DPRINT1("Recognized file system %S that doesn't support write support yet!\n", FileSystemName); } @@ -375,6 +377,10 @@ PreparePartitionForFormatting( } } } + else if (wcscmp(FileSystem->FileSystemName, L"BTRFS") == 0) + { + SetPartitionType(PartEntry, PARTITION_LINUX); + } #if 0 else if (wcscmp(FileSystem->FileSystemName, L"EXT2") == 0) { diff --git a/base/setup/usetup/CMakeLists.txt b/base/setup/usetup/CMakeLists.txt index 13aea12e16..db5b7d713b 100644 --- a/base/setup/usetup/CMakeLists.txt +++ b/base/setup/usetup/CMakeLists.txt @@ -41,6 +41,6 @@ endif() add_pch(usetup usetup.h SOURCE) set_module_type(usetup nativecui) -target_link_libraries(usetup inflib setuplib zlib_solo ext2lib vfatlib) +target_link_libraries(usetup inflib setuplib zlib_solo ext2lib vfatlib btrfslib) add_importlibs(usetup ntdll) add_cd_file(TARGET usetup DESTINATION reactos/system32 NO_CAB NAME_ON_CD smss.exe FOR bootcd regtest) diff --git a/base/setup/usetup/bootsup.c b/base/setup/usetup/bootsup.c index b59767131b..309e096d39 100644 --- a/base/setup/usetup/bootsup.c +++ b/base/setup/usetup/bootsup.c @@ -79,12 +79,16 @@ typedef struct _FAT32_BOOTSECTOR } FAT32_BOOTSECTOR, *PFAT32_BOOTSECTOR; -typedef struct _EXT2_BOOTSECTOR +typedef struct _BTRFS_BOOTSECTOR { - // The EXT2 bootsector is completely user-specific. - // No FS data is stored there. - UCHAR Fill[1024]; -} EXT2_BOOTSECTOR, *PEXT2_BOOTSECTOR; + UCHAR JumpBoot[3]; + UCHAR ChunkMapSize; + UCHAR BootDrive; + ULONGLONG PartitionStartLBA; + UCHAR Fill[1521]; // 1536 - 15 + USHORT BootSectorMagic; +} BTRFS_BOOTSECTOR, *PBTRFS_BOOTSECTOR; +C_ASSERT(sizeof(BTRFS_BOOTSECTOR) == 3 * 512); // TODO: Add more bootsector structures! @@ -1837,7 +1841,7 @@ InstallFat32BootCodeToDisk( static NTSTATUS -InstallExt2BootCodeToDisk( +InstallBtrfsBootCodeToDisk( PWSTR SrcPath, PWSTR RootPath) { @@ -1848,8 +1852,9 @@ InstallExt2BootCodeToDisk( HANDLE FileHandle; LARGE_INTEGER FileOffset; // PEXT2_BOOTSECTOR OrigBootSector; - PEXT2_BOOTSECTOR NewBootSector; + PBTRFS_BOOTSECTOR NewBootSector; // USHORT BackupBootSector; + PARTITION_INFORMATION_EX PartInfo; #if 0 /* Allocate buffer for original bootsector */ @@ -1897,7 +1902,7 @@ InstallExt2BootCodeToDisk( #endif /* Allocate buffer for new bootsector */ - NewBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(EXT2_BOOTSECTOR)); + NewBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(BTRFS_BOOTSECTOR)); if (NewBootSector == NULL) { // RtlFreeHeap(ProcessHeap, 0, OrigBootSector); @@ -1932,7 +1937,7 @@ InstallExt2BootCodeToDisk( NULL, &IoStatusBlock, NewBootSector, - sizeof(EXT2_BOOTSECTOR), + sizeof(BTRFS_BOOTSECTOR), NULL, NULL); NtClose(FileHandle); @@ -1981,6 +1986,28 @@ InstallExt2BootCodeToDisk( return Status; } + /* Obtaining partition info and writing it to bootsector */ + Status = NtDeviceIoControlFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + IOCTL_DISK_GET_PARTITION_INFO_EX, + NULL, + 0, + &PartInfo, + sizeof(PartInfo)); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("IOCTL_DISK_GET_PARTITION_INFO_EX failed (Status %lx)\n", Status); + NtClose(FileHandle); + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + return Status; + } + + NewBootSector->PartitionStartLBA = PartInfo.StartingOffset.QuadPart / SECTORSIZE; + /* Write sector 0 */ FileOffset.QuadPart = 0ULL; Status = NtWriteFile(FileHandle, @@ -1989,7 +2016,7 @@ InstallExt2BootCodeToDisk( NULL, &IoStatusBlock, NewBootSector, - sizeof(EXT2_BOOTSECTOR), + sizeof(BTRFS_BOOTSECTOR), &FileOffset, NULL); #if 0 @@ -2552,7 +2579,7 @@ InstallFatBootcodeToPartition( static NTSTATUS -InstallExt2BootcodeToPartition( +InstallBtrfsBootcodeToPartition( PUNICODE_STRING SystemRootPath, PUNICODE_STRING SourceRootPath, PUNICODE_STRING DestinationArcPath, @@ -2563,7 +2590,7 @@ InstallExt2BootcodeToPartition( WCHAR SrcPath[MAX_PATH]; WCHAR DstPath[MAX_PATH]; - /* EXT2 partition */ + /* BTRFS partition */ DPRINT("System path: '%wZ'\n", SystemRootPath); /* Copy FreeLoader to the system partition, always overwriting the older version */ @@ -2625,7 +2652,7 @@ InstallExt2BootcodeToPartition( CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector); DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); - Status = SaveBootSector(SystemRootPath->Buffer, DstPath, sizeof(EXT2_BOOTSECTOR)); + Status = SaveBootSector(SystemRootPath->Buffer, DstPath, sizeof(BTRFS_BOOTSECTOR)); if (!NT_SUCCESS(Status)) { DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); @@ -2645,14 +2672,14 @@ InstallExt2BootcodeToPartition( /* Install new bootsector on the disk */ // if (PartitionType == PARTITION_EXT2) { - /* Install EXT2 bootcode */ - CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\ext2.bin"); + /* Install BTRFS bootcode */ + CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\btrfs.bin"); - DPRINT1("Install EXT2 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); - Status = InstallExt2BootCodeToDisk(SrcPath, SystemRootPath->Buffer); + DPRINT1("Install BTRFS bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); + Status = InstallBtrfsBootCodeToDisk(SrcPath, SystemRootPath->Buffer); if (!NT_SUCCESS(Status)) { - DPRINT1("InstallExt2BootCodeToDisk() failed (Status %lx)\n", Status); + DPRINT1("InstallBtrfsBootCodeToDisk() failed (Status %lx)\n", Status); return Status; } } @@ -2684,12 +2711,12 @@ InstallVBRToPartition( PartitionType); } - case PARTITION_EXT2: + case PARTITION_LINUX: { - return InstallExt2BootcodeToPartition(SystemRootPath, - SourceRootPath, - DestinationArcPath, - PartitionType); + return InstallBtrfsBootcodeToPartition(SystemRootPath, + SourceRootPath, + DestinationArcPath, + PartitionType); } case PARTITION_IFS: diff --git a/boot/bootdata/txtsetup.sif b/boot/bootdata/txtsetup.sif index fc2aa63284..73eda6f7fa 100644 --- a/boot/bootdata/txtsetup.sif +++ b/boot/bootdata/txtsetup.sif @@ -56,6 +56,7 @@ pci.sys=,,,,,,,,,,,,4 scsiport.sys=,,,,,,x,,,,,,4 storport.sys=,,,,,,x,,,,,,4 fastfat.sys=,,,,,,x,,,,,,4 +btrfs.sys=,,,,,,x,,,,,,4 ramdisk.sys=,,,,,,x,,,,,,4 classpnp.sys=,,,,,,,,,,,,4 pciide.sys=,,,,,,,,,,,,4 diff --git a/drivers/filesystems/btrfs/CMakeLists.txt b/drivers/filesystems/btrfs/CMakeLists.txt index 123c9f0522..65e61d255a 100644 --- a/drivers/filesystems/btrfs/CMakeLists.txt +++ b/drivers/filesystems/btrfs/CMakeLists.txt @@ -41,4 +41,4 @@ add_definitions(-D__KERNEL__) set_module_type(btrfs kernelmodedriver) target_link_libraries(btrfs rtlver ntoskrnl_vista zlib_solo wdmguid ${PSEH_LIB}) add_importlibs(btrfs ntoskrnl hal) -add_cd_file(TARGET btrfs DESTINATION reactos/system32/drivers FOR all) +add_cd_file(TARGET btrfs DESTINATION reactos/system32/drivers NO_CAB FOR all)
6 years, 4 months
1
0
0
0
01/01: [UMPNPMGR] Simplify PNP_GetDeviceRegProp
by Eric Kohl
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=934104d73fddea67e1e27…
commit 934104d73fddea67e1e27a138d386e6e6b1587ba Author: Eric Kohl <eric.kohl(a)reactos.org> AuthorDate: Mon Aug 20 00:55:03 2018 +0200 Commit: Eric Kohl <eric.kohl(a)reactos.org> CommitDate: Mon Aug 20 00:55:03 2018 +0200 [UMPNPMGR] Simplify PNP_GetDeviceRegProp --- base/services/umpnpmgr/umpnpmgr.c | 89 ++++++--------------------------------- 1 file changed, 13 insertions(+), 76 deletions(-) diff --git a/base/services/umpnpmgr/umpnpmgr.c b/base/services/umpnpmgr/umpnpmgr.c index 02eaf05b3a..0a00d40325 100644 --- a/base/services/umpnpmgr/umpnpmgr.c +++ b/base/services/umpnpmgr/umpnpmgr.c @@ -782,7 +782,7 @@ PNP_GetDeviceRegProp( break; case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME; break; case CM_DRP_CAPABILITIES: @@ -790,7 +790,7 @@ PNP_GetDeviceRegProp( break; case CM_DRP_UI_NUMBER: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_UI_NUMBER; break; case CM_DRP_UPPERFILTERS: @@ -802,19 +802,19 @@ PNP_GetDeviceRegProp( break; case CM_DRP_BUSTYPEGUID: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_BUSTYPEGUID; break; case CM_DRP_LEGACYBUSTYPE: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_LEGACYBUSTYPE; break; case CM_DRP_BUSNUMBER: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_BUSNUMBER; break; case CM_DRP_ENUMERATOR_NAME: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_ENUMERATOR_NAME; break; case CM_DRP_SECURITY: @@ -834,7 +834,7 @@ PNP_GetDeviceRegProp( break; case CM_DRP_ADDRESS: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_ADDRESS; break; case CM_DRP_UI_NUMBER_DESC_FORMAT: @@ -842,15 +842,15 @@ PNP_GetDeviceRegProp( break; case CM_DRP_DEVICE_POWER_DATA: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_POWER_DATA; break; case CM_DRP_REMOVAL_POLICY: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY; break; case CM_DRP_REMOVAL_POLICY_HW_DEFAULT: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT; break; case CM_DRP_REMOVAL_POLICY_OVERRIDE: @@ -858,18 +858,18 @@ PNP_GetDeviceRegProp( break; case CM_DRP_INSTALL_STATE: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_INSTALL_STATE; break; #if (WINVER >= _WIN32_WINNT_WS03) case CM_DRP_LOCATION_PATHS: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_LOCATION_PATHS; break; #endif #if (WINVER >= _WIN32_WINNT_WIN7) case CM_DRP_BASE_CONTAINERID: - lpValueName = NULL; + PlugPlayData.Property = PNP_PROPERTY_CONTAINERID; break; #endif @@ -923,68 +923,6 @@ PNP_GetDeviceRegProp( PlugPlayData.Buffer = Buffer; PlugPlayData.BufferSize = *pulLength; - switch (ulProperty) - { - case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME: - PlugPlayData.Property = PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME; - break; - - case CM_DRP_UI_NUMBER: - PlugPlayData.Property = PNP_PROPERTY_UI_NUMBER; - break; - - case CM_DRP_BUSTYPEGUID: - PlugPlayData.Property = PNP_PROPERTY_BUSTYPEGUID; - break; - - case CM_DRP_LEGACYBUSTYPE: - PlugPlayData.Property = PNP_PROPERTY_LEGACYBUSTYPE; - break; - - case CM_DRP_BUSNUMBER: - PlugPlayData.Property = PNP_PROPERTY_BUSNUMBER; - break; - - case CM_DRP_ENUMERATOR_NAME: - PlugPlayData.Property = PNP_PROPERTY_ENUMERATOR_NAME; - break; - - case CM_DRP_ADDRESS: - PlugPlayData.Property = PNP_PROPERTY_ADDRESS; - break; - - case CM_DRP_DEVICE_POWER_DATA: - PlugPlayData.Property = PNP_PROPERTY_POWER_DATA; - break; - - case CM_DRP_REMOVAL_POLICY: - PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY; - break; - - case CM_DRP_REMOVAL_POLICY_HW_DEFAULT: - PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT; - break; - - case CM_DRP_INSTALL_STATE: - PlugPlayData.Property = PNP_PROPERTY_INSTALL_STATE; - break; - -#if (WINVER >= _WIN32_WINNT_WS03) - case CM_DRP_LOCATION_PATHS: - PlugPlayData.Property = PNP_PROPERTY_LOCATION_PATHS; - break; -#endif - -#if (WINVER >= _WIN32_WINNT_WIN7) - case CM_DRP_BASE_CONTAINERID: - PlugPlayData.Property = PNP_PROPERTY_CONTAINERID; - break; -#endif - - default: - return CR_INVALID_PROPERTY; - } - Status = NtPlugPlayControl(PlugPlayControlProperty, (PVOID)&PlugPlayData, sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA)); @@ -999,7 +937,6 @@ PNP_GetDeviceRegProp( } done: - if (pulTransferLen) *pulTransferLen = (ret == CR_SUCCESS) ? *pulLength : 0;
6 years, 4 months
1
0
0
0
01/01: [SETUPAPI] SetupDiGetDeviceRegistryPropertyW call CM_Get_DevNode_Registry_Property_ExW for properties that can not be retrieved from the registry
by Eric Kohl
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=91fab9e53b536ce462005…
commit 91fab9e53b536ce462005eb832e034cf4c3dc295 Author: Eric Kohl <eric.kohl(a)reactos.org> AuthorDate: Mon Aug 20 00:15:26 2018 +0200 Commit: Eric Kohl <eric.kohl(a)reactos.org> CommitDate: Mon Aug 20 00:16:18 2018 +0200 [SETUPAPI] SetupDiGetDeviceRegistryPropertyW call CM_Get_DevNode_Registry_Property_ExW for properties that can not be retrieved from the registry --- dll/win32/setupapi/devinst.c | 84 +++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/dll/win32/setupapi/devinst.c b/dll/win32/setupapi/devinst.c index 2aaa4962e2..73990f5952 100644 --- a/dll/win32/setupapi/devinst.c +++ b/dll/win32/setupapi/devinst.c @@ -3368,9 +3368,11 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW( DWORD PropertyBufferSize, PDWORD RequiredSize) { - BOOL ret = FALSE; struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet; struct DeviceInfo *devInfo; + CONFIGRET cr; + LONG lError = ERROR_SUCCESS; + DWORD size; TRACE("%p %p %d %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, @@ -3392,58 +3394,100 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW( SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } + + if (Property >= SPDRP_MAXIMUM_PROPERTY) + { + SetLastError(ERROR_INVALID_REG_PROPERTY); + return FALSE; + } + devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved; + if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0]) && PropertyMap[Property].nameW) { - DWORD size = PropertyBufferSize; HKEY hKey; - LONG l; + size = PropertyBufferSize; hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE); if (hKey == INVALID_HANDLE_VALUE) return FALSE; - l = RegQueryValueExW(hKey, PropertyMap[Property].nameW, - NULL, PropertyRegDataType, PropertyBuffer, &size); + lError = RegQueryValueExW(hKey, PropertyMap[Property].nameW, + NULL, PropertyRegDataType, PropertyBuffer, &size); RegCloseKey(hKey); if (RequiredSize) *RequiredSize = size; - switch(l) { + + switch (lError) + { case ERROR_SUCCESS: - if (PropertyBuffer != NULL || size == 0) - ret = TRUE; - else - SetLastError(ERROR_INSUFFICIENT_BUFFER); + if (PropertyBuffer == NULL && size != 0) + lError = ERROR_INSUFFICIENT_BUFFER; break; case ERROR_MORE_DATA: - SetLastError(ERROR_INSUFFICIENT_BUFFER); + lError = ERROR_INSUFFICIENT_BUFFER; break; default: - SetLastError(l); + break; } } else if (Property == SPDRP_PHYSICAL_DEVICE_OBJECT_NAME) { - DWORD required = (strlenW(devInfo->Data) + 1) * sizeof(WCHAR); + size = (strlenW(devInfo->Data) + 1) * sizeof(WCHAR); if (PropertyRegDataType) *PropertyRegDataType = REG_SZ; if (RequiredSize) - *RequiredSize = required; - if (PropertyBufferSize >= required) + *RequiredSize = size; + if (PropertyBufferSize >= size) { strcpyW((LPWSTR)PropertyBuffer, devInfo->Data); - ret = TRUE; } else - SetLastError(ERROR_INSUFFICIENT_BUFFER); + lError = ERROR_INSUFFICIENT_BUFFER; } else { - ERR("Property 0x%lx not implemented\n", Property); - SetLastError(ERROR_NOT_SUPPORTED); + size = PropertyBufferSize; + + cr = CM_Get_DevNode_Registry_Property_ExW(devInfo->dnDevInst, + Property + (CM_DRP_DEVICEDESC - SPDRP_DEVICEDESC), + PropertyRegDataType, + PropertyBuffer, + &size, + 0, + set->hMachine); + if ((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) + { + if (RequiredSize) + *RequiredSize = size; + } + + if (cr != CR_SUCCESS) + { + switch (cr) + { + case CR_INVALID_DEVINST: + lError = ERROR_NO_SUCH_DEVINST; + break; + + case CR_INVALID_PROPERTY: + lError = ERROR_INVALID_REG_PROPERTY; + break; + + case CR_BUFFER_SMALL: + lError = ERROR_INSUFFICIENT_BUFFER; + break; + + default : + lError = ERROR_INVALID_DATA; + break; + } + } } - return ret; + + SetLastError(lError); + return (lError == ERROR_SUCCESS); } /***********************************************************************
6 years, 4 months
1
0
0
0
01/01: [FONT][WIN32SS] Refactor the loop (1 of 5)
by Katayama Hirofumi MZ
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=5daa7b07c868fd5a7db39…
commit 5daa7b07c868fd5a7db3922c0f83d29f864b6b59 Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com> AuthorDate: Mon Aug 20 06:08:38 2018 +0900 Commit: Mark Jansen <mark.jansen(a)reactos.org> CommitDate: Sun Aug 19 23:08:38 2018 +0200 [FONT][WIN32SS] Refactor the loop (1 of 5) --- win32ss/gdi/ntgdi/freetype.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c index e7a6cee516..5275b36576 100644 --- a/win32ss/gdi/ntgdi/freetype.c +++ b/win32ss/gdi/ntgdi/freetype.c @@ -266,16 +266,17 @@ RemoveCachedEntry(PFONT_CACHE_ENTRY Entry) static void RemoveCacheEntries(FT_Face Face) { - PLIST_ENTRY CurrentEntry; + PLIST_ENTRY CurrentEntry, NextEntry; PFONT_CACHE_ENTRY FontEntry; ASSERT_FREETYPE_LOCK_HELD(); - CurrentEntry = g_FontCacheListHead.Flink; - while (CurrentEntry != &g_FontCacheListHead) + for (CurrentEntry = g_FontCacheListHead.Flink; + CurrentEntry != &g_FontCacheListHead; + CurrentEntry = NextEntry) { FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry); - CurrentEntry = CurrentEntry->Flink; + NextEntry = CurrentEntry->Flink; if (FontEntry->Face == Face) {
6 years, 4 months
1
0
0
0
01/01: [FONT][WIN32SS] Refactor the loop (2 of 5)
by Katayama Hirofumi MZ
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c4e010776594ea0a46e55…
commit c4e010776594ea0a46e55ed360c89f9b506a7b21 Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com> AuthorDate: Sun Aug 19 13:36:31 2018 +0900 Commit: Mark Jansen <mark.jansen(a)reactos.org> CommitDate: Sun Aug 19 23:07:37 2018 +0200 [FONT][WIN32SS] Refactor the loop (2 of 5) --- win32ss/gdi/ntgdi/freetype.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c index 97d4b2d14c..e7a6cee516 100644 --- a/win32ss/gdi/ntgdi/freetype.c +++ b/win32ss/gdi/ntgdi/freetype.c @@ -1344,8 +1344,9 @@ IntGdiRemoveFontMemResource(HANDLE hMMFont) PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); IntLockProcessPrivateFonts(Win32Process); - Entry = Win32Process->PrivateMemFontListHead.Flink; - while (Entry != &Win32Process->PrivateMemFontListHead) + for (Entry = Win32Process->PrivateMemFontListHead.Flink; + Entry != &Win32Process->PrivateMemFontListHead; + Entry = Entry->Flink) { CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry); @@ -1355,8 +1356,6 @@ IntGdiRemoveFontMemResource(HANDLE hMMFont) UnlinkFontMemCollection(CurrentEntry); break; } - - Entry = Entry->Flink; } IntUnLockProcessPrivateFonts(Win32Process);
6 years, 4 months
1
0
0
0
01/01: [FONT][WIN32SS] Refactor the loop (4 of 5)
by Katayama Hirofumi MZ
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=b9b4c903037457ad12a85…
commit b9b4c903037457ad12a85dbec15ca3e2a54b7c9a Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com> AuthorDate: Sun Aug 19 13:38:06 2018 +0900 Commit: Mark Jansen <mark.jansen(a)reactos.org> CommitDate: Sun Aug 19 23:05:35 2018 +0200 [FONT][WIN32SS] Refactor the loop (4 of 5) --- win32ss/gdi/ntgdi/freetype.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c index 013c0bb6a4..97d4b2d14c 100644 --- a/win32ss/gdi/ntgdi/freetype.c +++ b/win32ss/gdi/ntgdi/freetype.c @@ -2672,8 +2672,9 @@ ftGdiGlyphCacheGet( ASSERT_FREETYPE_LOCK_HELD(); - CurrentEntry = g_FontCacheListHead.Flink; - while (CurrentEntry != &g_FontCacheListHead) + for (CurrentEntry = g_FontCacheListHead.Flink; + CurrentEntry != &g_FontCacheListHead; + CurrentEntry = CurrentEntry->Flink) { FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry); if ((FontEntry->Face == Face) && @@ -2682,7 +2683,6 @@ ftGdiGlyphCacheGet( (FontEntry->RenderMode == RenderMode) && (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx))) break; - CurrentEntry = CurrentEntry->Flink; } if (CurrentEntry == &g_FontCacheListHead)
6 years, 4 months
1
0
0
0
01/01: [FONT][WIN32SS] Refactor the loop (5 of 5)
by Katayama Hirofumi MZ
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7b04962aed7f6d017d4be…
commit 7b04962aed7f6d017d4bebb8dc5175f87ef9ed1e Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com> AuthorDate: Sun Aug 19 13:39:02 2018 +0900 Commit: Mark Jansen <mark.jansen(a)reactos.org> CommitDate: Sun Aug 19 23:05:04 2018 +0200 [FONT][WIN32SS] Refactor the loop (5 of 5) --- win32ss/gdi/ntgdi/freetype.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c index 94578a4047..013c0bb6a4 100644 --- a/win32ss/gdi/ntgdi/freetype.c +++ b/win32ss/gdi/ntgdi/freetype.c @@ -4592,11 +4592,9 @@ FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT); /* get the FontObj of lowest penalty */ - Entry = Head->Flink; - while (Entry != Head) + for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) { CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); - Entry = Entry->Flink; FontGDI = CurrentEntry->Font; ASSERT(FontGDI);
6 years, 4 months
1
0
0
0
← Newer
1
...
7
8
9
10
11
12
13
...
31
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Results per page:
10
25
50
100
200