1/* 2 * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* @test 25 * @bug 6595866 26 * @summary Test java.io.File operations with sym links 27 * @build SymLinks Util 28 * @run main SymLinks 29 */ 30 31import java.io.*; 32import java.nio.file.*; 33import java.nio.file.attribute.*; 34import static java.nio.file.LinkOption.*; 35 36public class SymLinks { 37 static final PrintStream out = System.out; 38 39 static final File top = new File(System.getProperty("test.dir", ".")); 40 41 // files used by the test 42 43 static final File file = new File(top, "foofile"); 44 static final File link2file = new File(top, "link2file"); 45 static final File link2link2file = new File(top, "link2link2file"); 46 47 static final File dir = new File(top, "foodir"); 48 static final File link2dir = new File(top, "link2dir"); 49 static final File link2link2dir = new File(top, "link2link2dir"); 50 51 static final File link2nobody = new File(top, "link2nobody"); 52 static final File link2link2nobody = new File(top, "link2link2nobody"); 53 54 /** 55 * Setup files, directories, and sym links used by test. 56 */ 57 static void setup() throws IOException { 58 // link2link2file -> link2file -> foofile 59 FileOutputStream fos = new FileOutputStream(file); 60 try { 61 fos.write(new byte[16*1024]); 62 } finally { 63 fos.close(); 64 } 65 mklink(link2file, file); 66 mklink(link2link2file, link2file); 67 68 // link2link2dir -> link2dir -> dir 69 assertTrue(dir.mkdir()); 70 mklink(link2dir, dir); 71 mklink(link2link2dir, link2dir); 72 73 // link2link2nobody -> link2nobody -> <does-not-exist> 74 mklink(link2nobody, new File(top, "DoesNotExist")); 75 mklink(link2link2nobody, link2nobody); 76 } 77 78 /** 79 * Remove files, directories, and sym links used by test. 80 */ 81 static void cleanup() throws IOException { 82 if (file != null) 83 file.delete(); 84 if (link2file != null) 85 Files.deleteIfExists(link2file.toPath()); 86 if (link2link2file != null) 87 Files.deleteIfExists(link2link2file.toPath()); 88 if (dir != null) 89 dir.delete(); 90 if (link2dir != null) 91 Files.deleteIfExists(link2dir.toPath()); 92 if (link2link2dir != null) 93 Files.deleteIfExists(link2link2dir.toPath()); 94 if (link2nobody != null) 95 Files.deleteIfExists(link2nobody.toPath()); 96 if (link2link2nobody != null) 97 Files.deleteIfExists(link2link2nobody.toPath()); 98 } 99 100 /** 101 * Creates a sym link source->target 102 */ 103 static void mklink(File source, File target) throws IOException { 104 Files.createSymbolicLink(source.toPath(), target.toPath()); 105 } 106 107 /** 108 * Returns true if the "link" exists and is a sym link. 109 */ 110 static boolean isSymLink(File link) { 111 return Files.isSymbolicLink(link.toPath()); 112 } 113 114 /** 115 * Returns the last modified time of a sym link. 116 */ 117 static long lastModifiedOfSymLink(File link) throws IOException { 118 BasicFileAttributes attrs = 119 Files.readAttributes(link.toPath(), BasicFileAttributes.class, NOFOLLOW_LINKS); 120 assertTrue(attrs.isSymbolicLink()); 121 return attrs.lastModifiedTime().toMillis(); 122 } 123 124 /** 125 * Returns true if sym links are supported on the file system where 126 * "dir" exists. 127 */ 128 static boolean supportsSymLinks(File dir) { 129 Path link = dir.toPath().resolve("link"); 130 Path target = dir.toPath().resolve("target"); 131 try { 132 Files.createSymbolicLink(link, target); 133 Files.delete(link); 134 return true; 135 } catch (UnsupportedOperationException x) { 136 return false; 137 } catch (IOException x) { 138 return false; 139 } 140 } 141 142 static void assertTrue(boolean v) { 143 if (!v) throw new RuntimeException("Test failed"); 144 } 145 146 static void assertFalse(boolean v) { 147 assertTrue(!v); 148 } 149 150 static void header(String h) { 151 out.println(); 152 out.println(); 153 out.println("-- " + h + " --"); 154 } 155 156 /** 157 * Tests go here. 158 */ 159 static void go() throws IOException { 160 161 // check setup 162 assertTrue(file.isFile()); 163 assertTrue(isSymLink(link2file)); 164 assertTrue(isSymLink(link2link2file)); 165 assertTrue(dir.isDirectory()); 166 assertTrue(isSymLink(link2dir)); 167 assertTrue(isSymLink(link2link2dir)); 168 assertTrue(isSymLink(link2nobody)); 169 assertTrue(isSymLink(link2link2nobody)); 170 171 header("createNewFile"); 172 173 assertFalse(file.createNewFile()); 174 assertFalse(link2file.createNewFile()); 175 assertFalse(link2link2file.createNewFile()); 176 assertFalse(dir.createNewFile()); 177 assertFalse(link2dir.createNewFile()); 178 assertFalse(link2link2dir.createNewFile()); 179 assertFalse(link2nobody.createNewFile()); 180 assertFalse(link2link2nobody.createNewFile()); 181 182 header("mkdir"); 183 184 assertFalse(file.mkdir()); 185 assertFalse(link2file.mkdir()); 186 assertFalse(link2link2file.mkdir()); 187 assertFalse(dir.mkdir()); 188 assertFalse(link2dir.mkdir()); 189 assertFalse(link2link2dir.mkdir()); 190 assertFalse(link2nobody.mkdir()); 191 assertFalse(link2link2nobody.mkdir()); 192 193 header("delete"); 194 195 File link = new File(top, "mylink"); 196 try { 197 mklink(link, file); 198 assertTrue(link.delete()); 199 assertTrue(!isSymLink(link)); 200 assertTrue(file.exists()); 201 202 mklink(link, link2file); 203 assertTrue(link.delete()); 204 assertTrue(!isSymLink(link)); 205 assertTrue(link2file.exists()); 206 207 mklink(link, dir); 208 assertTrue(link.delete()); 209 assertTrue(!isSymLink(link)); 210 assertTrue(dir.exists()); 211 212 mklink(link, link2dir); 213 assertTrue(link.delete()); 214 assertTrue(!isSymLink(link)); 215 assertTrue(link2dir.exists()); 216 217 mklink(link, link2nobody); 218 assertTrue(link.delete()); 219 assertTrue(!isSymLink(link)); 220 assertTrue(isSymLink(link2nobody)); 221 222 } finally { 223 Files.deleteIfExists(link.toPath()); 224 } 225 226 header("renameTo"); 227 228 File newlink = new File(top, "newlink"); 229 assertTrue(link2file.renameTo(newlink)); 230 try { 231 assertTrue(file.exists()); 232 assertTrue(isSymLink(newlink)); 233 assertTrue(!isSymLink(link2file)); 234 } finally { 235 newlink.renameTo(link2file); // restore link 236 } 237 238 assertTrue(link2dir.renameTo(newlink)); 239 try { 240 assertTrue(dir.exists()); 241 assertTrue(isSymLink(newlink)); 242 assertTrue(!isSymLink(link2dir)); 243 } finally { 244 newlink.renameTo(link2dir); // restore link 245 } 246 247 header("list"); 248 249 final String name = "entry"; 250 File entry = new File(dir, name); 251 try { 252 assertTrue(dir.list().length == 0); // directory should be empty 253 assertTrue(link2dir.list().length == 0); 254 assertTrue(link2link2dir.list().length == 0); 255 256 assertTrue(entry.createNewFile()); 257 assertTrue(dir.list().length == 1); 258 assertTrue(dir.list()[0].equals(name)); 259 260 // access directory by following links 261 assertTrue(link2dir.list().length == 1); 262 assertTrue(link2dir.list()[0].equals(name)); 263 assertTrue(link2link2dir.list().length == 1); 264 assertTrue(link2link2dir.list()[0].equals(name)); 265 266 // files that are not directories 267 assertTrue(link2file.list() == null); 268 assertTrue(link2nobody.list() == null); 269 270 } finally { 271 entry.delete(); 272 } 273 274 header("isXXX"); 275 276 assertTrue(file.isFile()); 277 assertTrue(link2file.isFile()); 278 assertTrue(link2link2file.isFile()); 279 280 assertTrue(dir.isDirectory()); 281 assertTrue(link2dir.isDirectory()); 282 assertTrue(link2link2dir.isDirectory()); 283 284 // on Windows we test with the DOS hidden attribute set 285 if (System.getProperty("os.name").startsWith("Windows")) { 286 DosFileAttributeView view = Files 287 .getFileAttributeView(file.toPath(), DosFileAttributeView.class); 288 view.setHidden(true); 289 try { 290 assertTrue(file.isHidden()); 291 assertTrue(link2file.isHidden()); 292 assertTrue(link2link2file.isHidden()); 293 } finally { 294 view.setHidden(false); 295 } 296 assertFalse(file.isHidden()); 297 assertFalse(link2file.isHidden()); 298 assertFalse(link2link2file.isHidden()); 299 } 300 301 header("length"); 302 303 long len = file.length(); 304 assertTrue(len > 0L); 305 // these tests should follow links 306 assertTrue(link2file.length() == len); 307 assertTrue(link2link2file.length() == len); 308 assertTrue(link2nobody.length() == 0L); 309 310 header("lastModified / setLastModified"); 311 312 // need time to diff between link and file 313 long origLastModified = file.lastModified(); 314 assertTrue(origLastModified != 0L); 315 try { Thread.sleep(2000); } catch (InterruptedException x) { } 316 file.setLastModified(System.currentTimeMillis()); 317 318 long lastModified = file.lastModified(); 319 assertTrue(lastModified != origLastModified); 320 assertTrue(lastModifiedOfSymLink(link2file) != lastModified); 321 assertTrue(lastModifiedOfSymLink(link2link2file) != lastModified); 322 assertTrue(link2file.lastModified() == lastModified); 323 assertTrue(link2link2file.lastModified() == lastModified); 324 assertTrue(link2nobody.lastModified() == 0L); 325 326 origLastModified = dir.lastModified(); 327 assertTrue(origLastModified != 0L); 328 dir.setLastModified(0L); 329 assertTrue(dir.lastModified() == 0L); 330 assertTrue(link2dir.lastModified() == 0L); 331 assertTrue(link2link2dir.lastModified() == 0L); 332 dir.setLastModified(origLastModified); 333 334 header("setXXX / canXXX"); 335 336 assertTrue(file.canRead()); 337 assertTrue(file.canWrite()); 338 assertTrue(link2file.canRead()); 339 assertTrue(link2file.canWrite()); 340 assertTrue(link2link2file.canRead()); 341 assertTrue(link2link2file.canWrite()); 342 343 if (!Util.isPrivileged() && file.setReadOnly()) { 344 assertFalse(file.canWrite()); 345 assertFalse(link2file.canWrite()); 346 assertFalse(link2link2file.canWrite()); 347 348 assertTrue(file.setWritable(true)); // make writable 349 assertTrue(file.canWrite()); 350 assertTrue(link2file.canWrite()); 351 assertTrue(link2link2file.canWrite()); 352 353 assertTrue(link2file.setReadOnly()); // make read only 354 assertFalse(file.canWrite()); 355 assertFalse(link2file.canWrite()); 356 assertFalse(link2link2file.canWrite()); 357 358 assertTrue(link2link2file.setWritable(true)); // make writable 359 assertTrue(file.canWrite()); 360 assertTrue(link2file.canWrite()); 361 assertTrue(link2link2file.canWrite()); 362 } 363 } 364 365 public static void main(String[] args) throws IOException { 366 if (supportsSymLinks(top)) { 367 try { 368 setup(); 369 go(); 370 } finally { 371 cleanup(); 372 } 373 } 374 } 375 376} 377