2121
2222import java .io .File ;
2323import java .io .IOException ;
24+ import java .nio .file .FileSystem ;
2425import java .nio .file .Files ;
2526import java .nio .file .LinkOption ;
2627import java .nio .file .Path ;
2728import java .nio .file .attribute .FileTime ;
2829import java .nio .file .attribute .PosixFilePermission ;
2930import java .security .Principal ;
3031import java .util .Collections ;
31- import java .util .HashMap ;
3232import java .util .Map ;
3333import java .util .Set ;
34+ import java .util .WeakHashMap ;
35+ import java .util .concurrent .ConcurrentHashMap ;
3436
3537/*
3638 * File attributes
@@ -68,6 +70,12 @@ public class FileAttributes implements PlexusIoResourceAttributes {
6870
6971 private final FileTime lastModifiedTime ;
7072
73+ private static final Map <FileSystem , Map <Integer , String >> UIDS_CACHE =
74+ Collections .synchronizedMap (new WeakHashMap <>());
75+
76+ private static final Map <FileSystem , Map <Integer , String >> GIDS_CACHE =
77+ Collections .synchronizedMap (new WeakHashMap <>());
78+
7179 /**
7280 * @deprecated use {@link #FileAttributes(File)} and remove the unused userCache and groupCache parameters
7381 */
@@ -79,32 +87,64 @@ public FileAttributes(
7987 }
8088
8189 public FileAttributes (@ Nonnull File file ) throws IOException {
82- this (file , false );
90+ this (file . toPath () , false );
8391 }
8492
8593 public FileAttributes (@ Nonnull File file , boolean followLinks ) throws IOException {
94+ this (file .toPath (), followLinks );
95+ }
96+
97+ private static Map <Integer , String > getUserCache (FileSystem fs ) {
98+ return UIDS_CACHE .computeIfAbsent (fs , f -> new ConcurrentHashMap <>());
99+ }
100+
101+ private static Map <Integer , String > getGroupCache (FileSystem fs ) {
102+ return GIDS_CACHE .computeIfAbsent (fs , f -> new ConcurrentHashMap <>());
103+ }
104+
105+ public FileAttributes (@ Nonnull Path path , boolean followLinks ) throws IOException {
86106 LinkOption [] options = followLinks ? FOLLOW_LINK_OPTIONS : NOFOLLOW_LINK_OPTIONS ;
87- Path path = file .toPath ();
88107 Set <String > views = path .getFileSystem ().supportedFileAttributeViews ();
89108 String names ;
90109 if (views .contains ("unix" )) {
91- names = "unix:*" ;
110+ names =
111+ "unix:gid,uid,isSymbolicLink,isRegularFile,isDirectory,isOther,mode,permissions,size,lastModifiedTime" ;
92112 } else if (views .contains ("posix" )) {
93113 names = "posix:*" ;
94114 } else {
95115 names = "basic:*" ;
96116 }
97117 Map <String , Object > attrs = Files .readAttributes (path , names , options );
98- if (!attrs .containsKey ("group" ) && !attrs .containsKey ("owner" ) && views .contains ("owner" )) {
99- Map <String , Object > ownerAttrs = Files .readAttributes (path , "owner:*" , options );
100- Map <String , Object > newAttrs = new HashMap <>(attrs );
101- newAttrs .putAll (ownerAttrs );
102- attrs = newAttrs ;
103- }
104118 this .groupId = (Integer ) attrs .get ("gid" );
105- this .groupName = attrs .containsKey ("group" ) ? ((Principal ) attrs .get ("group" )).getName () : null ;
119+ if (attrs .containsKey ("group" )) {
120+ this .groupName = ((Principal ) attrs .get ("group" )).getName ();
121+ } else if (this .groupId != null ) {
122+ Map <Integer , String > cache = getGroupCache (path .getFileSystem ());
123+ String name = cache .get (this .groupId );
124+ if (name == null ) {
125+ name = getPrincipalName (path , "unix:group" );
126+ cache .put (this .groupId , name );
127+ }
128+ this .groupName = name ;
129+ } else {
130+ this .groupName = null ;
131+ }
106132 this .userId = (Integer ) attrs .get ("uid" );
107- this .userName = attrs .containsKey ("owner" ) ? ((Principal ) attrs .get ("owner" )).getName () : null ;
133+ if (attrs .containsKey ("owner" )) {
134+ this .userName = ((Principal ) attrs .get ("owner" )).getName ();
135+ } else if (this .userId != null ) {
136+ Map <Integer , String > cache = getUserCache (path .getFileSystem ());
137+ String name = cache .get (this .userId );
138+ if (name == null ) {
139+ name = getPrincipalName (path , "unix:owner" );
140+ cache .put (this .userId , name );
141+ }
142+ this .userName = name ;
143+ } else if (views .contains ("owner" )) {
144+ this .userName = getPrincipalName (path , "owner:owner" );
145+ } else {
146+ this .userName = null ;
147+ }
108148 this .symbolicLink = (Boolean ) attrs .get ("isSymbolicLink" );
109149 this .regularFile = (Boolean ) attrs .get ("isRegularFile" );
110150 this .directory = (Boolean ) attrs .get ("isDirectory" );
@@ -120,6 +160,11 @@ public FileAttributes(@Nonnull File file, boolean followLinks) throws IOExceptio
120160 this .lastModifiedTime = (FileTime ) attrs .get ("lastModifiedTime" );
121161 }
122162
163+ private static String getPrincipalName (Path path , String attribute ) throws IOException {
164+ Object owner = Files .getAttribute (path , attribute , LinkOption .NOFOLLOW_LINKS );
165+ return ((Principal ) owner ).getName ();
166+ }
167+
123168 public FileAttributes (
124169 @ Nullable Integer userId ,
125170 String userName ,
0 commit comments