1575N/A/*
3909N/A * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
1575N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1575N/A *
1575N/A * This code is free software; you can redistribute it and/or modify it
1575N/A * under the terms of the GNU General Public License version 2 only, as
1575N/A * published by the Free Software Foundation.
1575N/A *
1575N/A * This code is distributed in the hope that it will be useful, but WITHOUT
1575N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1575N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1575N/A * version 2 for more details (a copy is included in the LICENSE file that
1575N/A * accompanied this code).
1575N/A *
1575N/A * You should have received a copy of the GNU General Public License version
1575N/A * 2 along with this work; if not, write to the Free Software Foundation,
1575N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1575N/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.
1575N/A */
1575N/A
1575N/A/* @test
1575N/A * @bug 6595866
1575N/A * @summary Test java.io.File operations with sym links
1575N/A */
1575N/A
1575N/Aimport java.io.*;
3471N/Aimport java.nio.file.*;
1575N/Aimport java.nio.file.attribute.*;
1575N/Aimport static java.nio.file.LinkOption.*;
1575N/A
1575N/Apublic class SymLinks {
1575N/A final static PrintStream out = System.out;
1575N/A
1575N/A final static File top = new File(System.getProperty("test.dir", "."));
1575N/A
1575N/A // files used by the test
1575N/A
1575N/A final static File file = new File(top, "foofile");
1575N/A final static File link2file = new File(top, "link2file");
1575N/A final static File link2link2file = new File(top, "link2link2file");
1575N/A
1575N/A final static File dir = new File(top, "foodir");
1575N/A final static File link2dir = new File(top, "link2dir");
1575N/A final static File link2link2dir = new File(top, "link2link2dir");
1575N/A
1575N/A final static File link2nobody = new File(top, "link2nobody");
1575N/A final static File link2link2nobody = new File(top, "link2link2nobody");
1575N/A
1575N/A /**
1575N/A * Setup files, directories, and sym links used by test.
1575N/A */
1575N/A static void setup() throws IOException {
1575N/A // link2link2file -> link2file -> foofile
1575N/A FileOutputStream fos = new FileOutputStream(file);
1575N/A try {
1575N/A fos.write(new byte[16*1024]);
1575N/A } finally {
1575N/A fos.close();
1575N/A }
1575N/A mklink(link2file, file);
1575N/A mklink(link2link2file, link2file);
1575N/A
1575N/A // link2link2dir -> link2dir -> dir
1575N/A assertTrue(dir.mkdir());
1575N/A mklink(link2dir, dir);
1575N/A mklink(link2link2dir, link2dir);
1575N/A
1575N/A // link2link2nobody -> link2nobody -> <does-not-exist>
1575N/A mklink(link2nobody, new File(top, "DoesNotExist"));
1575N/A mklink(link2link2nobody, link2nobody);
1575N/A }
1575N/A
1575N/A /**
1575N/A * Remove files, directories, and sym links used by test.
1575N/A */
1575N/A static void cleanup() throws IOException {
1575N/A if (file != null)
1575N/A file.delete();
1575N/A if (link2file != null)
3471N/A Files.deleteIfExists(link2file.toPath());
1575N/A if (link2link2file != null)
3471N/A Files.deleteIfExists(link2link2file.toPath());
1575N/A if (dir != null)
1575N/A dir.delete();
1575N/A if (link2dir != null)
3471N/A Files.deleteIfExists(link2dir.toPath());
1575N/A if (link2link2dir != null)
3471N/A Files.deleteIfExists(link2link2dir.toPath());
1575N/A if (link2nobody != null)
3471N/A Files.deleteIfExists(link2nobody.toPath());
1575N/A if (link2link2nobody != null)
3471N/A Files.deleteIfExists(link2link2nobody.toPath());
1575N/A }
1575N/A
1575N/A /**
1575N/A * Creates a sym link source->target
1575N/A */
1575N/A static void mklink(File source, File target) throws IOException {
3471N/A Files.createSymbolicLink(source.toPath(), target.toPath());
1575N/A }
1575N/A
1575N/A /**
1575N/A * Returns true if the "link" exists and is a sym link.
1575N/A */
1575N/A static boolean isSymLink(File link) {
3471N/A return Files.isSymbolicLink(link.toPath());
1575N/A }
1575N/A
1575N/A /**
1575N/A * Returns the last modified time of a sym link.
1575N/A */
1575N/A static long lastModifiedOfSymLink(File link) throws IOException {
1575N/A BasicFileAttributes attrs =
3471N/A Files.readAttributes(link.toPath(), BasicFileAttributes.class, NOFOLLOW_LINKS);
1575N/A assertTrue(attrs.isSymbolicLink());
1575N/A return attrs.lastModifiedTime().toMillis();
1575N/A }
1575N/A
1575N/A /**
1575N/A * Returns true if sym links are supported on the file system where
1575N/A * "dir" exists.
1575N/A */
1575N/A static boolean supportsSymLinks(File dir) {
1575N/A Path link = dir.toPath().resolve("link");
1575N/A Path target = dir.toPath().resolve("target");
1575N/A try {
3471N/A Files.createSymbolicLink(link, target);
3471N/A Files.delete(link);
1575N/A return true;
1575N/A } catch (UnsupportedOperationException x) {
1575N/A return false;
1575N/A } catch (IOException x) {
1575N/A return false;
1575N/A }
1575N/A }
1575N/A
1575N/A static void assertTrue(boolean v) {
1575N/A if (!v) throw new RuntimeException("Test failed");
1575N/A }
1575N/A
1575N/A static void assertFalse(boolean v) {
1575N/A assertTrue(!v);
1575N/A }
1575N/A
1575N/A static void header(String h) {
1575N/A out.println();
1575N/A out.println();
1575N/A out.println("-- " + h + " --");
1575N/A }
1575N/A
1575N/A /**
1575N/A * Tests go here.
1575N/A */
1575N/A static void go() throws IOException {
1575N/A
1575N/A // check setup
1575N/A assertTrue(file.isFile());
1575N/A assertTrue(isSymLink(link2file));
1575N/A assertTrue(isSymLink(link2link2file));
1575N/A assertTrue(dir.isDirectory());
1575N/A assertTrue(isSymLink(link2dir));
1575N/A assertTrue(isSymLink(link2link2dir));
1575N/A assertTrue(isSymLink(link2nobody));
1575N/A assertTrue(isSymLink(link2link2nobody));
1575N/A
1575N/A header("createNewFile");
1575N/A
1575N/A assertFalse(file.createNewFile());
1575N/A assertFalse(link2file.createNewFile());
1575N/A assertFalse(link2link2file.createNewFile());
1575N/A assertFalse(dir.createNewFile());
1575N/A assertFalse(link2dir.createNewFile());
1575N/A assertFalse(link2link2dir.createNewFile());
1575N/A assertFalse(link2nobody.createNewFile());
1575N/A assertFalse(link2link2nobody.createNewFile());
1575N/A
1575N/A header("mkdir");
1575N/A
1575N/A assertFalse(file.mkdir());
1575N/A assertFalse(link2file.mkdir());
1575N/A assertFalse(link2link2file.mkdir());
1575N/A assertFalse(dir.mkdir());
1575N/A assertFalse(link2dir.mkdir());
1575N/A assertFalse(link2link2dir.mkdir());
1575N/A assertFalse(link2nobody.mkdir());
1575N/A assertFalse(link2link2nobody.mkdir());
1575N/A
1575N/A header("delete");
1575N/A
1575N/A File link = new File(top, "mylink");
1575N/A try {
1575N/A mklink(link, file);
1575N/A assertTrue(link.delete());
1575N/A assertTrue(!isSymLink(link));
1575N/A assertTrue(file.exists());
1575N/A
1575N/A mklink(link, link2file);
1575N/A assertTrue(link.delete());
1575N/A assertTrue(!isSymLink(link));
1575N/A assertTrue(link2file.exists());
1575N/A
1575N/A mklink(link, dir);
1575N/A assertTrue(link.delete());
1575N/A assertTrue(!isSymLink(link));
1575N/A assertTrue(dir.exists());
1575N/A
1575N/A mklink(link, link2dir);
1575N/A assertTrue(link.delete());
1575N/A assertTrue(!isSymLink(link));
1575N/A assertTrue(link2dir.exists());
1575N/A
1575N/A mklink(link, link2nobody);
1575N/A assertTrue(link.delete());
1575N/A assertTrue(!isSymLink(link));
1575N/A assertTrue(isSymLink(link2nobody));
1575N/A
1575N/A } finally {
3471N/A Files.deleteIfExists(link.toPath());
1575N/A }
1575N/A
1575N/A header("renameTo");
1575N/A
1575N/A File newlink = new File(top, "newlink");
1575N/A assertTrue(link2file.renameTo(newlink));
1575N/A try {
1575N/A assertTrue(file.exists());
1575N/A assertTrue(isSymLink(newlink));
1575N/A assertTrue(!isSymLink(link2file));
1575N/A } finally {
1575N/A newlink.renameTo(link2file); // restore link
1575N/A }
1575N/A
1575N/A assertTrue(link2dir.renameTo(newlink));
1575N/A try {
1575N/A assertTrue(dir.exists());
1575N/A assertTrue(isSymLink(newlink));
1575N/A assertTrue(!isSymLink(link2dir));
1575N/A } finally {
1575N/A newlink.renameTo(link2dir); // restore link
1575N/A }
1575N/A
1575N/A header("list");
1575N/A
1575N/A final String name = "entry";
1575N/A File entry = new File(dir, name);
1575N/A try {
1575N/A assertTrue(dir.list().length == 0); // directory should be empty
1575N/A assertTrue(link2dir.list().length == 0);
1575N/A assertTrue(link2link2dir.list().length == 0);
1575N/A
1575N/A assertTrue(entry.createNewFile());
1575N/A assertTrue(dir.list().length == 1);
1575N/A assertTrue(dir.list()[0].equals(name));
1575N/A
1575N/A // access directory by following links
1575N/A assertTrue(link2dir.list().length == 1);
1575N/A assertTrue(link2dir.list()[0].equals(name));
1575N/A assertTrue(link2link2dir.list().length == 1);
1575N/A assertTrue(link2link2dir.list()[0].equals(name));
1575N/A
1575N/A // files that are not directories
1575N/A assertTrue(link2file.list() == null);
1575N/A assertTrue(link2nobody.list() == null);
1575N/A
1575N/A } finally {
1575N/A entry.delete();
1575N/A }
1575N/A
1575N/A header("isXXX");
1575N/A
1575N/A assertTrue(file.isFile());
1575N/A assertTrue(link2file.isFile());
1575N/A assertTrue(link2link2file.isFile());
1575N/A
1575N/A assertTrue(dir.isDirectory());
1575N/A assertTrue(link2dir.isDirectory());
1575N/A assertTrue(link2link2dir.isDirectory());
1575N/A
1575N/A // on Windows we test with the DOS hidden attribute set
1575N/A if (System.getProperty("os.name").startsWith("Windows")) {
3471N/A DosFileAttributeView view = Files
3471N/A .getFileAttributeView(file.toPath(), DosFileAttributeView.class);
1575N/A view.setHidden(true);
1575N/A try {
1575N/A assertTrue(file.isHidden());
1575N/A assertTrue(link2file.isHidden());
1575N/A assertTrue(link2link2file.isHidden());
1575N/A } finally {
1575N/A view.setHidden(false);
1575N/A }
1575N/A assertFalse(file.isHidden());
1575N/A assertFalse(link2file.isHidden());
1575N/A assertFalse(link2link2file.isHidden());
1575N/A }
1575N/A
1575N/A header("length");
1575N/A
1575N/A long len = file.length();
1575N/A assertTrue(len > 0L);
1575N/A // these tests should follow links
1575N/A assertTrue(link2file.length() == len);
1575N/A assertTrue(link2link2file.length() == len);
1575N/A assertTrue(link2nobody.length() == 0L);
1575N/A
1575N/A header("lastModified / setLastModified");
1575N/A
1575N/A // need time to diff between link and file
1575N/A long origLastModified = file.lastModified();
1575N/A assertTrue(origLastModified != 0L);
1575N/A try { Thread.sleep(2000); } catch (InterruptedException x) { }
1575N/A file.setLastModified(System.currentTimeMillis());
1575N/A
1575N/A long lastModified = file.lastModified();
1575N/A assertTrue(lastModified != origLastModified);
1575N/A assertTrue(lastModifiedOfSymLink(link2file) != lastModified);
1575N/A assertTrue(lastModifiedOfSymLink(link2link2file) != lastModified);
1575N/A assertTrue(link2file.lastModified() == lastModified);
1575N/A assertTrue(link2link2file.lastModified() == lastModified);
1575N/A assertTrue(link2nobody.lastModified() == 0L);
1575N/A
1575N/A origLastModified = dir.lastModified();
1575N/A assertTrue(origLastModified != 0L);
1575N/A dir.setLastModified(0L);
1575N/A assertTrue(dir.lastModified() == 0L);
1575N/A assertTrue(link2dir.lastModified() == 0L);
1575N/A assertTrue(link2link2dir.lastModified() == 0L);
1575N/A dir.setLastModified(origLastModified);
1575N/A
1575N/A header("setXXX / canXXX");
1575N/A
1575N/A assertTrue(file.canRead());
1575N/A assertTrue(file.canWrite());
1575N/A assertTrue(link2file.canRead());
1575N/A assertTrue(link2file.canWrite());
1575N/A assertTrue(link2link2file.canRead());
1575N/A assertTrue(link2link2file.canWrite());
1575N/A
1575N/A if (file.setReadOnly()) {
1575N/A assertFalse(file.canWrite());
1575N/A assertFalse(link2file.canWrite());
1575N/A assertFalse(link2link2file.canWrite());
1575N/A
1575N/A assertTrue(file.setWritable(true)); // make writable
1575N/A assertTrue(file.canWrite());
1575N/A assertTrue(link2file.canWrite());
1575N/A assertTrue(link2link2file.canWrite());
1575N/A
1575N/A assertTrue(link2file.setReadOnly()); // make read only
1575N/A assertFalse(file.canWrite());
1575N/A assertFalse(link2file.canWrite());
1575N/A assertFalse(link2link2file.canWrite());
1575N/A
1575N/A assertTrue(link2link2file.setWritable(true)); // make writable
1575N/A assertTrue(file.canWrite());
1575N/A assertTrue(link2file.canWrite());
1575N/A assertTrue(link2link2file.canWrite());
1575N/A }
1575N/A }
1575N/A
1575N/A public static void main(String[] args) throws IOException {
1575N/A if (supportsSymLinks(top)) {
1575N/A try {
1575N/A setup();
1575N/A go();
1575N/A } finally {
1575N/A cleanup();
1575N/A }
1575N/A }
1575N/A }
1575N/A
1575N/A}