From 4c0c5c905dbc7ed9c62a0b29a82b1dfd687769dc Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Tue, 19 Oct 2021 08:18:00 +0200 Subject: [PATCH] tools: add set/get xattr methods Signed-off-by: Thomas Lamprecht --- src/PVE/Syscall.pm | 4 ++++ src/PVE/Tools.pm | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/PVE/Syscall.pm b/src/PVE/Syscall.pm index 8dc2101..ee374d8 100644 --- a/src/PVE/Syscall.pm +++ b/src/PVE/Syscall.pm @@ -24,6 +24,10 @@ BEGIN { fsconfig => &SYS_fsconfig, fsmount => &SYS_fsmount, fspick => &SYS_fspick, + getxattr => &SYS_getxattr, + setxattr => &SYS_setxattr, + fgetxattr => &SYS_fgetxattr, + fsetxattr => &SYS_fsetxattr, # Below aren't yet in perl's syscall.ph but use asm-generic, so the same across (sane) archs # -> none unknown currently, yay diff --git a/src/PVE/Tools.pm b/src/PVE/Tools.pm index 5586910..cacfc89 100644 --- a/src/PVE/Tools.pm +++ b/src/PVE/Tools.pm @@ -1864,6 +1864,40 @@ sub mount($$$$$) { ); } +# size is optional and defaults to 256, note that xattr limits are FS specific and that xattrs can +# get arbitrary long. NOTE: $! is set to ENOBUFS if the xattr is longer than the buffer size used. +sub getxattr($$;$) { + my ($path_or_handle, $name, $size) = @_; + $size //= 256; + my $buf = pack("x${size}"); + + my $xattr_size = -1; # the actual size of the xattr, can be zero + if (defined(my $fd = fileno($path_or_handle))) { + $xattr_size = syscall(&PVE::Syscall::fgetxattr, $fd, $name, $buf, $size); + } else { + $xattr_size = syscall(&PVE::Syscall::getxattr, $path_or_handle, $name, $buf, $size); + } + if ($xattr_size < 0) { + warn "$xattr_size <0 - $!"; + return undef; + } elsif ($xattr_size > $size) { + $! = POSIX::ENOBUFS; + } + return wantarray ? ($buf, $xattr_size) : $buf; +} + +# NOTE: can take either a path or an open file handle, i.e., its multiplexing setxattr and fsetxattr +sub setxattr($$$;$) { + my ($path_or_handle, $name, $value, $flags) = @_; + my $size = length($value); # NOTE: seems to get correct length also for wide-characters in text.. + + if (defined(my $fd = fileno($path_or_handle))) { + return 0 == syscall(&PVE::Syscall::fsetxattr, $fd, $name, $value, $size, $flags // 0); + } else { + return 0 == syscall(&PVE::Syscall::setxattr, $path_or_handle, $name, $value, $size, $flags // 0); + } +} + sub safe_compare { my ($left, $right, $cmp) = @_; -- 2.39.2