Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/borg/platform/solaris.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
attribute directory attached to that file. The attribute directory is opened by giving
O_XATTR to open(2)/openat(2), see fsattr(7) — xattr names/values map to the names/contents
of the files in there. There are no xattr namespaces, so names are used verbatim.

Block and character device nodes are treated as not supporting extended attributes:
reaching their attribute directory would require opening the device itself.
"""

import errno
import os
import stat

from .base import ENOATTR

Expand All @@ -32,6 +36,11 @@ def _open_attrdir(path, follow_symlinks):
# referring to the file, so for a path, the file itself must be opened first.
if isinstance(path, int):
return os.open(".", os.O_RDONLY | O_XATTR, dir_fd=path)
# Opening a device node runs the open routine of its driver, which might fail (ENXIO if
# there is no such device), block or have side effects (e.g. a tape rewinding on close).
st = os.stat(path, follow_symlinks=follow_symlinks)
if stat.S_ISBLK(st.st_mode) or stat.S_ISCHR(st.st_mode):
raise OSError(errno.ENOTSUP, os.strerror(errno.ENOTSUP), path)
flags = os.O_RDONLY | os.O_NONBLOCK # O_NONBLOCK: do not hang on FIFOs
if not follow_symlinks:
flags |= os.O_NOFOLLOW
Expand Down
20 changes: 19 additions & 1 deletion src/borg/testsuite/xattr_test.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import errno
import os
import stat

import pytest

from ..platform.xattr import buffer, split_lstring
from ..xattr import is_enabled, getxattr, setxattr, listxattr, XATTR_FAKEROOT
from ..xattr import is_enabled, getxattr, setxattr, listxattr, get_all, XATTR_FAKEROOT
from ..platformflags import is_linux, is_sunos

# Whether xattrs can be set on a symlink itself:
Expand Down Expand Up @@ -83,6 +85,22 @@ def test_getxattr_buffer_growth(tempfile_symlink):
assert len(buffer) == 128


@pytest.mark.skipif(not is_sunos, reason="illumos/Solaris only")
@pytest.mark.parametrize("kind", [stat.S_IFBLK, stat.S_IFCHR])
def test_device_node_is_not_opened(tmp_path, kind):
# Reaching the attribute directory of a device node would open the device itself,
# which fails with ENXIO for a device number without a driver (like this one).
path = os.fsencode(tmp_path / "dev")
try:
os.mknod(path, 0o600 | kind, os.makedev(30, 40))
except PermissionError:
pytest.skip("creating device nodes requires root")
with pytest.raises(OSError) as excinfo:
listxattr(path)
assert excinfo.value.errno == errno.ENOTSUP
assert get_all(path) == {}


@pytest.mark.parametrize(
"lstring, expected", [(b"", []), (b"\x00", [b""]), (b"\x01a", [b"a"]), (b"\x01a\x02cd", [b"a", b"cd"])]
)
Expand Down
Loading