/* * Copyright (c) 2009, 2011, 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. */ /* @test * @bug 6595866 * @summary Test java.io.File operations with sym links */ import java.io.*; import java.nio.file.*; import java.nio.file.attribute.*; import static java.nio.file.LinkOption.*; public class SymLinks { final static PrintStream out = System.out; final static File top = new File(System.getProperty("test.dir", ".")); // files used by the test final static File file = new File(top, "foofile"); final static File link2file = new File(top, "link2file"); final static File link2link2file = new File(top, "link2link2file"); final static File dir = new File(top, "foodir"); final static File link2dir = new File(top, "link2dir"); final static File link2link2dir = new File(top, "link2link2dir"); final static File link2nobody = new File(top, "link2nobody"); final static File link2link2nobody = new File(top, "link2link2nobody"); /** * Setup files, directories, and sym links used by test. */ static void setup() throws IOException { // link2link2file -> link2file -> foofile FileOutputStream fos = new FileOutputStream(file); try { fos.write(new byte[16*1024]); } finally { fos.close(); } mklink(link2file, file); mklink(link2link2file, link2file); // link2link2dir -> link2dir -> dir assertTrue(dir.mkdir()); mklink(link2dir, dir); mklink(link2link2dir, link2dir); // link2link2nobody -> link2nobody -> mklink(link2nobody, new File(top, "DoesNotExist")); mklink(link2link2nobody, link2nobody); } /** * Remove files, directories, and sym links used by test. */ static void cleanup() throws IOException { if (file != null) file.delete(); if (link2file != null) Files.deleteIfExists(link2file.toPath()); if (link2link2file != null) Files.deleteIfExists(link2link2file.toPath()); if (dir != null) dir.delete(); if (link2dir != null) Files.deleteIfExists(link2dir.toPath()); if (link2link2dir != null) Files.deleteIfExists(link2link2dir.toPath()); if (link2nobody != null) Files.deleteIfExists(link2nobody.toPath()); if (link2link2nobody != null) Files.deleteIfExists(link2link2nobody.toPath()); } /** * Creates a sym link source->target */ static void mklink(File source, File target) throws IOException { Files.createSymbolicLink(source.toPath(), target.toPath()); } /** * Returns true if the "link" exists and is a sym link. */ static boolean isSymLink(File link) { return Files.isSymbolicLink(link.toPath()); } /** * Returns the last modified time of a sym link. */ static long lastModifiedOfSymLink(File link) throws IOException { BasicFileAttributes attrs = Files.readAttributes(link.toPath(), BasicFileAttributes.class, NOFOLLOW_LINKS); assertTrue(attrs.isSymbolicLink()); return attrs.lastModifiedTime().toMillis(); } /** * Returns true if sym links are supported on the file system where * "dir" exists. */ static boolean supportsSymLinks(File dir) { Path link = dir.toPath().resolve("link"); Path target = dir.toPath().resolve("target"); try { Files.createSymbolicLink(link, target); Files.delete(link); return true; } catch (UnsupportedOperationException x) { return false; } catch (IOException x) { return false; } } static void assertTrue(boolean v) { if (!v) throw new RuntimeException("Test failed"); } static void assertFalse(boolean v) { assertTrue(!v); } static void header(String h) { out.println(); out.println(); out.println("-- " + h + " --"); } /** * Tests go here. */ static void go() throws IOException { // check setup assertTrue(file.isFile()); assertTrue(isSymLink(link2file)); assertTrue(isSymLink(link2link2file)); assertTrue(dir.isDirectory()); assertTrue(isSymLink(link2dir)); assertTrue(isSymLink(link2link2dir)); assertTrue(isSymLink(link2nobody)); assertTrue(isSymLink(link2link2nobody)); header("createNewFile"); assertFalse(file.createNewFile()); assertFalse(link2file.createNewFile()); assertFalse(link2link2file.createNewFile()); assertFalse(dir.createNewFile()); assertFalse(link2dir.createNewFile()); assertFalse(link2link2dir.createNewFile()); assertFalse(link2nobody.createNewFile()); assertFalse(link2link2nobody.createNewFile()); header("mkdir"); assertFalse(file.mkdir()); assertFalse(link2file.mkdir()); assertFalse(link2link2file.mkdir()); assertFalse(dir.mkdir()); assertFalse(link2dir.mkdir()); assertFalse(link2link2dir.mkdir()); assertFalse(link2nobody.mkdir()); assertFalse(link2link2nobody.mkdir()); header("delete"); File link = new File(top, "mylink"); try { mklink(link, file); assertTrue(link.delete()); assertTrue(!isSymLink(link)); assertTrue(file.exists()); mklink(link, link2file); assertTrue(link.delete()); assertTrue(!isSymLink(link)); assertTrue(link2file.exists()); mklink(link, dir); assertTrue(link.delete()); assertTrue(!isSymLink(link)); assertTrue(dir.exists()); mklink(link, link2dir); assertTrue(link.delete()); assertTrue(!isSymLink(link)); assertTrue(link2dir.exists()); mklink(link, link2nobody); assertTrue(link.delete()); assertTrue(!isSymLink(link)); assertTrue(isSymLink(link2nobody)); } finally { Files.deleteIfExists(link.toPath()); } header("renameTo"); File newlink = new File(top, "newlink"); assertTrue(link2file.renameTo(newlink)); try { assertTrue(file.exists()); assertTrue(isSymLink(newlink)); assertTrue(!isSymLink(link2file)); } finally { newlink.renameTo(link2file); // restore link } assertTrue(link2dir.renameTo(newlink)); try { assertTrue(dir.exists()); assertTrue(isSymLink(newlink)); assertTrue(!isSymLink(link2dir)); } finally { newlink.renameTo(link2dir); // restore link } header("list"); final String name = "entry"; File entry = new File(dir, name); try { assertTrue(dir.list().length == 0); // directory should be empty assertTrue(link2dir.list().length == 0); assertTrue(link2link2dir.list().length == 0); assertTrue(entry.createNewFile()); assertTrue(dir.list().length == 1); assertTrue(dir.list()[0].equals(name)); // access directory by following links assertTrue(link2dir.list().length == 1); assertTrue(link2dir.list()[0].equals(name)); assertTrue(link2link2dir.list().length == 1); assertTrue(link2link2dir.list()[0].equals(name)); // files that are not directories assertTrue(link2file.list() == null); assertTrue(link2nobody.list() == null); } finally { entry.delete(); } header("isXXX"); assertTrue(file.isFile()); assertTrue(link2file.isFile()); assertTrue(link2link2file.isFile()); assertTrue(dir.isDirectory()); assertTrue(link2dir.isDirectory()); assertTrue(link2link2dir.isDirectory()); // on Windows we test with the DOS hidden attribute set if (System.getProperty("os.name").startsWith("Windows")) { DosFileAttributeView view = Files .getFileAttributeView(file.toPath(), DosFileAttributeView.class); view.setHidden(true); try { assertTrue(file.isHidden()); assertTrue(link2file.isHidden()); assertTrue(link2link2file.isHidden()); } finally { view.setHidden(false); } assertFalse(file.isHidden()); assertFalse(link2file.isHidden()); assertFalse(link2link2file.isHidden()); } header("length"); long len = file.length(); assertTrue(len > 0L); // these tests should follow links assertTrue(link2file.length() == len); assertTrue(link2link2file.length() == len); assertTrue(link2nobody.length() == 0L); header("lastModified / setLastModified"); // need time to diff between link and file long origLastModified = file.lastModified(); assertTrue(origLastModified != 0L); try { Thread.sleep(2000); } catch (InterruptedException x) { } file.setLastModified(System.currentTimeMillis()); long lastModified = file.lastModified(); assertTrue(lastModified != origLastModified); assertTrue(lastModifiedOfSymLink(link2file) != lastModified); assertTrue(lastModifiedOfSymLink(link2link2file) != lastModified); assertTrue(link2file.lastModified() == lastModified); assertTrue(link2link2file.lastModified() == lastModified); assertTrue(link2nobody.lastModified() == 0L); origLastModified = dir.lastModified(); assertTrue(origLastModified != 0L); dir.setLastModified(0L); assertTrue(dir.lastModified() == 0L); assertTrue(link2dir.lastModified() == 0L); assertTrue(link2link2dir.lastModified() == 0L); dir.setLastModified(origLastModified); header("setXXX / canXXX"); assertTrue(file.canRead()); assertTrue(file.canWrite()); assertTrue(link2file.canRead()); assertTrue(link2file.canWrite()); assertTrue(link2link2file.canRead()); assertTrue(link2link2file.canWrite()); if (file.setReadOnly()) { assertFalse(file.canWrite()); assertFalse(link2file.canWrite()); assertFalse(link2link2file.canWrite()); assertTrue(file.setWritable(true)); // make writable assertTrue(file.canWrite()); assertTrue(link2file.canWrite()); assertTrue(link2link2file.canWrite()); assertTrue(link2file.setReadOnly()); // make read only assertFalse(file.canWrite()); assertFalse(link2file.canWrite()); assertFalse(link2link2file.canWrite()); assertTrue(link2link2file.setWritable(true)); // make writable assertTrue(file.canWrite()); assertTrue(link2file.canWrite()); assertTrue(link2link2file.canWrite()); } } public static void main(String[] args) throws IOException { if (supportsSymLinks(top)) { try { setup(); go(); } finally { cleanup(); } } } }