1#![allow(clippy::comparison_chain)]
2//! A pure-Rust library to manage extended attributes.
3//!
4//! It provides support for manipulating extended attributes
5//! (`xattrs`) on modern Unix filesystems. See the `attr(5)`
6//! manpage for more details.
7//!
8//! An extension trait [`FileExt`] is provided to directly work with
9//! standard `File` objects and file descriptors.
10//!
11//! If the path argument is a symlink, the get/set/list/remove functions
12//! operate on the symlink itself. To operate on the symlink target, use
13//! the _deref variant of these functions.
14//!
15//! ```rust
16//! let mut xattrs = xattr::list("/").unwrap().peekable();
17//!
18//! if xattrs.peek().is_none() {
19//! println!("no xattr set on root");
20//! return;
21//! }
22//!
23//! println!("Extended attributes:");
24//! for attr in xattrs {
25//! println!(" - {:?}", attr);
26//! }
27//! ```
28
29mod error;
30mod sys;
31mod util;
32
33use std::ffi::OsStr;
34use std::fs::File;
35use std::io;
36use std::os::unix::io::{AsRawFd, BorrowedFd};
37use std::path::Path;
38
39pub use error::UnsupportedPlatformError;
40pub use sys::{XAttrs, SUPPORTED_PLATFORM};
41
42/// Get an extended attribute for the specified file.
43pub fn get<N, P>(path: P, name: N) -> io::Result<Option<Vec<u8>>>
44where
45 P: AsRef<Path>,
46 N: AsRef<OsStr>,
47{
48 util::extract_noattr(result:sys::get_path(path.as_ref(), name.as_ref(), deref:false))
49}
50
51/// Get an extended attribute for the specified file (dereference symlinks).
52pub fn get_deref<N, P>(path: P, name: N) -> io::Result<Option<Vec<u8>>>
53where
54 P: AsRef<Path>,
55 N: AsRef<OsStr>,
56{
57 util::extract_noattr(result:sys::get_path(path.as_ref(), name.as_ref(), deref:true))
58}
59
60/// Set an extended attribute on the specified file.
61pub fn set<N, P>(path: P, name: N, value: &[u8]) -> io::Result<()>
62where
63 P: AsRef<Path>,
64 N: AsRef<OsStr>,
65{
66 sys::set_path(path.as_ref(), name.as_ref(), value, deref:false)
67}
68
69/// Set an extended attribute on the specified file (dereference symlinks).
70pub fn set_deref<N, P>(path: P, name: N, value: &[u8]) -> io::Result<()>
71where
72 P: AsRef<Path>,
73 N: AsRef<OsStr>,
74{
75 sys::set_path(path.as_ref(), name.as_ref(), value, deref:true)
76}
77
78/// Remove an extended attribute from the specified file.
79pub fn remove<N, P>(path: P, name: N) -> io::Result<()>
80where
81 P: AsRef<Path>,
82 N: AsRef<OsStr>,
83{
84 sys::remove_path(path.as_ref(), name.as_ref(), deref:false)
85}
86
87/// Remove an extended attribute from the specified file (dereference symlinks).
88pub fn remove_deref<N, P>(path: P, name: N) -> io::Result<()>
89where
90 P: AsRef<Path>,
91 N: AsRef<OsStr>,
92{
93 sys::remove_path(path.as_ref(), name.as_ref(), deref:true)
94}
95
96/// List extended attributes attached to the specified file.
97///
98/// Note: this may not list *all* attributes. Speficially, it definitely won't list any trusted
99/// attributes unless you are root and it may not list system attributes.
100pub fn list<P>(path: P) -> io::Result<XAttrs>
101where
102 P: AsRef<Path>,
103{
104 sys::list_path(path.as_ref(), deref:false)
105}
106
107/// List extended attributes attached to the specified file (dereference symlinks).
108pub fn list_deref<P>(path: P) -> io::Result<XAttrs>
109where
110 P: AsRef<Path>,
111{
112 sys::list_path(path.as_ref(), deref:true)
113}
114
115/// Extension trait to manipulate extended attributes on `File`-like objects.
116pub trait FileExt: AsRawFd {
117 /// Get an extended attribute for the specified file.
118 fn get_xattr<N>(&self, name: N) -> io::Result<Option<Vec<u8>>>
119 where
120 N: AsRef<OsStr>,
121 {
122 // SAFETY: Implement I/O safety later.
123 let fd = unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) };
124 util::extract_noattr(sys::get_fd(fd, name.as_ref()))
125 }
126
127 /// Set an extended attribute on the specified file.
128 fn set_xattr<N>(&self, name: N, value: &[u8]) -> io::Result<()>
129 where
130 N: AsRef<OsStr>,
131 {
132 let fd = unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) };
133 sys::set_fd(fd, name.as_ref(), value)
134 }
135
136 /// Remove an extended attribute from the specified file.
137 fn remove_xattr<N>(&self, name: N) -> io::Result<()>
138 where
139 N: AsRef<OsStr>,
140 {
141 let fd = unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) };
142 sys::remove_fd(fd, name.as_ref())
143 }
144
145 /// List extended attributes attached to the specified file.
146 ///
147 /// Note: this may not list *all* attributes. Speficially, it definitely won't list any trusted
148 /// attributes unless you are root and it may not list system attributes.
149 fn list_xattr(&self) -> io::Result<XAttrs> {
150 let fd = unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) };
151 sys::list_fd(fd)
152 }
153}
154
155impl FileExt for File {}
156