1use crate::Result;
4use bitflags::bitflags;
5use errno::{errno, Errno};
6use std::{
7 ffi::{CString, OsStr, OsString},
8 os::unix::{ffi::OsStrExt, io::RawFd},
9 path::Path,
10 ptr::null_mut,
11};
12
13bitflags! {
14 pub struct Flags: libc::c_int {
16 const XATTR_CREATE = libc::XATTR_CREATE;
19 const XATTR_REPLACE = libc::XATTR_REPLACE;
22 }
23}
24
25pub fn listxattr<P: AsRef<Path>>(path: P) -> Result<Vec<OsString>> {
30 let path = match CString::new(path.as_ref().as_os_str().as_bytes()) {
31 Ok(p) => p,
32 _ => return Err(Errno(libc::EINVAL)),
33 };
34
35 let buffer_size =
37 match unsafe { libc::listxattr(path.as_ptr(), null_mut(), 0) } {
38 -1 => return Err(errno()),
39 0 => return Ok(Vec::new()),
40 buffer_size => buffer_size as usize,
41 };
42
43 let mut buffer: Vec<u8> = Vec::with_capacity(buffer_size);
44 let res = unsafe {
45 libc::listxattr(path.as_ptr(), buffer.as_mut_ptr().cast(), buffer_size)
46 };
47
48 match res {
49 -1 => Err(errno()),
50 len => {
51 unsafe { buffer.set_len(len as usize) };
52 Ok(buffer[..(len - 1) as usize]
53 .split(|&item| item == 0)
54 .map(OsStr::from_bytes)
55 .map(|str| str.to_owned())
56 .collect::<Vec<OsString>>())
57 }
58 }
59}
60
61pub fn llistxattr<P: AsRef<Path>>(path: P) -> Result<Vec<OsString>> {
67 let path = match CString::new(path.as_ref().as_os_str().as_bytes()) {
68 Ok(p) => p,
69 _ => return Err(Errno(libc::EINVAL)),
70 };
71
72 let buffer_size =
74 match unsafe { libc::llistxattr(path.as_ptr(), null_mut(), 0) } {
75 -1 => return Err(errno()),
76 0 => return Ok(Vec::new()),
77 buffer_size => buffer_size as usize,
78 };
79
80 let mut buffer: Vec<u8> = Vec::with_capacity(buffer_size);
81 let res = unsafe {
82 libc::llistxattr(path.as_ptr(), buffer.as_mut_ptr().cast(), buffer_size)
83 };
84
85 match res {
86 -1 => Err(errno()),
87 len => {
88 unsafe { buffer.set_len(len as usize) };
89 Ok(buffer[..(len - 1) as usize]
90 .split(|&item| item == 0)
91 .map(OsStr::from_bytes)
92 .map(|str| str.to_owned())
93 .collect::<Vec<OsString>>())
94 }
95 }
96}
97
98pub fn flistxattr(fd: RawFd) -> Result<Vec<OsString>> {
103 let buffer_size = match unsafe { libc::flistxattr(fd, null_mut(), 0) } {
105 -1 => return Err(errno()),
106 0 => return Ok(Vec::new()),
107 buffer_size => buffer_size as usize,
108 };
109
110 let mut buffer: Vec<u8> = Vec::with_capacity(buffer_size);
111 let res = unsafe {
112 libc::flistxattr(fd, buffer.as_mut_ptr().cast(), buffer_size)
113 };
114
115 match res {
116 -1 => Err(errno()),
117 len => {
118 unsafe { buffer.set_len(len as usize) };
119 Ok(buffer[..(len - 1) as usize]
120 .split(|&item| item == 0)
121 .map(OsStr::from_bytes)
122 .map(|str| str.to_owned())
123 .collect::<Vec<OsString>>())
124 }
125 }
126}
127
128pub fn getxattr<P, S>(path: P, name: S) -> Result<Vec<u8>>
134where
135 P: AsRef<Path>,
136 S: AsRef<OsStr>,
137{
138 let name = match CString::new(name.as_ref().as_bytes()) {
139 Ok(n) => n,
140 _ => return Err(Errno(libc::EINVAL)),
141 };
142 let path = match CString::new(path.as_ref().as_os_str().as_bytes()) {
143 Ok(n) => n,
144 _ => return Err(Errno(libc::EINVAL)),
145 };
146
147 let buffer_size = match unsafe {
149 libc::getxattr(path.as_ptr(), name.as_ptr(), null_mut(), 0)
150 } {
151 -1 => return Err(errno()),
152 0 => return Ok(Vec::new()),
153 buffer_size => buffer_size as usize,
154 };
155
156 let mut buffer: Vec<u8> = Vec::with_capacity(buffer_size);
157
158 let res = unsafe {
159 libc::getxattr(
160 path.as_ptr(),
161 name.as_ptr(),
162 buffer.as_mut_ptr().cast(),
163 buffer_size,
164 )
165 };
166
167 match res {
168 -1 => Err(errno()),
169 len => {
170 unsafe { buffer.set_len(len as usize) };
171 Ok(buffer)
172 }
173 }
174}
175
176pub fn lgetxattr<P, S>(path: P, name: S) -> Result<Vec<u8>>
182where
183 P: AsRef<Path>,
184 S: AsRef<OsStr>,
185{
186 let name = match CString::new(name.as_ref().as_bytes()) {
187 Ok(n) => n,
188 _ => return Err(Errno(libc::EINVAL)),
189 };
190 let path = match CString::new(path.as_ref().as_os_str().as_bytes()) {
191 Ok(n) => n,
192 _ => return Err(Errno(libc::EINVAL)),
193 };
194
195 let buffer_size = match unsafe {
197 libc::lgetxattr(path.as_ptr(), name.as_ptr(), null_mut(), 0)
198 } {
199 -1 => return Err(errno()),
200 0 => return Ok(Vec::new()),
201 buffer_size => buffer_size as usize,
202 };
203
204 let mut buffer: Vec<u8> = Vec::with_capacity(buffer_size);
205
206 let res = unsafe {
207 libc::lgetxattr(
208 path.as_ptr(),
209 name.as_ptr(),
210 buffer.as_mut_ptr().cast(),
211 buffer_size,
212 )
213 };
214
215 match res {
216 -1 => Err(errno()),
217 len => {
218 unsafe { buffer.set_len(len as usize) };
219 Ok(buffer)
220 }
221 }
222}
223
224pub fn fgetxattr<S>(fd: RawFd, name: S) -> Result<Vec<u8>>
230where
231 S: AsRef<OsStr>,
232{
233 let name = match CString::new(name.as_ref().as_bytes()) {
234 Ok(name) => name,
235 _ => return Err(Errno(libc::EINVAL)),
236 };
237
238 let buffer_size =
240 match unsafe { libc::fgetxattr(fd, name.as_ptr(), null_mut(), 0) } {
241 -1 => return Err(errno()),
242 0 => return Ok(Vec::new()),
243 buffer_size => buffer_size as usize,
244 };
245
246 let mut buffer: Vec<u8> = Vec::with_capacity(buffer_size);
247
248 let res = unsafe {
249 libc::fgetxattr(
250 fd,
251 name.as_ptr(),
252 buffer.as_mut_ptr().cast(),
253 buffer_size,
254 )
255 };
256
257 match res {
258 -1 => Err(errno()),
259 len => {
260 unsafe { buffer.set_len(len as usize) };
261 Ok(buffer)
262 }
263 }
264}
265
266pub fn removexattr<P, S>(path: P, name: S) -> Result<()>
272where
273 P: AsRef<Path>,
274 S: AsRef<OsStr>,
275{
276 let path = match CString::new(path.as_ref().as_os_str().as_bytes()) {
277 Ok(n) => n,
278 _ => return Err(Errno(libc::EINVAL)),
279 };
280 let name = match CString::new(name.as_ref().as_bytes()) {
281 Ok(name) => name,
282 _ => return Err(Errno(libc::EINVAL)),
283 };
284
285 let res = unsafe { libc::removexattr(path.as_ptr(), name.as_ptr()) };
286
287 match res {
288 -1 => Err(errno()),
289 _ => Ok(()),
290 }
291}
292
293pub fn lremovexattr<P, S>(path: P, name: S) -> Result<()>
299where
300 P: AsRef<Path>,
301 S: AsRef<OsStr>,
302{
303 let path = match CString::new(path.as_ref().as_os_str().as_bytes()) {
304 Ok(n) => n,
305 _ => return Err(Errno(libc::EINVAL)),
306 };
307 let name = match CString::new(name.as_ref().as_bytes()) {
308 Ok(name) => name,
309 _ => return Err(Errno(libc::EINVAL)),
310 };
311
312 let res = unsafe { libc::lremovexattr(path.as_ptr(), name.as_ptr()) };
313
314 match res {
315 -1 => Err(errno()),
316 _ => Ok(()),
317 }
318}
319
320pub fn fremovexattr<S>(fd: RawFd, name: S) -> Result<()>
325where
326 S: AsRef<OsStr>,
327{
328 let name = match CString::new(name.as_ref().as_bytes()) {
329 Ok(name) => name,
330 _ => return Err(Errno(libc::EINVAL)),
331 };
332 let res = unsafe { libc::fremovexattr(fd, name.as_ptr()) };
333
334 match res {
335 -1 => Err(errno()),
336 _ => Ok(()),
337 }
338}
339
340pub fn setxattr<P, S, B>(path: P, name: S, value: B, flags: Flags) -> Result<()>
346where
347 P: AsRef<Path>,
348 S: AsRef<OsStr>,
349 B: AsRef<[u8]>,
350{
351 let path = match CString::new(path.as_ref().as_os_str().as_bytes()) {
352 Ok(n) => n,
353 _ => return Err(Errno(libc::EINVAL)),
354 };
355 let name = match CString::new(name.as_ref().as_bytes()) {
356 Ok(name) => name,
357 _ => return Err(Errno(libc::EINVAL)),
358 };
359
360 let value_ptr = value.as_ref().as_ptr().cast();
361 let value_len = value.as_ref().len();
362
363 let res = unsafe {
364 libc::setxattr(
365 path.as_ptr(),
366 name.as_ptr(),
367 value_ptr,
368 value_len,
369 flags.bits(),
370 )
371 };
372
373 match res {
374 -1 => Err(errno()),
375 _ => Ok(()),
376 }
377}
378
379pub fn lsetxattr<P, S, B>(
385 path: P,
386 name: S,
387 value: B,
388 flags: Flags,
389) -> Result<()>
390where
391 P: AsRef<Path>,
392 S: AsRef<OsStr>,
393 B: AsRef<[u8]>,
394{
395 let path = match CString::new(path.as_ref().as_os_str().as_bytes()) {
396 Ok(n) => n,
397 _ => return Err(Errno(libc::EINVAL)),
398 };
399 let name = match CString::new(name.as_ref().as_bytes()) {
400 Ok(name) => name,
401 _ => return Err(Errno(libc::EINVAL)),
402 };
403
404 let value_ptr = value.as_ref().as_ptr().cast();
405 let value_len = value.as_ref().len();
406
407 let res = unsafe {
408 libc::lsetxattr(
409 path.as_ptr(),
410 name.as_ptr(),
411 value_ptr,
412 value_len,
413 flags.bits(),
414 )
415 };
416
417 match res {
418 -1 => Err(errno()),
419 _ => Ok(()),
420 }
421}
422
423pub fn fsetxattr<S, B>(fd: RawFd, name: S, value: B, flags: Flags) -> Result<()>
428where
429 S: AsRef<OsStr>,
430 B: AsRef<[u8]>,
431{
432 let name = match CString::new(name.as_ref().as_bytes()) {
433 Ok(name) => name,
434 _ => return Err(Errno(libc::EINVAL)),
435 };
436
437 let value_ptr = value.as_ref().as_ptr().cast();
438 let value_len = value.as_ref().len();
439
440 let res = unsafe {
441 libc::fsetxattr(fd, name.as_ptr(), value_ptr, value_len, flags.bits())
442 };
443
444 match res {
445 -1 => Err(errno()),
446 _ => Ok(()),
447 }
448}