1 | //! Extended attribute functions. |
2 | |
3 | #![allow (unsafe_code)] |
4 | |
5 | use crate::buffer::Buffer; |
6 | use crate::{backend, ffi, io, path}; |
7 | use backend::c; |
8 | use backend::fd::AsFd; |
9 | use bitflags::bitflags; |
10 | |
11 | bitflags! { |
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 | /// For a higher-level API to xattr functionality, see the [xattr] crate. |
31 | /// |
32 | /// [xattr]: https://crates.io/crates/xattr |
33 | /// |
34 | /// # References |
35 | /// - [Linux] |
36 | /// - [Apple] |
37 | /// |
38 | /// [Linux]: https://man7.org/linux/man-pages/man2/getxattr.2.html |
39 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getxattr.2.html |
40 | #[inline ] |
41 | pub fn getxattr<P: path::Arg, Name: path::Arg, Buf: Buffer<u8>>( |
42 | path: P, |
43 | name: Name, |
44 | mut value: Buf, |
45 | ) -> io::Result<Buf::Output> { |
46 | path.into_with_c_str(|path: &CStr| { |
47 | name.into_with_c_str(|name: &CStr| { |
48 | // SAFETY: `getxattr` behaves. |
49 | let len: usize = unsafe { backend::fs::syscalls::getxattr(path, name, value.parts_mut())? }; |
50 | // SAFETY: `getxattr` behaves. |
51 | unsafe { Ok(value.assume_init(len)) } |
52 | }) |
53 | }) |
54 | } |
55 | |
56 | /// `lgetxattr(path, name, value.as_ptr(), value.len())`—Get extended |
57 | /// filesystem attributes, without following symlinks in the last path |
58 | /// component. |
59 | /// |
60 | /// # References |
61 | /// - [Linux] |
62 | /// |
63 | /// [Linux]: https://man7.org/linux/man-pages/man2/lgetxattr.2.html |
64 | #[inline ] |
65 | pub fn lgetxattr<P: path::Arg, Name: path::Arg, Buf: Buffer<u8>>( |
66 | path: P, |
67 | name: Name, |
68 | mut value: Buf, |
69 | ) -> io::Result<Buf::Output> { |
70 | path.into_with_c_str(|path: &CStr| { |
71 | name.into_with_c_str(|name: &CStr| { |
72 | // SAFETY: `lgetxattr` behaves. |
73 | let len: usize = unsafe { backend::fs::syscalls::lgetxattr(path, name, value.parts_mut())? }; |
74 | // SAFETY: `lgetxattr` behaves. |
75 | unsafe { Ok(value.assume_init(len)) } |
76 | }) |
77 | }) |
78 | } |
79 | |
80 | /// `fgetxattr(fd, name, value.as_ptr(), value.len())`—Get extended |
81 | /// filesystem attributes on an open file descriptor. |
82 | /// |
83 | /// # References |
84 | /// - [Linux] |
85 | /// - [Apple] |
86 | /// |
87 | /// [Linux]: https://man7.org/linux/man-pages/man2/fgetxattr.2.html |
88 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fgetxattr.2.html |
89 | #[inline ] |
90 | pub fn fgetxattr<Fd: AsFd, Name: path::Arg, Buf: Buffer<u8>>( |
91 | fd: Fd, |
92 | name: Name, |
93 | mut value: Buf, |
94 | ) -> io::Result<Buf::Output> { |
95 | name.into_with_c_str(|name: &CStr| { |
96 | // SAFETY: `fgetxattr` behaves. |
97 | let len: usize = unsafe { backend::fs::syscalls::fgetxattr(fd.as_fd(), name, value.parts_mut())? }; |
98 | // SAFETY: `fgetxattr` behaves. |
99 | unsafe { Ok(value.assume_init(len)) } |
100 | }) |
101 | } |
102 | |
103 | /// `setxattr(path, name, value.as_ptr(), value.len(), flags)`—Set extended |
104 | /// filesystem attributes. |
105 | /// |
106 | /// # References |
107 | /// - [Linux] |
108 | /// - [Apple] |
109 | /// |
110 | /// [Linux]: https://man7.org/linux/man-pages/man2/setxattr.2.html |
111 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setxattr.2.html |
112 | #[inline ] |
113 | pub fn setxattr<P: path::Arg, Name: path::Arg>( |
114 | path: P, |
115 | name: Name, |
116 | value: &[u8], |
117 | flags: XattrFlags, |
118 | ) -> io::Result<()> { |
119 | path.into_with_c_str(|path: &CStr| { |
120 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::setxattr(path, name, value, flags)) |
121 | }) |
122 | } |
123 | |
124 | /// `setxattr(path, name, value.as_ptr(), value.len(), flags)`—Set extended |
125 | /// filesystem attributes, without following symlinks in the last path |
126 | /// component. |
127 | /// |
128 | /// # References |
129 | /// - [Linux] |
130 | /// |
131 | /// [Linux]: https://man7.org/linux/man-pages/man2/lsetxattr.2.html |
132 | #[inline ] |
133 | pub fn lsetxattr<P: path::Arg, Name: path::Arg>( |
134 | path: P, |
135 | name: Name, |
136 | value: &[u8], |
137 | flags: XattrFlags, |
138 | ) -> io::Result<()> { |
139 | path.into_with_c_str(|path: &CStr| { |
140 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::lsetxattr(path, name, value, flags)) |
141 | }) |
142 | } |
143 | |
144 | /// `fsetxattr(fd, name, value.as_ptr(), value.len(), flags)`—Set extended |
145 | /// filesystem attributes on an open file descriptor. |
146 | /// |
147 | /// # References |
148 | /// - [Linux] |
149 | /// - [Apple] |
150 | /// |
151 | /// [Linux]: https://man7.org/linux/man-pages/man2/fsetxattr.2.html |
152 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsetxattr.2.html |
153 | #[inline ] |
154 | pub fn fsetxattr<Fd: AsFd, Name: path::Arg>( |
155 | fd: Fd, |
156 | name: Name, |
157 | value: &[u8], |
158 | flags: XattrFlags, |
159 | ) -> io::Result<()> { |
160 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::fsetxattr(fd.as_fd(), name, value, flags)) |
161 | } |
162 | |
163 | /// `listxattr(path, list.as_ptr(), list.len())`—List extended filesystem |
164 | /// attributes. |
165 | /// |
166 | /// # References |
167 | /// - [Linux] |
168 | /// |
169 | /// [Linux]: https://man7.org/linux/man-pages/man2/listxattr.2.html |
170 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/listxattr.2.html |
171 | #[inline ] |
172 | pub fn listxattr<P: path::Arg, Buf: Buffer<u8>>(path: P, mut list: Buf) -> io::Result<Buf::Output> { |
173 | path.into_with_c_str(|path: &CStr| { |
174 | // SAFETY: `listxattr` behaves. |
175 | let len: usize = unsafe { backend::fs::syscalls::listxattr(path, list.parts_mut())? }; |
176 | // SAFETY: `listxattr` behaves. |
177 | unsafe { Ok(list.assume_init(len)) } |
178 | }) |
179 | } |
180 | |
181 | /// `llistxattr(path, list.as_ptr(), list.len())`—List extended filesystem |
182 | /// attributes, without following symlinks in the last path component. |
183 | /// |
184 | /// # References |
185 | /// - [Linux] |
186 | /// |
187 | /// [Linux]: https://man7.org/linux/man-pages/man2/llistxattr.2.html |
188 | #[inline ] |
189 | pub fn llistxattr<P: path::Arg, Buf: Buffer<u8>>( |
190 | path: P, |
191 | mut list: Buf, |
192 | ) -> io::Result<Buf::Output> { |
193 | path.into_with_c_str(|path: &CStr| { |
194 | // SAFETY: `flistxattr` behaves. |
195 | let len: usize = unsafe { backend::fs::syscalls::llistxattr(path, list.parts_mut())? }; |
196 | // SAFETY: `flistxattr` behaves. |
197 | unsafe { Ok(list.assume_init(len)) } |
198 | }) |
199 | } |
200 | |
201 | /// `flistxattr(fd, list.as_ptr(), list.len())`—List extended filesystem |
202 | /// attributes on an open file descriptor. |
203 | /// |
204 | /// # References |
205 | /// - [Linux] |
206 | /// - [Apple] |
207 | /// |
208 | /// [Linux]: https://man7.org/linux/man-pages/man2/flistxattr.2.html |
209 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/flistxattr.2.html |
210 | #[inline ] |
211 | pub fn flistxattr<Fd: AsFd, Buf: Buffer<u8>>(fd: Fd, mut list: Buf) -> io::Result<Buf::Output> { |
212 | // SAFETY: `flistxattr` behaves. |
213 | let len: usize = unsafe { backend::fs::syscalls::flistxattr(fd.as_fd(), list.parts_mut())? }; |
214 | // SAFETY: `flistxattr` behaves. |
215 | unsafe { Ok(list.assume_init(len)) } |
216 | } |
217 | |
218 | /// `removexattr(path, name)`—Remove an extended filesystem attribute. |
219 | /// |
220 | /// # References |
221 | /// - [Linux] |
222 | /// - [Apple] |
223 | /// |
224 | /// [Linux]: https://man7.org/linux/man-pages/man2/removexattr.2.html |
225 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/removexattr.2.html |
226 | pub fn removexattr<P: path::Arg, Name: path::Arg>(path: P, name: Name) -> io::Result<()> { |
227 | path.into_with_c_str(|path: &CStr| { |
228 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::removexattr(path, name)) |
229 | }) |
230 | } |
231 | |
232 | /// `lremovexattr(path, name)`—Remove an extended filesystem attribute, |
233 | /// without following symlinks in the last path component. |
234 | /// |
235 | /// # References |
236 | /// - [Linux] |
237 | /// |
238 | /// [Linux]: https://man7.org/linux/man-pages/man2/lremovexattr.2.html |
239 | pub fn lremovexattr<P: path::Arg, Name: path::Arg>(path: P, name: Name) -> io::Result<()> { |
240 | path.into_with_c_str(|path: &CStr| { |
241 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::lremovexattr(path, name)) |
242 | }) |
243 | } |
244 | |
245 | /// `fremovexattr(fd, name)`—Remove an extended filesystem attribute on an |
246 | /// open file descriptor. |
247 | /// |
248 | /// # References |
249 | /// - [Linux] |
250 | /// - [Apple] |
251 | /// |
252 | /// [Linux]: https://man7.org/linux/man-pages/man2/fremovexattr.2.html |
253 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fremovexattr.2.html |
254 | pub fn fremovexattr<Fd: AsFd, Name: path::Arg>(fd: Fd, name: Name) -> io::Result<()> { |
255 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::fremovexattr(fd.as_fd(), name)) |
256 | } |
257 | |