21
21
22
22
import java .io .File ;
23
23
import java .io .IOException ;
24
+ import java .nio .file .FileSystem ;
24
25
import java .nio .file .Files ;
25
26
import java .nio .file .LinkOption ;
26
27
import java .nio .file .Path ;
27
28
import java .nio .file .attribute .FileTime ;
28
29
import java .nio .file .attribute .PosixFilePermission ;
29
30
import java .security .Principal ;
30
31
import java .util .Collections ;
31
- import java .util .HashMap ;
32
32
import java .util .Map ;
33
33
import java .util .Set ;
34
+ import java .util .WeakHashMap ;
35
+ import java .util .concurrent .ConcurrentHashMap ;
34
36
35
37
/*
36
38
* File attributes
@@ -68,6 +70,12 @@ public class FileAttributes implements PlexusIoResourceAttributes {
68
70
69
71
private final FileTime lastModifiedTime ;
70
72
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
+
71
79
/**
72
80
* @deprecated use {@link #FileAttributes(File)} and remove the unused userCache and groupCache parameters
73
81
*/
@@ -79,32 +87,64 @@ public FileAttributes(
79
87
}
80
88
81
89
public FileAttributes (@ Nonnull File file ) throws IOException {
82
- this (file , false );
90
+ this (file . toPath () , false );
83
91
}
84
92
85
93
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 {
86
106
LinkOption [] options = followLinks ? FOLLOW_LINK_OPTIONS : NOFOLLOW_LINK_OPTIONS ;
87
- Path path = file .toPath ();
88
107
Set <String > views = path .getFileSystem ().supportedFileAttributeViews ();
89
108
String names ;
90
109
if (views .contains ("unix" )) {
91
- names = "unix:*" ;
110
+ names =
111
+ "unix:gid,uid,isSymbolicLink,isRegularFile,isDirectory,isOther,mode,permissions,size,lastModifiedTime" ;
92
112
} else if (views .contains ("posix" )) {
93
113
names = "posix:*" ;
94
114
} else {
95
115
names = "basic:*" ;
96
116
}
97
117
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
- }
104
118
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
+ }
106
132
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
+ }
108
148
this .symbolicLink = (Boolean ) attrs .get ("isSymbolicLink" );
109
149
this .regularFile = (Boolean ) attrs .get ("isRegularFile" );
110
150
this .directory = (Boolean ) attrs .get ("isDirectory" );
@@ -120,6 +160,11 @@ public FileAttributes(@Nonnull File file, boolean followLinks) throws IOExceptio
120
160
this .lastModifiedTime = (FileTime ) attrs .get ("lastModifiedTime" );
121
161
}
122
162
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
+
123
168
public FileAttributes (
124
169
@ Nullable Integer userId ,
125
170
String userName ,
0 commit comments