rustix/fs/
xattr.rs

1//! Extended attribute functions.
2
3#![allow(unsafe_code)]
4
5use crate::buffer::Buffer;
6use crate::{backend, ffi, io, path};
7use backend::c;
8use backend::fd::AsFd;
9use bitflags::bitflags;
10
11bitflags! {
12    /// `XATTR_*` constants for use with [`setxattr`], and other `*setxattr`
13    /// functions.
14    #[repr(transparent)]
15    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
16    pub struct XattrFlags: ffi::c_uint {
17        /// `XATTR_CREATE`
18        const CREATE = c::XATTR_CREATE as c::c_uint;
19
20        /// `XATTR_REPLACE`
21        const REPLACE = c::XATTR_REPLACE as c::c_uint;
22
23        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
24        const _ = !0;
25    }
26}
27
28/// `getxattr(path, name, value)`—Get extended filesystem attributes.
29///
30/// # References
31///  - [Linux]
32///
33/// [Linux]: https://man7.org/linux/man-pages/man2/getxattr.2.html
34#[inline]
35pub fn getxattr<P: path::Arg, Name: path::Arg, Buf: Buffer<u8>>(
36    path: P,
37    name: Name,
38    mut value: Buf,
39) -> io::Result<Buf::Output> {
40    path.into_with_c_str(|path| {
41        name.into_with_c_str(|name| {
42            // SAFETY: `getxattr` behaves.
43            let len = unsafe { backend::fs::syscalls::getxattr(path, name, value.parts_mut())? };
44            // SAFETY: `getxattr` behaves.
45            unsafe { Ok(value.assume_init(len)) }
46        })
47    })
48}
49
50/// `lgetxattr(path, name, value.as_ptr(), value.len())`—Get extended
51/// filesystem attributes, without following symlinks in the last path
52/// component.
53///
54/// # References
55///  - [Linux]
56///
57/// [Linux]: https://man7.org/linux/man-pages/man2/lgetxattr.2.html
58#[inline]
59pub fn lgetxattr<P: path::Arg, Name: path::Arg, Buf: Buffer<u8>>(
60    path: P,
61    name: Name,
62    mut value: Buf,
63) -> io::Result<Buf::Output> {
64    path.into_with_c_str(|path| {
65        name.into_with_c_str(|name| {
66            // SAFETY: `lgetxattr` behaves.
67            let len = unsafe { backend::fs::syscalls::lgetxattr(path, name, value.parts_mut())? };
68            // SAFETY: `lgetxattr` behaves.
69            unsafe { Ok(value.assume_init(len)) }
70        })
71    })
72}
73
74/// `fgetxattr(fd, name, value.as_ptr(), value.len())`—Get extended
75/// filesystem attributes on an open file descriptor.
76///
77/// # References
78///  - [Linux]
79///
80/// [Linux]: https://man7.org/linux/man-pages/man2/fgetxattr.2.html
81#[inline]
82pub fn fgetxattr<Fd: AsFd, Name: path::Arg, Buf: Buffer<u8>>(
83    fd: Fd,
84    name: Name,
85    mut value: Buf,
86) -> io::Result<Buf::Output> {
87    name.into_with_c_str(|name| {
88        // SAFETY: `fgetxattr` behaves.
89        let len = unsafe { backend::fs::syscalls::fgetxattr(fd.as_fd(), name, value.parts_mut())? };
90        // SAFETY: `fgetxattr` behaves.
91        unsafe { Ok(value.assume_init(len)) }
92    })
93}
94
95/// `setxattr(path, name, value.as_ptr(), value.len(), flags)`—Set extended
96/// filesystem attributes.
97///
98/// # References
99///  - [Linux]
100///
101/// [Linux]: https://man7.org/linux/man-pages/man2/setxattr.2.html
102#[inline]
103pub fn setxattr<P: path::Arg, Name: path::Arg>(
104    path: P,
105    name: Name,
106    value: &[u8],
107    flags: XattrFlags,
108) -> io::Result<()> {
109    path.into_with_c_str(|path| {
110        name.into_with_c_str(|name| backend::fs::syscalls::setxattr(path, name, value, flags))
111    })
112}
113
114/// `setxattr(path, name, value.as_ptr(), value.len(), flags)`—Set extended
115/// filesystem attributes, without following symlinks in the last path
116/// component.
117///
118/// # References
119///  - [Linux]
120///
121/// [Linux]: https://man7.org/linux/man-pages/man2/lsetxattr.2.html
122#[inline]
123pub fn lsetxattr<P: path::Arg, Name: path::Arg>(
124    path: P,
125    name: Name,
126    value: &[u8],
127    flags: XattrFlags,
128) -> io::Result<()> {
129    path.into_with_c_str(|path| {
130        name.into_with_c_str(|name| backend::fs::syscalls::lsetxattr(path, name, value, flags))
131    })
132}
133
134/// `fsetxattr(fd, name, value.as_ptr(), value.len(), flags)`—Set extended
135/// filesystem attributes on an open file descriptor.
136///
137/// # References
138///  - [Linux]
139///
140/// [Linux]: https://man7.org/linux/man-pages/man2/fsetxattr.2.html
141#[inline]
142pub fn fsetxattr<Fd: AsFd, Name: path::Arg>(
143    fd: Fd,
144    name: Name,
145    value: &[u8],
146    flags: XattrFlags,
147) -> io::Result<()> {
148    name.into_with_c_str(|name| backend::fs::syscalls::fsetxattr(fd.as_fd(), name, value, flags))
149}
150
151/// `listxattr(path, list.as_ptr(), list.len())`—List extended filesystem
152/// attributes.
153///
154/// # References
155///  - [Linux]
156///
157/// [Linux]: https://man7.org/linux/man-pages/man2/listxattr.2.html
158#[inline]
159pub fn listxattr<P: path::Arg, Buf: Buffer<u8>>(path: P, mut list: Buf) -> io::Result<Buf::Output> {
160    path.into_with_c_str(|path| {
161        // SAFETY: `listxattr` behaves.
162        let len = unsafe { backend::fs::syscalls::listxattr(path, list.parts_mut())? };
163        // SAFETY: `listxattr` behaves.
164        unsafe { Ok(list.assume_init(len)) }
165    })
166}
167
168/// `llistxattr(path, list.as_ptr(), list.len())`—List extended filesystem
169/// attributes, without following symlinks in the last path component.
170///
171/// # References
172///  - [Linux]
173///
174/// [Linux]: https://man7.org/linux/man-pages/man2/llistxattr.2.html
175#[inline]
176pub fn llistxattr<P: path::Arg, Buf: Buffer<u8>>(
177    path: P,
178    mut list: Buf,
179) -> io::Result<Buf::Output> {
180    path.into_with_c_str(|path| {
181        // SAFETY: `flistxattr` behaves.
182        let len = unsafe { backend::fs::syscalls::llistxattr(path, list.parts_mut())? };
183        // SAFETY: `flistxattr` behaves.
184        unsafe { Ok(list.assume_init(len)) }
185    })
186}
187
188/// `flistxattr(fd, list.as_ptr(), list.len())`—List extended filesystem
189/// attributes on an open file descriptor.
190///
191/// # References
192///  - [Linux]
193///
194/// [Linux]: https://man7.org/linux/man-pages/man2/flistxattr.2.html
195#[inline]
196pub fn flistxattr<Fd: AsFd, Buf: Buffer<u8>>(fd: Fd, mut list: Buf) -> io::Result<Buf::Output> {
197    // SAFETY: `flistxattr` behaves.
198    let len = unsafe { backend::fs::syscalls::flistxattr(fd.as_fd(), list.parts_mut())? };
199    // SAFETY: `flistxattr` behaves.
200    unsafe { Ok(list.assume_init(len)) }
201}
202
203/// `removexattr(path, name)`—Remove an extended filesystem attribute.
204///
205/// # References
206///  - [Linux]
207///
208/// [Linux]: https://man7.org/linux/man-pages/man2/removexattr.2.html
209pub fn removexattr<P: path::Arg, Name: path::Arg>(path: P, name: Name) -> io::Result<()> {
210    path.into_with_c_str(|path| {
211        name.into_with_c_str(|name| backend::fs::syscalls::removexattr(path, name))
212    })
213}
214
215/// `lremovexattr(path, name)`—Remove an extended filesystem attribute,
216/// without following symlinks in the last path component.
217///
218/// # References
219///  - [Linux]
220///
221/// [Linux]: https://man7.org/linux/man-pages/man2/lremovexattr.2.html
222pub fn lremovexattr<P: path::Arg, Name: path::Arg>(path: P, name: Name) -> io::Result<()> {
223    path.into_with_c_str(|path| {
224        name.into_with_c_str(|name| backend::fs::syscalls::lremovexattr(path, name))
225    })
226}
227
228/// `fremovexattr(fd, name)`—Remove an extended filesystem attribute on an
229/// open file descriptor.
230///
231/// # References
232///  - [Linux]
233///
234/// [Linux]: https://man7.org/linux/man-pages/man2/fremovexattr.2.html
235pub fn fremovexattr<Fd: AsFd, Name: path::Arg>(fd: Fd, name: Name) -> io::Result<()> {
236    name.into_with_c_str(|name| backend::fs::syscalls::fremovexattr(fd.as_fd(), name))
237}