0N/A/*
2362N/A * Copyright (c) 1998, 2000, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A @summary Common definitions for general exhaustive pathname tests
0N/A @author Mark Reinhold
0N/A */
0N/A
0N/Aimport java.io.*;
0N/Aimport java.util.*;
0N/A
0N/A
0N/Apublic class General {
0N/A
0N/A public static boolean debug = false;
0N/A
0N/A private static boolean win32 = (File.separatorChar == '\\');
0N/A
0N/A private static int gensymCounter = 0;
0N/A
0N/A
0N/A /* Generate a filename unique to this run */
0N/A private static String gensym() {
0N/A return "x." + ++gensymCounter;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Find a file in the given subdirectory, or descend into further
0N/A * subdirectories, if any, if no file is found here. Return null if no
0N/A * file can be found anywhere beneath the given subdirectory.
0N/A * @param dir Directory at which we started
0N/A * @param subdir Subdirectory that we're exploring
0N/A * @param dl Listing of subdirectory
0N/A */
0N/A private static String findSomeFile(String dir, String subdir, String[] dl) {
0N/A for (int i = 0; i < dl.length; i++) {
0N/A File f = new File(subdir, dl[i]);
0N/A File df = new File(dir, f.getPath());
0N/A if (df.exists() && df.isFile()) {
0N/A return f.getPath();
0N/A }
0N/A }
0N/A for (int i = 0; i < dl.length; i++) {
0N/A File f = (subdir.length() == 0) ? new File(dl[i])
0N/A : new File(subdir, dl[i]);
0N/A File df = new File(dir, f.getPath());
0N/A if (df.exists() && df.isDirectory()) {
0N/A String[] dl2 = df.list();
0N/A if (dl2 != null) {
0N/A String ff = findSomeFile(dir, f.getPath(), dl2);
0N/A if (ff != null) return ff;
0N/A }
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Construct a string that names a file in the given directory. If create
0N/A * is true, then create a file if none is found, and throw an exception if
0N/A * that is not possible; otherwise, return null if no file can be found.
0N/A */
0N/A private static String findSomeFile(String dir, boolean create) {
0N/A File d = new File(dir);
0N/A String[] dl = d.list();
0N/A if (dl == null) {
0N/A throw new RuntimeException("Can't list " + dir);
0N/A }
0N/A for (int i = 0; i < dl.length; i++) {
0N/A File f = new File(dir, dl[i]);
0N/A if (f.isFile()) {
0N/A return dl[i];
0N/A }
0N/A }
0N/A String f = findSomeFile(dir, "", dl);
0N/A if (f != null) {
0N/A return f;
0N/A }
0N/A if (create) {
0N/A File nf = new File(d, gensym());
0N/A OutputStream os;
0N/A try {
0N/A os = new FileOutputStream(nf);
0N/A os.close();
0N/A } catch (IOException x) {
0N/A throw new RuntimeException("Can't create a file in " + dir);
0N/A }
0N/A return nf.getName();
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Construct a string that names a subdirectory of the given directory.
0N/A * If create is true, then create a subdirectory if none is found, and
0N/A * throw an exception if that is not possible; otherwise, return null if
0N/A * no subdirectory can be found.
0N/A */
0N/A private static String findSomeDir(String dir, boolean create) {
0N/A File d = new File(dir);
0N/A String[] dl = d.list();
0N/A if (dl == null) {
0N/A throw new RuntimeException("Can't list " + dir);
0N/A }
0N/A for (int i = 0; i < dl.length; i++) {
0N/A File f = new File(d, dl[i]);
0N/A if (f.isDirectory() && f.canRead()) {
0N/A String[] dl2 = f.list();
0N/A if (dl2.length >= 250) {
0N/A /* Heuristic to avoid scanning huge directories */
0N/A continue;
0N/A }
0N/A return dl[i];
0N/A }
0N/A }
0N/A if (create) {
0N/A File sd = new File(d, gensym());
0N/A if (sd.mkdir()) return sd.getName();
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A
0N/A /** Construct a string that does not name a file in the given directory */
0N/A private static String findNon(String dir) {
0N/A File d = new File(dir);
0N/A String[] x = new String[] { "foo", "bar", "baz" };
0N/A for (int i = 0; i < x.length; i++) {
0N/A File f = new File(d, x[i]);
0N/A if (!f.exists()) {
0N/A return x[i];
0N/A }
0N/A }
0N/A for (int i = 0; i < 1024; i++) {
0N/A String n = "xx" + Integer.toString(i);
0N/A File f = new File(d, n);
0N/A if (!f.exists()) {
0N/A return n;
0N/A }
0N/A }
0N/A throw new RuntimeException("Can't find a non-existent file in " + dir);
0N/A }
0N/A
0N/A
0N/A /** Ensure that the named file does not exist */
0N/A public static void ensureNon(String fn) {
0N/A if ((new File(fn)).exists()) {
0N/A throw new RuntimeException("Test path " + fn + " exists");
0N/A }
0N/A }
0N/A
0N/A
0N/A /** Tell whether the given character is a "slash" on this platform */
0N/A private static boolean isSlash(char x) {
0N/A if (x == File.separatorChar) return true;
0N/A if (win32 && (x == '/')) return true;
0N/A return false;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Trim trailing slashes from the given string, but leave singleton slashes
0N/A * alone (they denote root directories)
0N/A */
0N/A private static String trimTrailingSlashes(String s) {
0N/A int n = s.length();
0N/A if (n == 0) return s;
0N/A n--;
0N/A while ((n > 0) && isSlash(s.charAt(n))) {
0N/A if ((n >= 1) && s.charAt(n - 1) == ':') break;
0N/A n--;
0N/A }
0N/A return s.substring(0, n + 1);
0N/A }
0N/A
0N/A
0N/A /** Concatenate two paths, trimming slashes as needed */
0N/A private static String pathConcat(String a, String b) {
0N/A if (a.length() == 0) return b;
0N/A if (b.length() == 0) return a;
0N/A if (isSlash(a.charAt(a.length() - 1))
0N/A || isSlash(b.charAt(0))
0N/A || (win32 && (a.charAt(a.length() - 1) == ':'))) {
0N/A return a + b;
0N/A } else {
0N/A return a + File.separatorChar + b;
0N/A }
0N/A }
0N/A
0N/A
0N/A
0N/A /** Hash table of input pathnames, used to detect duplicates */
0N/A private static Hashtable checked = new Hashtable();
0N/A
0N/A /**
0N/A * Check the given pathname. Its canonical pathname should be the given
0N/A * answer. If the path names a file that exists and is readable, then
0N/A * FileInputStream and RandomAccessFile should both be able to open it.
0N/A */
0N/A public static void check(String answer, String path) throws IOException {
0N/A String ans = trimTrailingSlashes(answer);
0N/A if (path.length() == 0) return;
0N/A if (checked.get(path) != null) {
0N/A System.err.println("DUP " + path);
0N/A return;
0N/A }
0N/A checked.put(path, path);
0N/A
0N/A String cpath;
0N/A try {
0N/A File f = new File(path);
0N/A cpath = f.getCanonicalPath();
0N/A if (f.exists() && f.isFile() && f.canRead()) {
0N/A InputStream in = new FileInputStream(path);
0N/A in.close();
0N/A RandomAccessFile raf = new RandomAccessFile(path, "r");
0N/A raf.close();
0N/A }
0N/A } catch (IOException x) {
0N/A System.err.println(ans + " <-- " + path + " ==> " + x);
0N/A if (debug) return;
0N/A else throw x;
0N/A }
0N/A if (cpath.equals(ans)) {
0N/A System.err.println(ans + " <== " + path);
0N/A } else {
0N/A System.err.println(ans + " <-- " + path + " ==> " + cpath + " MISMATCH");
0N/A if (!debug) {
0N/A throw new RuntimeException("Mismatch: " + path + " ==> " + cpath +
0N/A ", should be " + ans);
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A
0N/A /*
0N/A * The following three mutually-recursive methods generate and check a tree
0N/A * of filenames of arbitrary depth. Each method has (at least) these
0N/A * arguments:
0N/A *
0N/A * int depth Remaining tree depth
0N/A * boolean create Controls whether test files and directories
0N/A * will be created as needed
0N/A * String ans Expected answer for the check method (above)
0N/A * String ask Input pathname to be passed to the check method
0N/A */
0N/A
0N/A
0N/A /** Check a single slash case, plus its children */
0N/A public static void checkSlash(int depth, boolean create,
0N/A String ans, String ask, String slash)
0N/A throws Exception
0N/A {
0N/A check(ans, ask + slash);
0N/A checkNames(depth, create,
0N/A ans.endsWith(File.separator) ? ans : ans + File.separator,
0N/A ask + slash);
0N/A }
0N/A
0N/A
0N/A /** Check slash cases for the given ask string */
0N/A public static void checkSlashes(int depth, boolean create,
0N/A String ans, String ask)
0N/A throws Exception
0N/A {
0N/A check(ans, ask);
0N/A if (depth == 0) return;
0N/A
0N/A checkSlash(depth, create, ans, ask, "/");
0N/A checkSlash(depth, create, ans, ask, "//");
0N/A checkSlash(depth, create, ans, ask, "///");
0N/A if (win32) {
0N/A checkSlash(depth, create, ans, ask, "\\");
0N/A checkSlash(depth, create, ans, ask, "\\\\");
0N/A checkSlash(depth, create, ans, ask, "\\/");
0N/A checkSlash(depth, create, ans, ask, "/\\");
0N/A checkSlash(depth, create, ans, ask, "\\\\\\");
0N/A }
0N/A }
0N/A
0N/A
0N/A /** Check name cases for the given ask string */
0N/A public static void checkNames(int depth, boolean create,
0N/A String ans, String ask)
0N/A throws Exception
0N/A {
0N/A int d = depth - 1;
0N/A File f = new File(ans);
0N/A String n;
0N/A
0N/A /* Normal name */
0N/A if (f.exists()) {
0N/A if (f.isDirectory() && f.canRead()) {
0N/A if ((n = findSomeFile(ans, create)) != null)
0N/A checkSlashes(d, create, ans + n, ask + n);
0N/A if ((n = findSomeDir(ans, create)) != null)
0N/A checkSlashes(d, create, ans + n, ask + n);
0N/A }
0N/A n = findNon(ans);
0N/A checkSlashes(d, create, ans + n, ask + n);
0N/A } else {
0N/A n = "foo" + depth;
0N/A checkSlashes(d, create, ans + n, ask + n);
0N/A }
0N/A
0N/A /* "." */
0N/A checkSlashes(d, create, trimTrailingSlashes(ans), ask + ".");
0N/A
0N/A /* ".." */
0N/A if ((n = f.getParent()) != null) {
0N/A String n2;
0N/A if (win32
0N/A && ((n2 = f.getParentFile().getParent()) != null)
0N/A && n2.equals("\\\\")) {
0N/A /* Win32 resolves \\foo\bar\.. to \\foo\bar */
0N/A checkSlashes(d, create, ans, ask + "..");
0N/A } else {
0N/A checkSlashes(d, create, n, ask + "..");
0N/A }
0N/A }
0N/A else {
0N/A if (win32)
0N/A checkSlashes(d, create, ans, ask + "..");
0N/A else {
0N/A // Fix for 4237875. We must ensure that we are sufficiently
0N/A // deep in the path hierarchy to test parents this high up
0N/A File thisPath = new File(ask);
0N/A File nextPath = new File(ask + "..");
0N/A if (!thisPath.getCanonicalPath().equals(nextPath.getCanonicalPath()))
0N/A checkSlashes(d, create, ans + "..", ask + "..");
0N/A }
0N/A }
0N/A }
0N/A}