@@ -479,6 +479,12 @@ impl User {
479479 Self :: from_uid ( Self :: real_uid ( ) )
480480 }
481481
482+ pub fn primary_group ( & self ) -> std:: io:: Result < Group > {
483+ // Use from_gid_unchecked here to ensure that we can still resolve when
484+ // the /etc/group entry for the primary group is missing.
485+ Group :: from_gid_unchecked ( self . gid )
486+ }
487+
482488 pub fn from_name ( name_c : & CStr ) -> Result < Option < User > , Error > {
483489 let max_pw_size = sysconf ( libc:: _SC_GETPW_R_SIZE_MAX) . unwrap_or ( 16_384 ) ;
484490 let mut buf = vec ! [ 0 ; max_pw_size as usize ] ;
@@ -511,7 +517,7 @@ impl User {
511517#[ cfg_attr( test, derive( PartialEq ) ) ]
512518pub struct Group {
513519 pub gid : GroupId ,
514- pub name : String ,
520+ pub name : Option < String > ,
515521}
516522
517523impl Group {
@@ -525,11 +531,12 @@ impl Group {
525531 let name = unsafe { string_from_ptr ( grp. gr_name ) } ;
526532 Group {
527533 gid : GroupId :: new ( grp. gr_gid ) ,
528- name,
534+ name : Some ( name ) ,
529535 }
530536 }
531537
532- pub fn from_gid ( gid : GroupId ) -> std:: io:: Result < Option < Group > > {
538+ /// Lookup group for gid without returning an error when a /etc/group entry is missing.
539+ fn from_gid_unchecked ( gid : GroupId ) -> std:: io:: Result < Group > {
533540 let max_gr_size = sysconf ( libc:: _SC_GETGR_R_SIZE_MAX) . unwrap_or ( 16_384 ) ;
534541 let mut buf = vec ! [ 0 ; max_gr_size as usize ] ;
535542 let mut grp = MaybeUninit :: uninit ( ) ;
@@ -545,13 +552,23 @@ impl Group {
545552 )
546553 } ) ?;
547554 if grp_ptr. is_null ( ) {
548- Ok ( None )
555+ Ok ( Group { gid , name : None } )
549556 } else {
550557 // SAFETY: grp_ptr was not null, and getgrgid_r succeeded, so we have assurances that
551558 // the `grp` structure was written to by getgrgid_r
552559 let grp = unsafe { grp. assume_init ( ) } ;
553560 // SAFETY: `pwd` was obtained by a call to getgrXXX_r, as required.
554- Ok ( Some ( unsafe { Group :: from_libc ( & grp) } ) )
561+ Ok ( unsafe { Group :: from_libc ( & grp) } )
562+ }
563+ }
564+
565+ pub fn from_gid ( gid : GroupId ) -> std:: io:: Result < Option < Group > > {
566+ let group = Self :: from_gid_unchecked ( gid) ?;
567+ if group. name . is_none ( ) {
568+ // No entry in /etc/group
569+ Ok ( None )
570+ } else {
571+ Ok ( Some ( group) )
555572 }
556573 }
557574
@@ -947,7 +964,7 @@ mod tests {
947964 for & ( id, name) in fixed_groups {
948965 let root = Group :: from_gid ( id) . unwrap ( ) . unwrap ( ) ;
949966 assert_eq ! ( root. gid, id) ;
950- assert_eq ! ( root. name, name) ;
967+ assert_eq ! ( root. name. unwrap ( ) , name) ;
951968 }
952969 }
953970
@@ -978,7 +995,7 @@ mod tests {
978995 }
979996 } ,
980997 Group {
981- name: name. to_string( ) ,
998+ name: Some ( name. to_string( ) ) ,
982999 gid: GroupId :: new( gid) ,
9831000 }
9841001 )
0 commit comments