@@ -92,35 +92,29 @@ fn item_to_value(item: &[u8], radix: u32) -> Option<u32> {
9292 }
9393}
9494
95- fn get_xattr_common ( buf : & [ u8 ] ) -> io:: Result < Option < ( u32 , u32 , u32 ) > > {
95+ fn get_xattr_common ( buf : & [ u8 ] ) -> io:: Result < ( Option < u32 > , Option < u32 > , Option < u32 > ) > {
9696 let mut items = buf. split ( |c| * c == b':' ) ;
9797
9898 let uid = match items. next ( ) {
99- Some ( item) => match item_to_value ( item, 10 ) {
100- Some ( item) => item,
101- None => return Ok ( None ) ,
102- } ,
103- None => return Ok ( None ) ,
99+ Some ( item) => item_to_value ( item, 10 ) ,
100+ None => None ,
104101 } ;
105102 let gid = match items. next ( ) {
106- Some ( item) => match item_to_value ( item, 10 ) {
107- Some ( item) => item,
108- None => return Ok ( None ) ,
109- } ,
110- None => return Ok ( None ) ,
103+ Some ( item) => item_to_value ( item, 10 ) ,
104+ None => None ,
111105 } ;
112106 let mode = match items. next ( ) {
113- Some ( item) => match item_to_value ( item, 8 ) {
114- Some ( item) => item,
115- None => return Ok ( None ) ,
116- } ,
117- None => return Ok ( None ) ,
107+ Some ( item) => item_to_value ( item, 8 ) ,
108+ None => None ,
118109 } ;
119110
120- Ok ( Some ( ( uid, gid, mode) ) )
111+ Ok ( ( uid, gid, mode) )
121112}
122113
123- fn get_xattr_fstat ( fd : RawFd , st : bindings:: stat64 ) -> io:: Result < Option < ( u32 , u32 , u32 ) > > {
114+ fn get_xattr_fstat (
115+ fd : RawFd ,
116+ st : bindings:: stat64 ,
117+ ) -> io:: Result < ( Option < u32 > , Option < u32 > , Option < u32 > ) > {
124118 let mut buf: Vec < u8 > = vec ! [ 0 ; 32 ] ;
125119 let options = if ( st. st_mode & libc:: S_IFMT ) == libc:: S_IFLNK {
126120 libc:: XATTR_NOFOLLOW
@@ -139,15 +133,18 @@ fn get_xattr_fstat(fd: RawFd, st: bindings::stat64) -> io::Result<Option<(u32, u
139133 } ;
140134 if res < 0 {
141135 debug ! ( "fget_xattr error: {res}" ) ;
142- return Ok ( None ) ;
136+ return Ok ( ( None , None , None ) ) ;
143137 }
144138
145139 buf. resize ( res as usize , 0 ) ;
146140
147141 get_xattr_common ( & buf)
148142}
149143
150- fn get_xattr_lstat ( path : & CString , st : bindings:: stat64 ) -> io:: Result < Option < ( u32 , u32 , u32 ) > > {
144+ fn get_xattr_lstat (
145+ path : & CString ,
146+ st : bindings:: stat64 ,
147+ ) -> io:: Result < ( Option < u32 > , Option < u32 > , Option < u32 > ) > {
151148 let mut buf: Vec < u8 > = vec ! [ 0 ; 32 ] ;
152149 let options = if ( st. st_mode & libc:: S_IFMT ) == libc:: S_IFLNK {
153150 libc:: XATTR_NOFOLLOW
@@ -166,7 +163,7 @@ fn get_xattr_lstat(path: &CString, st: bindings::stat64) -> io::Result<Option<(u
166163 } ;
167164 if res < 0 {
168165 debug ! ( "fget_xattr error: {res}" ) ;
169- return Ok ( None ) ;
166+ return Ok ( ( None , None , None ) ) ;
170167 }
171168
172169 buf. resize ( res as usize , 0 ) ;
@@ -198,32 +195,46 @@ fn set_xattr_stat(
198195 0
199196 } ;
200197
201- let ( new_owner, new_mode) = if is_valid_owner ( owner) && mode. is_some ( ) {
202- ( owner. unwrap ( ) , mode. unwrap ( ) )
198+ let buf = if is_valid_owner ( owner) && mode. is_some ( ) {
199+ let owner = owner. unwrap ( ) ;
200+ let mode = mode. unwrap ( ) ;
201+ format ! ( "{}:{}:0{:o}" , owner. 0 , owner. 1 , mode)
203202 } else {
204- let ( orig_owner , orig_mode ) = if let Some ( ( xuid , xgid , xmode ) ) = match file {
203+ let ( orig_uid , orig_gid , orig_mode ) = match file {
205204 InodeHandle :: Fd ( fd) => get_xattr_fstat ( * fd, st) ?,
206205 InodeHandle :: Path ( ref c_path) => get_xattr_lstat ( c_path, st) ?,
207- } {
208- ( ( xuid, xgid) , xmode)
209- } else {
210- ( ( 0 , 0 ) , 0o0777 )
211206 } ;
212207
213- let new_owner = match owner {
208+ let ( uid , gid ) = match owner {
214209 Some ( o) => {
215- let uid = if o. 0 < UID_MAX { o. 0 } else { orig_owner . 0 } ;
216- let gid = if o. 1 < UID_MAX { o. 1 } else { orig_owner . 1 } ;
210+ let uid = if o. 0 < UID_MAX { Some ( o. 0 ) } else { orig_uid } ;
211+ let gid = if o. 1 < UID_MAX { Some ( o. 1 ) } else { orig_gid } ;
217212 ( uid, gid)
218213 }
219- None => orig_owner ,
214+ None => ( orig_uid , orig_gid ) ,
220215 } ;
221216
222- ( new_owner, mode. unwrap_or ( orig_mode) )
217+ let mut buf = String :: new ( ) ;
218+ if let Some ( uid) = uid {
219+ write ! ( & mut buf, "{uid}" ) ;
220+ } else {
221+ buf. push ( 'x' ) ;
222+ }
223+ if let Some ( gid) = gid {
224+ write ! ( & mut buf, ":{gid}:" ) ;
225+ } else {
226+ buf. push_str ( ":x:" ) ;
227+ }
228+ if let Some ( mode) = mode {
229+ write ! ( & mut buf, "0{mode:o}" ) ;
230+ } else if let Some ( orig_mode) = orig_mode {
231+ write ! ( & mut buf, "0{orig_mode:o}" ) ;
232+ } else {
233+ buf. push ( 'x' ) ;
234+ }
235+ buf
223236 } ;
224237
225- let buf = format ! ( "{}:{}:0{:o}" , new_owner. 0 , new_owner. 1 , new_mode) ;
226-
227238 let res = match file {
228239 InodeHandle :: Path ( path) => unsafe {
229240 libc:: setxattr (
@@ -254,6 +265,32 @@ fn set_xattr_stat(
254265 }
255266}
256267
268+ fn stat_common (
269+ mut st : bindings:: stat64 ,
270+ uid : Option < u32 > ,
271+ gid : Option < u32 > ,
272+ mode : Option < u32 > ,
273+ host : bool ,
274+ ) -> io:: Result < bindings:: stat64 > {
275+ if !host {
276+ if let Some ( uid) = uid {
277+ st. st_uid = uid;
278+ }
279+ if let Some ( gid) = gid {
280+ st. st_gid = gid;
281+ }
282+ if let Some ( mode) = mode {
283+ if mode as u16 & libc:: S_IFMT == 0 {
284+ st. st_mode = ( st. st_mode & libc:: S_IFMT ) | mode as u16 ;
285+ } else {
286+ st. st_mode = mode as u16 ;
287+ }
288+ }
289+ }
290+
291+ Ok ( st)
292+ }
293+
257294fn fstat ( fd : RawFd , host : bool ) -> io:: Result < bindings:: stat64 > {
258295 let mut st = MaybeUninit :: < bindings:: stat64 > :: zeroed ( ) ;
259296
@@ -262,21 +299,13 @@ fn fstat(fd: RawFd, host: bool) -> io::Result<bindings::stat64> {
262299 let res = unsafe { libc:: fstat ( fd, st. as_mut_ptr ( ) ) } ;
263300 if res >= 0 {
264301 // Safe because the kernel guarantees that the struct is now fully initialized.
265- let mut st = unsafe { st. assume_init ( ) } ;
266-
302+ let st = unsafe { st. assume_init ( ) } ;
267303 if !host {
268- if let Some ( ( uid, gid, mode) ) = get_xattr_fstat ( fd, st) ? {
269- st. st_uid = uid;
270- st. st_gid = gid;
271- if mode as u16 & libc:: S_IFMT == 0 {
272- st. st_mode = ( st. st_mode & libc:: S_IFMT ) | mode as u16 ;
273- } else {
274- st. st_mode = mode as u16 ;
275- }
276- }
304+ let ( uid, gid, mode) = get_xattr_fstat ( fd, st) ?;
305+ stat_common ( st, uid, gid, mode, host)
306+ } else {
307+ Ok ( st)
277308 }
278-
279- Ok ( st)
280309 } else {
281310 Err ( linux_error ( io:: Error :: last_os_error ( ) ) )
282311 }
@@ -290,21 +319,13 @@ fn lstat(c_path: &CString, host: bool) -> io::Result<bindings::stat64> {
290319 let res = unsafe { libc:: lstat ( c_path. as_ptr ( ) , st. as_mut_ptr ( ) ) } ;
291320 if res >= 0 {
292321 // Safe because the kernel guarantees that the struct is now fully initialized.
293- let mut st = unsafe { st. assume_init ( ) } ;
294-
322+ let st = unsafe { st. assume_init ( ) } ;
295323 if !host {
296- if let Some ( ( uid, gid, mode) ) = get_xattr_lstat ( c_path, st) ? {
297- st. st_uid = uid;
298- st. st_gid = gid;
299- if mode as u16 & libc:: S_IFMT == 0 {
300- st. st_mode = ( st. st_mode & libc:: S_IFMT ) | mode as u16 ;
301- } else {
302- st. st_mode = mode as u16 ;
303- }
304- }
324+ let ( uid, gid, mode) = get_xattr_lstat ( c_path, st) ?;
325+ stat_common ( st, uid, gid, mode, host)
326+ } else {
327+ Ok ( st)
305328 }
306-
307- Ok ( st)
308329 } else {
309330 Err ( linux_error ( io:: Error :: last_os_error ( ) ) )
310331 }
0 commit comments