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