Extended Attributes
From the bestbits.at (Archive) site:
Extended attributes are arbitrary name/value pairs which are associated with files or directories. They can be used to store system objects like capabilities of executables and access control lists, as well as user objects.
Extended Attributes (EA) are implemented differently on each operating system. This article tries to give a short overview and some usage examples for various operating systems. In most implementations, EAs follow the same schema "namespace:attribute:value".
FreeBSD
FreeBSD supports EAs on UFS and ZFS. For ZFS, extended attributes can be enabled on a per-filesystem basis.
Only root can query the system namespace:
$ lsextattr system test.txt lsextattr: test_xattr.img: failed: Operation not permitted
Let's see if the user namespace has some EAs set:
$ lsextattr user test.txt test.txt foo
Let's get the value of our attribute foo:
$ getextattr user foo test.txt test.txt 42
Let's change the value and add another attribute:
$ setextattr user foo 23 test.txt $ setextattr user bar 42 test.txt $ getextattr user foo test.txt test.txt 23 $ getextattr user bar test.txt test.txt 42
Remove attributes:
rmextattr user foo test.txt rmextattr user bar test.txt
Note that adding EAs to a file might take up some space if the EA does not fit into the file's inode space:[1]
$ stat -f "File: %N Size: %z Blocks: %b" test.txt
File: test.txt Size: 25170 Blocks: 56
$ setextattr user sha256 `sha256 -q test.txt` test.txt
$ stat -f "File: %N Size: %z Blocks: %b" test.txt
File: test.txt Size: 25170 Blocks: 64
Linux
Linux supports EAs on many (but not all) filesystems:
- ext2, ext3, reiserfs - when mounted with user_xattr
- ext4[2], btrfs, jfs, xfs
List all EAs and their values on a file:
$ getfattr -d test.txt # file: test.txt user.foo="23"
Here, the namespace ("user") is already printed. When we try to access the attribute w/o specifying its namespace, this happens:
$ getfattr -n foo test.txt test.txt: foo: Operation not supported
When specifying the namespace, this works:
$ getfattr -n user.foo --only-values test.txt 23
Add a new EA, remove user.foo:
$ setfattr -n user.bar -v 42 test.txt $ setfattr -x user.foo test.txt $ getfattr -d test.txt # file: test.txt user.bar="42"
There's also attr(5), which is described in its manpage as:
attr - extended attributes on XFS filesystem objects
However, this works quite well on other filesystems too and can be used to operate on the root namespace. Let's look at the getfattr call again, but this time through strace(1):
lstat("test.txt", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 getxattr("test.txt", "foo", 0x0, 0) = -1 EOPNOTSUPP (Operation not supported)
Try again with attr(1):
$ attr -R -s foo -V bar test.txt Attribute "foo" set to a 3 byte value for test.txt: bar $ attr -l test.txt Attribute "foo" has a 3 byte value for test.txt
We have to specify the correct namespace:
$ attr -g foo test.txt
attr_get: No data available
Could not get "foo" for test.txt
$ attr -R -g foo test.txt
Attribute "foo" had a 3 byte value for test.txt:
bar
Remove the EA from the root namespace again:
attr -R -r foo test.txt
Note that adding EAs to a file might take up some space if the EA does not fit into the file's inode space:[1]
$ stat -c "File: %n Size: %s Blocks: %b" test.txt
File: test.txt Size: 25170 Blocks: 56
$ setfattr -n user.sha512 -v "`sha512sum test.txt`" test.txt
$ stat -c "File: %n Size: %s Blocks: %b" test.txt
File: test.txt Size: 25170 Blocks: 64
- The system namespace is reserved for the system administrator and/or the kernel.
- The user namespace is reserved for general usage. That is, to store arbitrary combinations of attribute and value to a filesystem object.
- The security.selinux namespace is reserved for SELinux attributes.
MacOS X
In MacOS X, EAs are managed by xattr(1), a Python script apparently:
$ xattr -l test.txt bar: 4242 foo: 42
Print only a specific attribute:
$ xattr -p foo test.txt 42
We can also use plain old ls(1) to display EAs and the size of their values:
$ ls -l test.txt -rw-------@ 1 dummy dummy 1024 Apr 9 12:49 test.txt $ ls -l@ test.txt -rw-------@ 1 dummy dummy 1024 Apr 9 12:49 test.txt bar 4 foo 2
Let's change a value, add another attribute, and delete an attribute:
$ xattr -w foo 23 test.txt $ xattr -w baz 10 test.txt $ xattr -d bar test.txt $ xattr -l test.txt baz: 10 foo: 23
MacOS can store incredibly long amounts of EA information without the file taking more space:
$ stat -f "File: %N Size: %z Blocks: %b" test.txt File: test.txt Size: 1024 Blocks: 8 $ seq 1 131100 | while read a; do echo "a: $a" xattr -w foo "`seq $a | while read f; do printf x; done`" test.txt || break done [...] a: 131070 a: 131071 a: 131072 a: 131073 xattr: [Errno 7] Argument list too long: 'test.txt'
$ stat -f "File: %N Size: %z Blocks: %b" test.txt File: test.txt Size: 1024 Blocks: 8
But we have ~128K of EA material stored:
$ xattr -l test.txt > test.ea $ ls -lgo test.ea -rw------- 1 131078 Apr 9 13:35 test.ea
So where does MacOS X store this EA?[3] In a resource fork, apparently:
$ mv test.txt /mnt/smb/data/tmp/
Now, on that Samba server, we can see how the resource fork is stored in a separate file on this non-HFS+ filesystem:
% ls -lgo test.txt ._test.txt
-rw------- 1 135168 Apr 9 13:40 ._test.txt
-rwx------ 1 1024 Apr 9 13:40 test.txt
Solaris
Solaris supports EAs on UFS[4], NFS[5], TMPFS[6] and ZFS[7] (but can be disabled by mounting with noxattr). Sadly, its usage[8] is rather cryptic:
$ ls -lgo test.txt -rw------- 1 1024 Apr 10 01:51 test.txt $ du -sk test.txt 1 test.txt $ runat test.txt cp /etc/hosts /usr/bin/ksh . $ runat test.txt ls -l total 519 -rw------- 1 dummy users 168 Apr 10 01:52 hosts -r-x--x--x 1 dummy users 171412 Apr 10 01:52 ksh $ runat test.txt cat hosts ::1 localhost 127.0.0.1 localhost
Now let's see what we can do with that:
$ ls -lgo test.txt -rw------- 1 1024 Apr 10 01:51 test.txt $ ls -@go test.txt -rw-------@ 1 1024 Apr 10 01:51 test.txt
But du(1) reveals that we have gained some weight:
$ du -sk test.txt 262 test.txt
We can even execute the ksh binary attached to it:
$ runat test.txt ./ksh cannot access parent directories %% ls -la total 525 drwxrwxrwt 2 dummy users 4 Apr 10 01:52 . -rw------- 1 dummy users 1024 Apr 10 01:51 .. -rw------- 1 dummy users 168 Apr 10 01:52 hosts -r-x--x--x 1 dummy users 171412 Apr 10 01:52 ksh %% pwd cannot access parent directories %% cd .. ./ksh: ..: not a directory %% exit
Let's try something more useful:
$ runat test.txt "echo \"`digest -a sha256 -v test.txt`\" > checksum.sha256"
Note: since there is no "test.txt" within this file's namespace, we have to run digest in our original namespace and echo its value into a new file, checksum.sha256. We also have to use quotes ("), otherwise checksum.sha256 would have been created in out original namespace. And since the verbose output from digest(1) includes spaces, we have to quote its output again. Pretty ugly, hm?
$ ls -@go test.txt -rw-------@ 1 1024 Apr 10 03:00 test.txt $ runat test.txt ls -lgo total 2 -rw------- 1 65 Apr 10 03:00 checksum.sha256 $ runat test.txt cat checksum.sha256 sha256 (test.txt) = 5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef
And sure enough, this checksum matches:
$ digest -a sha256 test.txt 5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef
Links
- ACL - Filesystem ACLs
- Extended Attributes and ACLs (2010-02-09)
- Extended Attributes and ACLs on MacOS X (2011-08-07)
- File::ExtAttr - Perl extension for accessing extended attributes of files
References
- ↑ 1.0 1.1 The size of an inode depends on the filesystem used and the parameters when this filesystem was created or mounted.
- ↑ ext4: enable acls and user_xattr by default
- ↑ Mac OS X 10.4 Tiger: Extended attributes (John Siracusa, 2005-04-28)
- ↑ mount_ufs
- ↑ mount_nfs
- ↑ mount_tmpfs
- ↑ Solaris ZFS Administration Guide: ZFS Property Improvements
- ↑ Solaris Internals: Solaris 10 and OpenSolaris Kernel Architecture. The UFS File System: Extended Attributes in UFS