]> git.proxmox.com Git - pve-common.git/commitdiff
tools: add set/get xattr methods
authorThomas Lamprecht <t.lamprecht@proxmox.com>
Tue, 19 Oct 2021 06:18:00 +0000 (08:18 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Tue, 19 Oct 2021 06:18:00 +0000 (08:18 +0200)
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
src/PVE/Syscall.pm
src/PVE/Tools.pm

index 8dc21019b1b5ab7e9cc7458335630f0217258d5e..ee374d80932568a66df1281baf24d1221144c260 100644 (file)
@@ -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
index 5586910889c8dc710a17fec3555c57d7fdbe77ea..cacfc89f9b6b31e01a9ca354fbe54b019fca70ea 100644 (file)
@@ -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) = @_;