diff options
Diffstat (limited to 'bitbake/lib/bb/xattr.py')
-rwxr-xr-x | bitbake/lib/bb/xattr.py | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/bitbake/lib/bb/xattr.py b/bitbake/lib/bb/xattr.py new file mode 100755 index 0000000000..7b634944a4 --- /dev/null +++ b/bitbake/lib/bb/xattr.py @@ -0,0 +1,126 @@ +#! /usr/bin/env python3 +# +# Copyright 2023 by Garmin Ltd. or its subsidiaries +# +# SPDX-License-Identifier: MIT + +import sys +import ctypes +import os +import errno + +libc = ctypes.CDLL("libc.so.6", use_errno=True) +fsencoding = sys.getfilesystemencoding() + + +libc.listxattr.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_size_t] +libc.llistxattr.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_size_t] + + +def listxattr(path, follow=True): + func = libc.listxattr if follow else libc.llistxattr + + os_path = os.fsencode(path) + + while True: + length = func(os_path, None, 0) + + if length < 0: + err = ctypes.get_errno() + raise OSError(err, os.strerror(err), str(path)) + + if length == 0: + return [] + + arr = ctypes.create_string_buffer(length) + + read_length = func(os_path, arr, length) + if read_length != length: + # Race! + continue + + return [a.decode(fsencoding) for a in arr.raw.split(b"\x00") if a] + + +libc.getxattr.argtypes = [ + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_size_t, +] +libc.lgetxattr.argtypes = [ + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_size_t, +] + + +def getxattr(path, name, follow=True): + func = libc.getxattr if follow else libc.lgetxattr + + os_path = os.fsencode(path) + os_name = os.fsencode(name) + + while True: + length = func(os_path, os_name, None, 0) + + if length < 0: + err = ctypes.get_errno() + if err == errno.ENODATA: + return None + raise OSError(err, os.strerror(err), str(path)) + + if length == 0: + return "" + + arr = ctypes.create_string_buffer(length) + + read_length = func(os_path, os_name, arr, length) + if read_length != length: + # Race! + continue + + return arr.raw + + +def get_all_xattr(path, follow=True): + attrs = {} + + names = listxattr(path, follow) + + for name in names: + value = getxattr(path, name, follow) + if value is None: + # This can happen if a value is erased after listxattr is called, + # so ignore it + continue + attrs[name] = value + + return attrs + + +def main(): + import argparse + from pathlib import Path + + parser = argparse.ArgumentParser() + parser.add_argument("path", help="File Path", type=Path) + + args = parser.parse_args() + + attrs = get_all_xattr(args.path) + + for name, value in attrs.items(): + try: + value = value.decode(fsencoding) + except UnicodeDecodeError: + pass + + print(f"{name} = {value}") + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) |