Dear list,

We've unearth an odd behaviour in cp: `cp --preserve=xattr` tries to copy both 
attributes of the chattr kind and extended attributes of the getfattr kind with 
apparently no way to disable either one of them (it's all or nothing). This is 
problematic in tools like mkosi where non-filesystem-specific xattributes need 
to be preserved whilst FS-specific attributes must be discarded for 
cross-filesystem support.

I have added a MWE at the end of this email after my signature: it creates two 
raw partitions as files (one as XFS, one as BTRFS), mounts them in local 
folders and creates 3 files in the BTRFS partitions later altered before copy.

Referring to the script, we think there should be an option to copy files foo 
(no-attr), bar (setfattr) and baz (chattr), keeping the setfattr's xattr and 
discarding chattr's attr. Looking at the code, it seems like cp eventually 
defers the actual attribute copying libattr, which seems to handle both, but 
separately (which is what we want).

Would it make sense to add a separate `attr` preserve value for the chattr case 
and keep `xattr` for getfattr case?

Thanks
Gaël



#!/bin/bash

workspace="/tmp/cp_attr"

echo "WORKDIR: ${workspace}"
echo
echo 'SETTING UP WORKSPACE'
mkdir -p ${workspace}/{xfs,btrfs}
truncate -s 512M ${workspace}/xfs.img
truncate -s 512M ${workspace}/btrfs.img

mkfs.xfs -q ${workspace}/xfs.img
mkfs.btrfs -q ${workspace}/btrfs.img

echo 'BECOMING ROOT'
sudo sh -c "
    cd ${workspace}
    echo '  - mounting filesystems'
    mount -o loop xfs.img xfs
    mount -o loop btrfs.img btrfs
    echo '  - creating files in BTRFS'
    touch btrfs/{foo,bar,baz}

    echo '  - original attr state:'
    lsattr btrfs/

    echo '  - original xattr state:'
    getfattr btrfs/*

    echo

    echo 'CHANGING ATTRIBUTES'
    echo '  - unchanged: btrfs/foo'
    echo '  - set xattr: btrfs/bar | setfattr -n user.foobar -v BAR'
    setfattr -n user.foobar -v BAR btrfs/bar

    echo '  - set  attr: btrfs/baz | chattr +c btrfs/baz'
    chattr +c btrfs/baz

    echo '  - current attr state:'
    lsattr btrfs/

    echo '  - current xattr state:'
    getfattr btrfs/*

    echo

    echo 'COPIES'
    # Works:
    echo '  - copying btrfs/foo -> xfs/foo'
    cp --preserve=xattr btrfs/foo xfs/ && echo 'Success!' || echo 'Failed!'
    
    # Works:
    echo '  - copying btrfs/bar -> xfs/bar'
    cp --preserve=xattr btrfs/bar xfs/ && echo 'Success!' || echo 'Failed!'

    # PROBLEM IS RIGHT HERE:
    echo '  - copying btrfs/baz -> xfs/baz'
    cp --preserve=xattr btrfs/baz xfs/ && echo 'Success!' || echo 'Failed!'


    umount btrfs
    umount xfs
"

rm ${workspace}/{xfs,btrfs}.img
rmdir ${workspace}/{xfs,btrfs}


Reply via email to