1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.nio.file; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.nio.file.attribute.BasicFileAttributes; 31 import java.util.Arrays; 32 33 /** 34 * Utility methods for Files.mismatch. 35 */ 36 class FilesMismatch { 37 // see Files.mismatch for the specification 38 static long mismatch(Path path, Path path2) throws IOException { 39 long result = mismatchByAttrs(path, path2); 40 if (result != -2) { 41 return result; 42 } 43 44 try (InputStream in1 = Files.newInputStream(path); 45 InputStream in2 = Files.newInputStream(path2);) { 46 result = mismatch(in1, in2); 47 return result; 48 } 49 } 50 51 // check mismatch by file attributes, return -1 for no mismatch, 0 for mismatch 52 // at the beginning of the file, or -2 to indicate undetermined 53 private static long mismatchByAttrs(Path path, Path path2) throws IOException { 54 // initial values: -1 -- no mismatch 55 long result = -1; 56 try { 57 // the following checks NPE as well 58 path = path.toRealPath(); 59 path2 = path2.toRealPath(); 60 if (path.compareTo(path2) == 0) { 61 return result; 62 } 63 // readAttributes checks whether the file exists, throws IOE if not 64 BasicFileAttributes attrs1 = Files.readAttributes(path, BasicFileAttributes.class); 65 BasicFileAttributes attrs2 = Files.readAttributes(path2, BasicFileAttributes.class); 66 long s1 = attrs1.size(); 67 long s2 = attrs2.size(); 68 69 if (s1 == 0 && s2 == 0) { 70 return result; 71 } 72 if (s1 == 0 && s2 > 0 || s1 > 0 && s2 == 0) { 73 return 0; 74 } 75 if (s1 == s2) { 76 Object k1 = attrs1.fileKey(); 77 if (k1 != null && k1.equals(attrs2.fileKey())) { 78 return result; 79 } 80 } 81 } catch (ProviderMismatchException e) { 82 throw new UnsupportedOperationException(e); 83 } 84 return -2; 85 } 86 87 /** 88 * Finds and returns the index of the first mismatching byte in the content 89 * of two files. 90 * 91 * @param in1 an inputstream 92 * @param in2 another inputstream 93 * @return the mismatch index if a mismatch is found, otherwise -1 to indicate 94 * no mismatch 95 * @throws IOException 96 */ 97 private static long mismatch(InputStream in1, InputStream in2) 98 throws IOException { 99 byte[] buffer1 = new byte[Files.BUFFER_SIZE]; 100 byte[] buffer2 = new byte[Files.BUFFER_SIZE]; 101 int totalRead = 0; 102 while (true) { 103 int nRead1 = in1.readNBytes(buffer1, 0, Files.BUFFER_SIZE); 104 int nRead2 = in2.readNBytes(buffer2, 0, Files.BUFFER_SIZE); 105 106 if (nRead1 == 0 || nRead2 == 0) { 107 if (nRead1 == 0 && nRead2 == 0) { 108 // both files reach EOF 109 return -1; 110 } else { 111 // one of the files reaches EOF 112 return totalRead; 113 } 114 } else if (nRead1 != nRead2) { 115 int len = Math.min(nRead1, nRead2); 116 // there's always a mismatch when nRead1 != nRead2 117 return totalRead + 118 Arrays.mismatch(buffer1, 0, len, buffer2, 0, len); 119 120 } else { 121 int i = Arrays.mismatch(buffer1, 0, nRead1, buffer2, 0, nRead1); 122 if (i > -1) { 123 return totalRead + i; 124 } 125 if (nRead1 < Files.BUFFER_SIZE) { 126 // we've reached the end of the files, but found no mismatch 127 return -1; 128 } 129 totalRead += nRead1; 130 } 131 } 132 } 133 }