3333
3434import static java .util .Comparator .comparing ;
3535import static org .elasticsearch .core .PathUtils .getDefaultFileSystem ;
36- import static org .elasticsearch .entitlement .runtime .policy .FileUtils .PATH_ORDER ;
3736import static org .elasticsearch .entitlement .runtime .policy .PathLookup .BaseDir .CONFIG ;
3837import static org .elasticsearch .entitlement .runtime .policy .PathLookup .BaseDir .TEMP ;
3938import static org .elasticsearch .entitlement .runtime .policy .entitlements .FilesEntitlement .Mode .READ_WRITE ;
7069 * Secondly, the path separator (whether slash or backslash) sorts after the dot character. This means, for example, if the array contains
7170 * {@code ["/a", "/a.xml"]} and we look up {@code "/a/b"} using normal string comparison, the binary search would land on {@code "/a.xml"},
7271 * which is neither an exact match nor a containing directory, and so the lookup would incorrectly report no match, even though
73- * {@code "/a"} is in the array. To fix this, we define {@link FileUtils#PATH_ORDER } which sorts path separators before any other
74- * character. In the example, this would cause {@code "/a/b"} to sort between {@code "/a"} and {@code "/a.xml"} so that it correctly
75- * finds {@code "/a"}.
72+ * {@code "/a"} is in the array. To fix this, we define {@link FileAccessTreeComparison#pathComparator() } which sorts path separators
73+ * before any other character. In the example, this would cause {@code "/a/b"} to sort between {@code "/a"} and {@code "/a.xml"} so that
74+ * it correctly finds {@code "/a"}.
7675 * </p>
7776 * With the paths pruned, sorted, and segregated by permission, each binary search has the following properties:
7877 * <ul>
@@ -118,7 +117,11 @@ public String toString() {
118117 }
119118 }
120119
121- static List <ExclusivePath > buildExclusivePathList (List <ExclusiveFileEntitlement > exclusiveFileEntitlements , PathLookup pathLookup ) {
120+ static List <ExclusivePath > buildExclusivePathList (
121+ List <ExclusiveFileEntitlement > exclusiveFileEntitlements ,
122+ PathLookup pathLookup ,
123+ FileAccessTreeComparison comparison
124+ ) {
122125 Map <String , ExclusivePath > exclusivePaths = new HashMap <>();
123126 for (ExclusiveFileEntitlement efe : exclusiveFileEntitlements ) {
124127 for (FilesEntitlement .FileData fd : efe .filesEntitlement ().filesData ()) {
@@ -150,16 +153,16 @@ static List<ExclusivePath> buildExclusivePathList(List<ExclusiveFileEntitlement>
150153 }
151154 }
152155 }
153- return exclusivePaths .values ().stream ().sorted (comparing (ExclusivePath ::path , PATH_ORDER )).distinct ().toList ();
156+ return exclusivePaths .values ().stream ().sorted (comparing (ExclusivePath ::path , comparison . pathComparator () )).distinct ().toList ();
154157 }
155158
156- static void validateExclusivePaths (List <ExclusivePath > exclusivePaths ) {
159+ static void validateExclusivePaths (List <ExclusivePath > exclusivePaths , FileAccessTreeComparison comparison ) {
157160 if (exclusivePaths .isEmpty () == false ) {
158161 ExclusivePath currentExclusivePath = exclusivePaths .get (0 );
159162 for (int i = 1 ; i < exclusivePaths .size (); ++i ) {
160163 ExclusivePath nextPath = exclusivePaths .get (i );
161- if (FileUtils .samePath (currentExclusivePath .path (), nextPath .path )
162- || FileUtils .isParent (currentExclusivePath .path (), nextPath .path ())) {
164+ if (comparison .samePath (currentExclusivePath .path (), nextPath .path )
165+ || comparison .isParent (currentExclusivePath .path (), nextPath .path ())) {
163166 throw new IllegalArgumentException (
164167 "duplicate/overlapping exclusive paths found in files entitlements: " + currentExclusivePath + " and " + nextPath
165168 );
@@ -171,7 +174,11 @@ static void validateExclusivePaths(List<ExclusivePath> exclusivePaths) {
171174
172175 private static final Logger logger = LogManager .getLogger (FileAccessTree .class );
173176 private static final String FILE_SEPARATOR = getDefaultFileSystem ().getSeparator ();
177+ static final FileAccessTreeComparison DEFAULT_COMPARISON = Platform .LINUX .isCurrent ()
178+ ? new CaseSensitiveComparison ()
179+ : new CaseInsensitiveComparison ();
174180
181+ private final FileAccessTreeComparison comparison ;
175182 /**
176183 * lists paths that are forbidden for this component+module because some other component has granted exclusive access to one of its
177184 * modules
@@ -189,19 +196,27 @@ static void validateExclusivePaths(List<ExclusivePath> exclusivePaths) {
189196 private static String [] buildUpdatedAndSortedExclusivePaths (
190197 String componentName ,
191198 String moduleName ,
192- List <ExclusivePath > exclusivePaths
199+ List <ExclusivePath > exclusivePaths ,
200+ FileAccessTreeComparison comparison
193201 ) {
194202 List <String > updatedExclusivePaths = new ArrayList <>();
195203 for (ExclusivePath exclusivePath : exclusivePaths ) {
196204 if (exclusivePath .componentName ().equals (componentName ) == false || exclusivePath .moduleNames ().contains (moduleName ) == false ) {
197205 updatedExclusivePaths .add (exclusivePath .path ());
198206 }
199207 }
200- updatedExclusivePaths .sort (PATH_ORDER );
208+ updatedExclusivePaths .sort (comparison . pathComparator () );
201209 return updatedExclusivePaths .toArray (new String [0 ]);
202210 }
203211
204- private FileAccessTree (FilesEntitlement filesEntitlement , PathLookup pathLookup , Path componentPath , String [] sortedExclusivePaths ) {
212+ FileAccessTree (
213+ FilesEntitlement filesEntitlement ,
214+ PathLookup pathLookup ,
215+ Path componentPath ,
216+ String [] sortedExclusivePaths ,
217+ FileAccessTreeComparison comparison
218+ ) {
219+ this .comparison = comparison ;
205220 List <String > readPaths = new ArrayList <>();
206221 List <String > writePaths = new ArrayList <>();
207222 BiConsumer <Path , Mode > addPath = (path , mode ) -> {
@@ -253,23 +268,23 @@ private FileAccessTree(FilesEntitlement filesEntitlement, PathLookup pathLookup,
253268 Path jdk = Paths .get (System .getProperty ("java.home" ));
254269 addPathAndMaybeLink .accept (jdk .resolve ("conf" ), Mode .READ );
255270
256- readPaths .sort (PATH_ORDER );
257- writePaths .sort (PATH_ORDER );
271+ readPaths .sort (comparison . pathComparator () );
272+ writePaths .sort (comparison . pathComparator () );
258273
259274 this .exclusivePaths = sortedExclusivePaths ;
260- this .readPaths = pruneSortedPaths (readPaths ).toArray (new String [0 ]);
261- this .writePaths = pruneSortedPaths (writePaths ).toArray (new String [0 ]);
275+ this .readPaths = pruneSortedPaths (readPaths , comparison ).toArray (new String [0 ]);
276+ this .writePaths = pruneSortedPaths (writePaths , comparison ).toArray (new String [0 ]);
262277 }
263278
264279 // package private for testing
265- static List <String > pruneSortedPaths (List <String > paths ) {
280+ static List <String > pruneSortedPaths (List <String > paths , FileAccessTreeComparison comparison ) {
266281 List <String > prunedReadPaths = new ArrayList <>();
267282 if (paths .isEmpty () == false ) {
268283 String currentPath = paths .get (0 );
269284 prunedReadPaths .add (currentPath );
270285 for (int i = 1 ; i < paths .size (); ++i ) {
271286 String nextPath = paths .get (i );
272- if (FileUtils .samePath (currentPath , nextPath ) == false && FileUtils .isParent (currentPath , nextPath ) == false ) {
287+ if (comparison .samePath (currentPath , nextPath ) == false && comparison .isParent (currentPath , nextPath ) == false ) {
273288 prunedReadPaths .add (nextPath );
274289 currentPath = nextPath ;
275290 }
@@ -290,7 +305,8 @@ static FileAccessTree of(
290305 filesEntitlement ,
291306 pathLookup ,
292307 componentPath ,
293- buildUpdatedAndSortedExclusivePaths (componentName , moduleName , exclusivePaths )
308+ buildUpdatedAndSortedExclusivePaths (componentName , moduleName , exclusivePaths , DEFAULT_COMPARISON ),
309+ DEFAULT_COMPARISON
294310 );
295311 }
296312
@@ -302,7 +318,7 @@ public static FileAccessTree withoutExclusivePaths(
302318 PathLookup pathLookup ,
303319 @ Nullable Path componentPath
304320 ) {
305- return new FileAccessTree (filesEntitlement , pathLookup , componentPath , new String [0 ]);
321+ return new FileAccessTree (filesEntitlement , pathLookup , componentPath , new String [0 ], DEFAULT_COMPARISON );
306322 }
307323
308324 public boolean canRead (Path path ) {
@@ -333,14 +349,14 @@ private boolean checkPath(String path, String[] paths) {
333349 return false ;
334350 }
335351
336- int endx = Arrays .binarySearch (exclusivePaths , path , PATH_ORDER );
337- if (endx < -1 && FileUtils .isParent (exclusivePaths [-endx - 2 ], path ) || endx >= 0 ) {
352+ int endx = Arrays .binarySearch (exclusivePaths , path , comparison . pathComparator () );
353+ if (endx < -1 && comparison .isParent (exclusivePaths [-endx - 2 ], path ) || endx >= 0 ) {
338354 return false ;
339355 }
340356
341- int ndx = Arrays .binarySearch (paths , path , PATH_ORDER );
357+ int ndx = Arrays .binarySearch (paths , path , comparison . pathComparator () );
342358 if (ndx < -1 ) {
343- return FileUtils .isParent (paths [-ndx - 2 ], path );
359+ return comparison .isParent (paths [-ndx - 2 ], path );
344360 }
345361 return ndx >= 0 ;
346362 }
0 commit comments