/* * Copyright (c) 1998, 2000, 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. * * 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. */ /* @summary Common definitions for general exhaustive pathname tests @author Mark Reinhold */ import java.io.*; import java.util.*; public class General { public static boolean debug = false; private static boolean win32 = (File.separatorChar == '\\'); private static int gensymCounter = 0; /* Generate a filename unique to this run */ private static String gensym() { return "x." + ++gensymCounter; } /** * Find a file in the given subdirectory, or descend into further * subdirectories, if any, if no file is found here. Return null if no * file can be found anywhere beneath the given subdirectory. * @param dir Directory at which we started * @param subdir Subdirectory that we're exploring * @param dl Listing of subdirectory */ private static String findSomeFile(String dir, String subdir, String[] dl) { for (int i = 0; i < dl.length; i++) { File f = new File(subdir, dl[i]); File df = new File(dir, f.getPath()); if (df.exists() && df.isFile()) { return f.getPath(); } } for (int i = 0; i < dl.length; i++) { File f = (subdir.length() == 0) ? new File(dl[i]) : new File(subdir, dl[i]); File df = new File(dir, f.getPath()); if (df.exists() && df.isDirectory()) { String[] dl2 = df.list(); if (dl2 != null) { String ff = findSomeFile(dir, f.getPath(), dl2); if (ff != null) return ff; } } } return null; } /** * Construct a string that names a file in the given directory. If create * is true, then create a file if none is found, and throw an exception if * that is not possible; otherwise, return null if no file can be found. */ private static String findSomeFile(String dir, boolean create) { File d = new File(dir); String[] dl = d.list(); if (dl == null) { throw new RuntimeException("Can't list " + dir); } for (int i = 0; i < dl.length; i++) { File f = new File(dir, dl[i]); if (f.isFile()) { return dl[i]; } } String f = findSomeFile(dir, "", dl); if (f != null) { return f; } if (create) { File nf = new File(d, gensym()); OutputStream os; try { os = new FileOutputStream(nf); os.close(); } catch (IOException x) { throw new RuntimeException("Can't create a file in " + dir); } return nf.getName(); } return null; } /** * Construct a string that names a subdirectory of the given directory. * If create is true, then create a subdirectory if none is found, and * throw an exception if that is not possible; otherwise, return null if * no subdirectory can be found. */ private static String findSomeDir(String dir, boolean create) { File d = new File(dir); String[] dl = d.list(); if (dl == null) { throw new RuntimeException("Can't list " + dir); } for (int i = 0; i < dl.length; i++) { File f = new File(d, dl[i]); if (f.isDirectory()) { String[] dl2 = f.list(); if (dl2 == null || dl2.length >= 250) { /* Heuristic to avoid scanning huge directories */ continue; } return dl[i]; } } if (create) { File sd = new File(d, gensym()); if (sd.mkdir()) return sd.getName(); } return null; } /** Construct a string that does not name a file in the given directory */ private static String findNon(String dir) { File d = new File(dir); String[] x = new String[] { "foo", "bar", "baz" }; for (int i = 0; i < x.length; i++) { File f = new File(d, x[i]); if (!f.exists()) { return x[i]; } } for (int i = 0; i < 1024; i++) { String n = "xx" + Integer.toString(i); File f = new File(d, n); if (!f.exists()) { return n; } } throw new RuntimeException("Can't find a non-existent file in " + dir); } /** Ensure that the named file does not exist */ public static void ensureNon(String fn) { if ((new File(fn)).exists()) { throw new RuntimeException("Test path " + fn + " exists"); } } /** Tell whether the given character is a "slash" on this platform */ private static boolean isSlash(char x) { if (x == File.separatorChar) return true; if (win32 && (x == '/')) return true; return false; } /** * Trim trailing slashes from the given string, but leave singleton slashes * alone (they denote root directories) */ private static String trimTrailingSlashes(String s) { int n = s.length(); if (n == 0) return s; n--; while ((n > 0) && isSlash(s.charAt(n))) { if ((n >= 1) && s.charAt(n - 1) == ':') break; n--; } return s.substring(0, n + 1); } /** Concatenate two paths, trimming slashes as needed */ private static String pathConcat(String a, String b) { if (a.length() == 0) return b; if (b.length() == 0) return a; if (isSlash(a.charAt(a.length() - 1)) || isSlash(b.charAt(0)) || (win32 && (a.charAt(a.length() - 1) == ':'))) { return a + b; } else { return a + File.separatorChar + b; } } /** Hash table of input pathnames, used to detect duplicates */ private static Hashtable checked = new Hashtable(); /** * Check the given pathname. Its canonical pathname should be the given * answer. If the path names a file that exists and is readable, then * FileInputStream and RandomAccessFile should both be able to open it. */ public static void check(String answer, String path) throws IOException { String ans = trimTrailingSlashes(answer); if (path.length() == 0) return; if (checked.get(path) != null) { System.err.println("DUP " + path); return; } checked.put(path, path); String cpath; try { File f = new File(path); cpath = f.getCanonicalPath(); if (f.exists() && f.isFile() && f.canRead()) { InputStream in = new FileInputStream(path); in.close(); RandomAccessFile raf = new RandomAccessFile(path, "r"); raf.close(); } } catch (IOException x) { System.err.println(ans + " <-- " + path + " ==> " + x); if (debug) return; else throw x; } if (cpath.equals(ans)) { System.err.println(ans + " <== " + path); } else { System.err.println(ans + " <-- " + path + " ==> " + cpath + " MISMATCH"); if (!debug) { throw new RuntimeException("Mismatch: " + path + " ==> " + cpath + ", should be " + ans); } } } /* * The following three mutually-recursive methods generate and check a tree * of filenames of arbitrary depth. Each method has (at least) these * arguments: * * int depth Remaining tree depth * boolean create Controls whether test files and directories * will be created as needed * String ans Expected answer for the check method (above) * String ask Input pathname to be passed to the check method */ /** Check a single slash case, plus its children */ public static void checkSlash(int depth, boolean create, String ans, String ask, String slash) throws Exception { check(ans, ask + slash); checkNames(depth, create, ans.endsWith(File.separator) ? ans : ans + File.separator, ask + slash); } /** Check slash cases for the given ask string */ public static void checkSlashes(int depth, boolean create, String ans, String ask) throws Exception { check(ans, ask); if (depth == 0) return; checkSlash(depth, create, ans, ask, "/"); checkSlash(depth, create, ans, ask, "//"); checkSlash(depth, create, ans, ask, "///"); if (win32) { checkSlash(depth, create, ans, ask, "\\"); checkSlash(depth, create, ans, ask, "\\\\"); checkSlash(depth, create, ans, ask, "\\/"); checkSlash(depth, create, ans, ask, "/\\"); checkSlash(depth, create, ans, ask, "\\\\\\"); } } /** Check name cases for the given ask string */ public static void checkNames(int depth, boolean create, String ans, String ask) throws Exception { int d = depth - 1; File f = new File(ans); String n; /* Normal name */ if (f.exists()) { if (f.isDirectory() && f.canRead()) { if ((n = findSomeFile(ans, create)) != null) checkSlashes(d, create, ans + n, ask + n); if ((n = findSomeDir(ans, create)) != null) checkSlashes(d, create, ans + n, ask + n); } n = findNon(ans); checkSlashes(d, create, ans + n, ask + n); } else { n = "foo" + depth; checkSlashes(d, create, ans + n, ask + n); } /* "." */ checkSlashes(d, create, trimTrailingSlashes(ans), ask + "."); /* ".." */ if ((n = f.getParent()) != null) { String n2; if (win32 && ((n2 = f.getParentFile().getParent()) != null) && n2.equals("\\\\")) { /* Win32 resolves \\foo\bar\.. to \\foo\bar */ checkSlashes(d, create, ans, ask + ".."); } else { checkSlashes(d, create, n, ask + ".."); } } else { if (win32) checkSlashes(d, create, ans, ask + ".."); else { // Fix for 4237875. We must ensure that we are sufficiently // deep in the path hierarchy to test parents this high up File thisPath = new File(ask); File nextPath = new File(ask + ".."); if (!thisPath.getCanonicalPath().equals(nextPath.getCanonicalPath())) checkSlashes(d, create, ans + "..", ask + ".."); } } } }