22
33use libc:: { c_int, c_void, size_t, EPERM } ;
44use std:: ffi:: { CString , OsStr , OsString } ;
5- use std:: io;
6- use std:: mem;
5+ use std:: mem:: { self , MaybeUninit } ;
76use std:: os:: unix:: ffi:: { OsStrExt , OsStringExt } ;
87use std:: os:: unix:: io:: { AsRawFd , BorrowedFd } ;
98use std:: path:: Path ;
109use std:: ptr;
10+ use std:: { io, slice} ;
1111
1212use libc:: {
1313 extattr_delete_fd, extattr_delete_file, extattr_delete_link, extattr_get_fd, extattr_get_file,
1414 extattr_get_link, extattr_list_fd, extattr_list_file, extattr_list_link, extattr_set_fd,
1515 extattr_set_file, extattr_set_link, EXTATTR_NAMESPACE_SYSTEM , EXTATTR_NAMESPACE_USER ,
1616} ;
1717
18- use crate :: util:: allocate_loop;
19-
2018pub const ENOATTR : i32 = libc:: ENOATTR ;
2119pub const ERANGE : i32 = libc:: ERANGE ;
2220
@@ -36,14 +34,38 @@ fn path_to_c(path: &Path) -> io::Result<CString> {
3634}
3735
3836#[ inline]
39- fn slice_parts ( buf : & mut [ u8 ] ) -> ( * mut c_void , size_t ) {
37+ fn cvt ( res : libc:: ssize_t ) -> io:: Result < usize > {
38+ if res < 0 {
39+ Err ( io:: Error :: last_os_error ( ) )
40+ } else {
41+ Ok ( res as usize )
42+ }
43+ }
44+
45+ #[ inline]
46+ fn slice_parts ( buf : & mut [ MaybeUninit < u8 > ] ) -> ( * mut c_void , size_t ) {
4047 if buf. is_empty ( ) {
4148 ( ptr:: null_mut ( ) , 0 )
4249 } else {
4350 ( buf. as_mut_ptr ( ) . cast ( ) , buf. len ( ) as size_t )
4451 }
4552}
4653
54+ fn allocate_loop < F : Fn ( * mut c_void , size_t ) -> libc:: ssize_t > ( f : F ) -> io:: Result < Vec < u8 > > {
55+ crate :: util:: allocate_loop (
56+ |buf| unsafe {
57+ let ( ptr, len) = slice_parts ( buf) ;
58+ let new_len = cvt ( f ( ptr, len) ) ?;
59+ assert ! (
60+ new_len <= len,
61+ "OS returned length {new_len} greater than buffer size {len}"
62+ ) ;
63+ Ok ( slice:: from_raw_parts_mut ( ptr. cast ( ) , new_len) )
64+ } ,
65+ || cvt ( f ( ptr:: null_mut ( ) , 0 ) ) ,
66+ )
67+ }
68+
4769/// An iterator over a set of extended attributes names.
4870#[ derive( Default ) ]
4971pub struct XAttrs {
@@ -165,22 +187,9 @@ fn prefix_namespace(attr: &OsStr, ns: c_int) -> OsString {
165187 OsString :: from_vec ( v)
166188}
167189
168- fn cvt ( res : libc:: ssize_t ) -> io:: Result < usize > {
169- if res < 0 {
170- Err ( io:: Error :: last_os_error ( ) )
171- } else {
172- Ok ( res as usize )
173- }
174- }
175-
176190pub fn get_fd ( fd : BorrowedFd < ' _ > , name : & OsStr ) -> io:: Result < Vec < u8 > > {
177191 let ( ns, name) = name_to_ns ( name) ?;
178- unsafe {
179- allocate_loop ( |buf| {
180- let ( ptr, len) = slice_parts ( buf) ;
181- cvt ( extattr_get_fd ( fd. as_raw_fd ( ) , ns, name. as_ptr ( ) , ptr, len) )
182- } )
183- }
192+ unsafe { allocate_loop ( |ptr, len| extattr_get_fd ( fd. as_raw_fd ( ) , ns, name. as_ptr ( ) , ptr, len) ) }
184193}
185194
186195pub fn set_fd ( fd : BorrowedFd < ' _ > , name : & OsStr , value : & [ u8 ] ) -> io:: Result < ( ) > {
@@ -213,14 +222,8 @@ pub fn remove_fd(fd: BorrowedFd<'_>, name: &OsStr) -> io::Result<()> {
213222
214223pub fn list_fd ( fd : BorrowedFd < ' _ > ) -> io:: Result < XAttrs > {
215224 let sysvec = unsafe {
216- let res = allocate_loop ( |buf| {
217- let ( ptr, len) = slice_parts ( buf) ;
218- cvt ( extattr_list_fd (
219- fd. as_raw_fd ( ) ,
220- EXTATTR_NAMESPACE_SYSTEM ,
221- ptr,
222- len,
223- ) )
225+ let res = allocate_loop ( |ptr, len| {
226+ extattr_list_fd ( fd. as_raw_fd ( ) , EXTATTR_NAMESPACE_SYSTEM , ptr, len)
224227 } ) ;
225228 // On FreeBSD, system attributes require root privileges to view. However,
226229 // to mimic the behavior of listxattr in linux and osx, we need to query
@@ -238,14 +241,8 @@ pub fn list_fd(fd: BorrowedFd<'_>) -> io::Result<XAttrs> {
238241 } ;
239242
240243 let uservec = unsafe {
241- let res = allocate_loop ( |buf| {
242- let ( ptr, len) = slice_parts ( buf) ;
243- cvt ( extattr_list_fd (
244- fd. as_raw_fd ( ) ,
245- EXTATTR_NAMESPACE_USER ,
246- ptr,
247- len,
248- ) )
244+ let res = allocate_loop ( |ptr, len| {
245+ extattr_list_fd ( fd. as_raw_fd ( ) , EXTATTR_NAMESPACE_USER , ptr, len)
249246 } ) ;
250247 match res {
251248 Ok ( v) => v,
@@ -269,10 +266,7 @@ pub fn get_path(path: &Path, name: &OsStr, deref: bool) -> io::Result<Vec<u8>> {
269266 extattr_get_link
270267 } ;
271268 unsafe {
272- allocate_loop ( |buf| {
273- let ( ptr, len) = slice_parts ( buf) ;
274- cvt ( extattr_get_func ( path. as_ptr ( ) , ns, name. as_ptr ( ) , ptr, len) )
275- } )
269+ allocate_loop ( |ptr, len| extattr_get_func ( path. as_ptr ( ) , ns, name. as_ptr ( ) , ptr, len) )
276270 }
277271}
278272
@@ -324,14 +318,8 @@ pub fn list_path(path: &Path, deref: bool) -> io::Result<XAttrs> {
324318 extattr_list_link
325319 } ;
326320 let sysvec = unsafe {
327- let res = allocate_loop ( |buf| {
328- let ( ptr, len) = slice_parts ( buf) ;
329- cvt ( extattr_list_func (
330- path. as_ptr ( ) ,
331- EXTATTR_NAMESPACE_SYSTEM ,
332- ptr,
333- len,
334- ) )
321+ let res = allocate_loop ( |ptr, len| {
322+ extattr_list_func ( path. as_ptr ( ) , EXTATTR_NAMESPACE_SYSTEM , ptr, len)
335323 } ) ;
336324 // On FreeBSD, system attributes require root privileges to view. However,
337325 // to mimic the behavior of listxattr in linux and osx, we need to query
@@ -349,14 +337,8 @@ pub fn list_path(path: &Path, deref: bool) -> io::Result<XAttrs> {
349337 } ;
350338
351339 let uservec = unsafe {
352- let res = allocate_loop ( |buf| {
353- let ( ptr, len) = slice_parts ( buf) ;
354- cvt ( extattr_list_func (
355- path. as_ptr ( ) ,
356- EXTATTR_NAMESPACE_USER ,
357- ptr,
358- len,
359- ) )
340+ let res = allocate_loop ( |ptr, len| {
341+ extattr_list_func ( path. as_ptr ( ) , EXTATTR_NAMESPACE_USER , ptr, len)
360342 } ) ;
361343 match res {
362344 Ok ( v) => v,
0 commit comments