39
39
import java .util .ArrayList ;
40
40
import java .util .Arrays ;
41
41
import java .util .Comparator ;
42
- import java .util .HashMap ;
43
42
import java .util .HashSet ;
44
43
import java .util .List ;
45
44
import java .util .Map ;
46
45
import java .util .Set ;
46
+ import java .util .TreeMap ;
47
47
import java .util .concurrent .CopyOnWriteArrayList ;
48
48
import java .util .concurrent .CountDownLatch ;
49
49
import java .util .concurrent .ExecutionException ;
@@ -124,7 +124,15 @@ public class IndexDatabase {
124
124
private final Object INSTANCE_LOCK = new Object ();
125
125
126
126
/** Key is canonical path; Value is the first accepted, absolute path. */
127
- private final Map <String , String > acceptedNonlocalSymlinks = new HashMap <>();
127
+ private final Map <String , String > acceptedNonlocalSymlinks = new TreeMap <>((o1 , o2 ) -> {
128
+ // DESC by length.
129
+ int cmp = Integer .compare (o2 .length (), o1 .length ());
130
+ if (cmp != 0 ) {
131
+ return cmp ;
132
+ }
133
+ // ASC by String value.
134
+ return o1 .compareTo (o2 );
135
+ });
128
136
129
137
private Project project ;
130
138
private FSDirectory indexDirectory ;
@@ -957,44 +965,84 @@ private boolean acceptSymlink(Path absolute, File canonical, AcceptSymlinkRet re
957
965
new Object [] {canonical1 , absolute1 });
958
966
}
959
967
return true ;
960
- } else {
961
- /*
962
- * Do not accept symlinks to local directories, because the
963
- * canonical target will be indexed on its own -- but
964
- * relativize() a path to be returned in ret so that
965
- * a symlink can be replicated in xref/.
966
- */
967
- ret .localRelPath = absolute .getParent ().relativize (
968
- canonical .toPath ()).toString ();
969
- return false ;
970
968
}
969
+
970
+ /*
971
+ * Do not accept symlinks to local directories, because the
972
+ * canonical target will be indexed on its own -- but relativize()
973
+ * a path to be returned in ret so that a symlink can be replicated
974
+ * in xref/.
975
+ */
976
+ ret .localRelPath = absolute .getParent ().relativize (
977
+ canonical .toPath ()).toString ();
978
+ return false ;
971
979
}
972
980
981
+ /*
982
+ * No need to synchronize access to acceptedNonlocalSymlinks, as
983
+ * indexDown() runs on one thread.
984
+ */
985
+
973
986
String absolute0 ;
974
- // No need to synchronize, as indexDown() runs on one thread.
975
987
if ((absolute0 = acceptedNonlocalSymlinks .get (canonical1 )) != null ) {
976
988
if (absolute1 .equals (absolute0 )) {
977
989
return true ;
978
- } else if (!isCanonicalDir ) {
979
- if (LOGGER .isLoggable (Level .FINE )) {
980
- LOGGER .log (Level .FINE , "External file {0} has symlink from {1} after first {2}" ,
990
+ }
991
+ if (!isCanonicalDir ) {
992
+ if (LOGGER .isLoggable (Level .FINEST )) {
993
+ LOGGER .log (Level .FINEST ,
994
+ "External file {0} has symlink from {1} after first {2}" ,
981
995
new Object [] {canonical1 , absolute1 , absolute0 });
982
996
}
983
997
return true ;
984
- } else {
998
+ }
999
+
1000
+ /*
1001
+ * Do not accept symlinks to external directories already accepted
1002
+ * as linked elsewhere, because the canonical target will be
1003
+ * indexed already -- but relativize() a path to be returned in ret
1004
+ * so that this second symlink can be redone as a local
1005
+ * (non-external) symlink in xref/.
1006
+ */
1007
+ ret .localRelPath = absolute .getParent ().relativize (
1008
+ Paths .get (absolute0 )).toString ();
1009
+
1010
+ if (LOGGER .isLoggable (Level .FINEST )) {
1011
+ LOGGER .log (Level .FINEST , "External dir {0} has symlink from {1} after first {2}" ,
1012
+ new Object [] {canonical1 , absolute1 , absolute0 });
1013
+ }
1014
+ return false ;
1015
+ }
1016
+
1017
+ /*
1018
+ * Iterate through acceptedNonlocalSymlinks, which is sorted so that
1019
+ * longer canonical entries come first, to see if the new link is a
1020
+ * child canonically.
1021
+ */
1022
+ for (String canonicalPrev : acceptedNonlocalSymlinks .keySet ()) {
1023
+ if (canonical1 .startsWith (canonicalPrev + File .separator )) {
1024
+ String absolutePrev = acceptedNonlocalSymlinks .get (canonicalPrev );
1025
+ if (!isCanonicalDir ) {
1026
+ if (LOGGER .isLoggable (Level .FINEST )) {
1027
+ LOGGER .log (Level .FINEST ,
1028
+ "External file {0} has symlink from {1} under previous {2}" ,
1029
+ new Object [] {canonical1 , absolute1 , absolutePrev });
1030
+ }
1031
+ return true ;
1032
+ }
1033
+
985
1034
/*
986
- * Do not accept symlinks to external directories already
987
- * accepted as linked elsewhere, because the canonical target
988
- * will be indexed already -- but relativize() a path to be
989
- * returned in ret so that this second symlink can be redone as
990
- * a local (non-external) symlink in xref/.
1035
+ * See above about redoing a sourceRoot symlink as a local
1036
+ * (non-external) symlink in xref/.
991
1037
*/
992
- ret .localRelPath = absolute .getParent ().relativize (
993
- Paths .get (absolute0 )).toString ();
1038
+ Path abs0 = Paths .get (absolutePrev , canonical1 .substring (
1039
+ canonicalPrev .length () + 1 ));
1040
+ ret .localRelPath = absolute .getParent ().relativize (abs0 ).toString ();
994
1041
995
- if (LOGGER .isLoggable (Level .FINE )) {
996
- LOGGER .log (Level .FINE , "External dir {0} has symlink from {1} after first {2}" ,
997
- new Object [] {canonical1 , absolute1 , absolute0 });
1042
+ if (LOGGER .isLoggable (Level .FINEST )) {
1043
+ LOGGER .log (Level .FINEST ,
1044
+ "External dir {0} has symlink from {1} under previous {2}" ,
1045
+ new Object [] {canonical1 , absolute1 , absolutePrev });
998
1046
}
999
1047
return false ;
1000
1048
}
@@ -1005,8 +1053,8 @@ private boolean acceptSymlink(Path absolute, File canonical, AcceptSymlinkRet re
1005
1053
Set <String > canonicalRoots = env .getCanonicalRoots ();
1006
1054
for (String canonicalRoot : canonicalRoots ) {
1007
1055
if (canonical1 .startsWith (canonicalRoot )) {
1008
- if (LOGGER .isLoggable (Level .FINE )) {
1009
- LOGGER .log (Level .FINE , "Allowed symlink {0} per canonical root {1}" ,
1056
+ if (LOGGER .isLoggable (Level .FINEST )) {
1057
+ LOGGER .log (Level .FINEST , "Allowed symlink {0} per canonical root {1}" ,
1010
1058
new Object [] {absolute1 , canonical1 });
1011
1059
}
1012
1060
acceptedNonlocalSymlinks .put (canonical1 , absolute1 );
0 commit comments