--- /dev/null 2018-05-07 23:51:01.519000000 -0700 +++ new/src/java.base/share/classes/java/nio/file/FilesMismatch.java 2018-09-18 19:47:12.936485688 -0700 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.nio.file; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Arrays; + +/** + * Utility methods for Files.mismatch. + */ +class FilesMismatch { + // see Files.mismatch for the specification + static long mismatch(Path path, Path path2) throws IOException { + long result = mismatchByAttrs(path, path2); + if (result != -2) { + return result; + } + + try (InputStream in1 = Files.newInputStream(path); + InputStream in2 = Files.newInputStream(path2);) { + result = mismatch(in1, in2); + return result; + } + } + + // check mismatch by file attributes, return -1 for no mismatch, 0 for mismatch + // at the beginning of the file, or -2 to indicate undetermined + private static long mismatchByAttrs(Path path, Path path2) throws IOException { + // initial values: -1 -- no mismatch + long result = -1; + try { + // the following checks NPE as well + path = path.toRealPath(); + path2 = path2.toRealPath(); + if (path.compareTo(path2) == 0) { + return result; + } + // readAttributes checks whether the file exists, throws IOE if not + BasicFileAttributes attrs1 = Files.readAttributes(path, BasicFileAttributes.class); + BasicFileAttributes attrs2 = Files.readAttributes(path2, BasicFileAttributes.class); + long s1 = attrs1.size(); + long s2 = attrs2.size(); + + if (s1 == 0 && s2 == 0) { + return result; + } + if (s1 == 0 && s2 > 0 || s1 > 0 && s2 == 0) { + return 0; + } + if (s1 == s2) { + Object k1 = attrs1.fileKey(); + if (k1 != null && k1.equals(attrs2.fileKey())) { + return result; + } + } + } catch (ProviderMismatchException e) { + throw new UnsupportedOperationException(e); + } + return -2; + } + + /** + * Finds and returns the index of the first mismatching byte in the content + * of two files. + * + * @param in1 an inputstream + * @param in2 another inputstream + * @return the mismatch index if a mismatch is found, otherwise -1 to indicate + * no mismatch + * @throws IOException + */ + private static long mismatch(InputStream in1, InputStream in2) + throws IOException { + byte[] buffer1 = new byte[Files.BUFFER_SIZE]; + byte[] buffer2 = new byte[Files.BUFFER_SIZE]; + int totalRead = 0; + while (true) { + int nRead1 = in1.readNBytes(buffer1, 0, Files.BUFFER_SIZE); + int nRead2 = in2.readNBytes(buffer2, 0, Files.BUFFER_SIZE); + + if (nRead1 == 0 || nRead2 == 0) { + if (nRead1 == 0 && nRead2 == 0) { + // both files reach EOF + return -1; + } else { + // one of the files reaches EOF + return totalRead; + } + } else if (nRead1 != nRead2) { + int len = Math.min(nRead1, nRead2); + // there's always a mismatch when nRead1 != nRead2 + return totalRead + + Arrays.mismatch(buffer1, 0, len, buffer2, 0, len); + + } else { + int i = Arrays.mismatch(buffer1, 0, nRead1, buffer2, 0, nRead1); + if (i > -1) { + return totalRead + i; + } + if (nRead1 < Files.BUFFER_SIZE) { + // we've reached the end of the files, but found no mismatch + return -1; + } + totalRead += nRead1; + } + } + } +}