JCRVLT-49 support node names only differing in casing on case
insensitive file systems
WIP
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java
index a570690..33a3d9a 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java
@@ -100,9 +100,7 @@
case '/':
case'?':
case'%':
- buf.append('%');
- buf.append(Character.forDigit(c / 16, 16));
- buf.append(Character.forDigit(c % 16, 16));
+ addEscapedCharacter(buf, c);
break;
default:
buf.append(c);
@@ -115,6 +113,12 @@
}
}
+ public static void addEscapedCharacter(StringBuilder buf, char c) {
+ buf.append('%');
+ buf.append(Character.forDigit(c / 16, 16));
+ buf.append(Character.forDigit(c % 16, 16));
+ }
+
/**
* Returns the platform path for the given repository one.
* @param repoPath the repository path
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java
index 27fff62..d387b71 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-@Version("2.10.0")
+@Version("2.11.0")
package org.apache.jackrabbit.vault.util;
import org.osgi.annotation.versioning.Version;
\ No newline at end of file
diff --git a/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltDirectory.java b/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltDirectory.java
index c5014e5..4412c26 100644
--- a/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltDirectory.java
+++ b/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltDirectory.java
@@ -18,11 +18,16 @@
import java.io.File;
import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
+import java.util.Optional;
import java.util.Set;
+import java.util.function.Predicate;
import javax.jcr.RepositoryException;
@@ -33,6 +38,7 @@
import org.apache.jackrabbit.vault.util.Constants;
import org.apache.jackrabbit.vault.util.FileInputSource;
import org.apache.jackrabbit.vault.util.LineOutputStream;
+import org.apache.jackrabbit.vault.util.PlatformNameFormat;
import org.apache.jackrabbit.vault.vlt.actions.Action;
import org.apache.jackrabbit.vault.vlt.meta.MetaDirectory;
import org.apache.jackrabbit.vault.vlt.meta.VltEntries;
@@ -76,6 +82,78 @@
init();
}
+ /**
+ * Escapes the given name according to the file escaping rules in case a conflicting file name (e.g. just differ by case in case-ignoring filesystem) exists
+ * in the current directory.
+ *
+ * @param name
+ * @return
+ */
+ String escapeToMakeUnique(String name) {
+ File newFile = new File(dir, name);
+ Predicate<VltFile> sameFilePredicate = f -> {
+ try {
+ return Files.isSameFile(f.getFile().toPath(), newFile.toPath());
+ } catch (NoSuchFileException e) {
+ // ignore
+ return false;
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ };
+ Optional<VltFile> conflictingFile = getFiles().stream().filter(sameFilePredicate).findFirst();
+ if (conflictingFile.isPresent()) {
+ int firstDiffIndex = indexOfDifference(name, conflictingFile.get().getName());
+ StringBuilder newName = new StringBuilder(name.substring(0, firstDiffIndex));
+ PlatformNameFormat.addEscapedCharacter(newName, name.charAt(firstDiffIndex));
+ newName.append(name.substring(firstDiffIndex+1));
+ return newName.toString();
+ } else {
+ return name;
+ }
+ }
+
+ /**
+ * Compares two Strings, and returns the index at which the
+ * Strings begin to differ.
+ *
+ * For example,
+ * <code>indexOfDifference("i am a machine", "i am a robot") -> 7</code>
+ *
+ * <pre>
+ * StringUtils.indexOfDifference(null, null) = -1
+ * StringUtils.indexOfDifference("", "") = -1
+ * StringUtils.indexOfDifference("", "abc") = 0
+ * StringUtils.indexOfDifference("abc", "") = 0
+ * StringUtils.indexOfDifference("abc", "abc") = -1
+ * StringUtils.indexOfDifference("ab", "abxyz") = 2
+ * StringUtils.indexOfDifference("abcde", "abxyz") = 2
+ * StringUtils.indexOfDifference("abcde", "xyz") = 0
+ * </pre>
+ *
+ * @param str1 the first String, may be null
+ * @param str2 the second String, may be null
+ * @return the index where str2 and str1 begin to differ; -1 if they are equal
+ */
+ private static int indexOfDifference(String str1, String str2) {
+ if (str1 == str2) {
+ return -1;
+ }
+ if (str1 == null || str2 == null) {
+ return 0;
+ }
+ int i;
+ for (i = 0; i < str1.length() && i < str2.length(); ++i) {
+ if (str1.charAt(i) != str2.charAt(i)) {
+ break;
+ }
+ }
+ if (i < str2.length() || i < str1.length()) {
+ return i;
+ }
+ return -1;
+ }
+
public VltDirectory getParent() throws VltException {
return new VltDirectory(ctx, dir.getParentFile());
}
diff --git a/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltFile.java b/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltFile.java
index d7c970e..68e07a0 100644
--- a/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltFile.java
+++ b/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltFile.java
@@ -95,6 +95,10 @@
public VltFile(VltDirectory parent, String name, VltEntry entry)
throws VltException {
this.parent = parent;
+ if (entry == null) {
+ // potentially modify the name
+ name = parent.escapeToMakeUnique(name);
+ }
this.name = name;
this.entry = entry;
this.file = new File(parent.getDirectory(), name);