1 /* 2 * Copyright (c) 2009, 2011, 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 */ 28 29 import java.io.*; 30 import java.nio.file.*; 31 import java.nio.file.attribute.*; 32 import static java.nio.file.LinkOption.*; 33 34 public class SymLinks { 35 final static PrintStream out = System.out; 36 37 final static File top = new File(System.getProperty("test.dir", ".")); 38 39 // files used by the test 40 41 final static File file = new File(top, "foofile"); 42 final static File link2file = new File(top, "link2file"); 43 final static File link2link2file = new File(top, "link2link2file"); 44 45 final static File dir = new File(top, "foodir"); 46 final static File link2dir = new File(top, "link2dir"); 47 final static File link2link2dir = new File(top, "link2link2dir"); 48 49 final static File link2nobody = new File(top, "link2nobody"); 50 final static File link2link2nobody = new File(top, "link2link2nobody"); 51 52 /** 53 * Setup files, directories, and sym links used by test. 54 */ 55 static void setup() throws IOException { 56 // link2link2file -> link2file -> foofile 57 FileOutputStream fos = new FileOutputStream(file); 58 try { 59 fos.write(new byte[16*1024]); 60 } finally { 61 fos.close(); 62 } 63 mklink(link2file, file); 64 mklink(link2link2file, link2file); 65 66 // link2link2dir -> link2dir -> dir 67 assertTrue(dir.mkdir()); 68 mklink(link2dir, dir); 69 mklink(link2link2dir, link2dir); 70 71 // link2link2nobody -> link2nobody -> <does-not-exist> 72 mklink(link2nobody, new File(top, "DoesNotExist")); 73 mklink(link2link2nobody, link2nobody); 74 } 75 76 /** 77 * Remove files, directories, and sym links used by test. 78 */ 79 static void cleanup() throws IOException { 80 if (file != null) 81 file.delete(); 82 if (link2file != null) 83 Files.deleteIfExists(link2file.toPath()); 84 if (link2link2file != null) 85 Files.deleteIfExists(link2link2file.toPath()); 86 if (dir != null) 87 dir.delete(); 88 if (link2dir != null) 89 Files.deleteIfExists(link2dir.toPath()); 90 if (link2link2dir != null) 91 Files.deleteIfExists(link2link2dir.toPath()); 92 if (link2nobody != null) 93 Files.deleteIfExists(link2nobody.toPath()); 94 if (link2link2nobody != null) 95 Files.deleteIfExists(link2link2nobody.toPath()); 96 } 97 98 /** 99 * Creates a sym link source->target 100 */ 101 static void mklink(File source, File target) throws IOException { 102 Files.createSymbolicLink(source.toPath(), target.toPath()); 103 } 104 105 /** 106 * Returns true if the "link" exists and is a sym link. 107 */ 108 static boolean isSymLink(File link) { 109 return Files.isSymbolicLink(link.toPath()); 110 } 111 112 /** 113 * Returns the last modified time of a sym link. 114 */ 115 static long lastModifiedOfSymLink(File link) throws IOException { 116 BasicFileAttributes attrs = 117 Files.readAttributes(link.toPath(), BasicFileAttributes.class, NOFOLLOW_LINKS); 118 assertTrue(attrs.isSymbolicLink()); 119 return attrs.lastModifiedTime().toMillis(); 120 } 121 122 /** 123 * Returns true if sym links are supported on the file system where 124 * "dir" exists. 125 */ 126 static boolean supportsSymLinks(File dir) { 127 Path link = dir.toPath().resolve("link"); 128 Path target = dir.toPath().resolve("target"); 129 try { 130 Files.createSymbolicLink(link, target); 131 Files.delete(link); 132 return true; 133 } catch (UnsupportedOperationException x) { 134 return false; 135 } catch (IOException x) { 136 return false; 137 } 138 } 139 140 static void assertTrue(boolean v) { 141 if (!v) throw new RuntimeException("Test failed"); 142 } 143 144 static void assertFalse(boolean v) { 145 assertTrue(!v); 146 } 147 148 static void header(String h) { 149 out.println(); 150 out.println(); 151 out.println("-- " + h + " --"); 152 } 153 154 /** 155 * Tests go here. 156 */ 157 static void go() throws IOException { 158 159 // check setup 160 assertTrue(file.isFile()); 161 assertTrue(isSymLink(link2file)); 162 assertTrue(isSymLink(link2link2file)); 163 assertTrue(dir.isDirectory()); 164 assertTrue(isSymLink(link2dir)); 165 assertTrue(isSymLink(link2link2dir)); 166 assertTrue(isSymLink(link2nobody)); 167 assertTrue(isSymLink(link2link2nobody)); 168 169 header("createNewFile"); 170 171 assertFalse(file.createNewFile()); 172 assertFalse(link2file.createNewFile()); 173 assertFalse(link2link2file.createNewFile()); 174 assertFalse(dir.createNewFile()); 175 assertFalse(link2dir.createNewFile()); 176 assertFalse(link2link2dir.createNewFile()); 177 assertFalse(link2nobody.createNewFile()); 178 assertFalse(link2link2nobody.createNewFile()); 179 180 header("mkdir"); 181 182 assertFalse(file.mkdir()); 183 assertFalse(link2file.mkdir()); 184 assertFalse(link2link2file.mkdir()); 185 assertFalse(dir.mkdir()); 186 assertFalse(link2dir.mkdir()); 187 assertFalse(link2link2dir.mkdir()); 188 assertFalse(link2nobody.mkdir()); 189 assertFalse(link2link2nobody.mkdir()); 190 191 header("delete"); 192 193 File link = new File(top, "mylink"); 194 try { 195 mklink(link, file); 196 assertTrue(link.delete()); 197 assertTrue(!isSymLink(link)); 198 assertTrue(file.exists()); 199 200 mklink(link, link2file); 201 assertTrue(link.delete()); 202 assertTrue(!isSymLink(link)); 203 assertTrue(link2file.exists()); 204 205 mklink(link, dir); 206 assertTrue(link.delete()); 207 assertTrue(!isSymLink(link)); 208 assertTrue(dir.exists()); 209 210 mklink(link, link2dir); 211 assertTrue(link.delete()); 212 assertTrue(!isSymLink(link)); 213 assertTrue(link2dir.exists()); 214 215 mklink(link, link2nobody); 216 assertTrue(link.delete()); 217 assertTrue(!isSymLink(link)); 218 assertTrue(isSymLink(link2nobody)); 219 220 } finally { 221 Files.deleteIfExists(link.toPath()); 222 } 223 224 header("renameTo"); 225 226 File newlink = new File(top, "newlink"); 227 assertTrue(link2file.renameTo(newlink)); 228 try { 229 assertTrue(file.exists()); 230 assertTrue(isSymLink(newlink)); 231 assertTrue(!isSymLink(link2file)); 232 } finally { 233 newlink.renameTo(link2file); // restore link 234 } 235 236 assertTrue(link2dir.renameTo(newlink)); 237 try { 238 assertTrue(dir.exists()); 239 assertTrue(isSymLink(newlink)); 240 assertTrue(!isSymLink(link2dir)); 241 } finally { 242 newlink.renameTo(link2dir); // restore link 243 } 244 245 header("list"); 246 247 final String name = "entry"; 248 File entry = new File(dir, name); 249 try { 250 assertTrue(dir.list().length == 0); // directory should be empty 251 assertTrue(link2dir.list().length == 0); 252 assertTrue(link2link2dir.list().length == 0); 253 254 assertTrue(entry.createNewFile()); 255 assertTrue(dir.list().length == 1); 256 assertTrue(dir.list()[0].equals(name)); 257 258 // access directory by following links 259 assertTrue(link2dir.list().length == 1); 260 assertTrue(link2dir.list()[0].equals(name)); 261 assertTrue(link2link2dir.list().length == 1); 262 assertTrue(link2link2dir.list()[0].equals(name)); 263 264 // files that are not directories 265 assertTrue(link2file.list() == null); 266 assertTrue(link2nobody.list() == null); 267 268 } finally { 269 entry.delete(); 270 } 271 272 header("isXXX"); 273 274 assertTrue(file.isFile()); 275 assertTrue(link2file.isFile()); 276 assertTrue(link2link2file.isFile()); 277 278 assertTrue(dir.isDirectory()); 279 assertTrue(link2dir.isDirectory()); 280 assertTrue(link2link2dir.isDirectory()); 281 282 // on Windows we test with the DOS hidden attribute set 283 if (System.getProperty("os.name").startsWith("Windows")) { 284 DosFileAttributeView view = Files 285 .getFileAttributeView(file.toPath(), DosFileAttributeView.class); 286 view.setHidden(true); 287 try { 288 assertTrue(file.isHidden()); 289 assertTrue(link2file.isHidden()); 290 assertTrue(link2link2file.isHidden()); 291 } finally { 292 view.setHidden(false); 293 } 294 assertFalse(file.isHidden()); 295 assertFalse(link2file.isHidden()); 296 assertFalse(link2link2file.isHidden()); 297 } 298 299 header("length"); 300 301 long len = file.length(); 302 assertTrue(len > 0L); 303 // these tests should follow links 304 assertTrue(link2file.length() == len); 305 assertTrue(link2link2file.length() == len); 306 assertTrue(link2nobody.length() == 0L); 307 308 header("lastModified / setLastModified"); 309 310 // need time to diff between link and file 311 long origLastModified = file.lastModified(); 312 assertTrue(origLastModified != 0L); 313 try { Thread.sleep(2000); } catch (InterruptedException x) { } 314 file.setLastModified(System.currentTimeMillis()); 315 316 long lastModified = file.lastModified(); 317 assertTrue(lastModified != origLastModified); 318 assertTrue(lastModifiedOfSymLink(link2file) != lastModified); 319 assertTrue(lastModifiedOfSymLink(link2link2file) != lastModified); 320 assertTrue(link2file.lastModified() == lastModified); 321 assertTrue(link2link2file.lastModified() == lastModified); 322 assertTrue(link2nobody.lastModified() == 0L); 323 324 origLastModified = dir.lastModified(); 325 assertTrue(origLastModified != 0L); 326 dir.setLastModified(0L); 327 assertTrue(dir.lastModified() == 0L); 328 assertTrue(link2dir.lastModified() == 0L); 329 assertTrue(link2link2dir.lastModified() == 0L); 330 dir.setLastModified(origLastModified); 331 332 header("setXXX / canXXX"); 333 334 assertTrue(file.canRead()); 335 assertTrue(file.canWrite()); 336 assertTrue(link2file.canRead()); 337 assertTrue(link2file.canWrite()); 338 assertTrue(link2link2file.canRead()); 339 assertTrue(link2link2file.canWrite()); 340 341 if (file.setReadOnly()) { 342 assertFalse(file.canWrite()); 343 assertFalse(link2file.canWrite()); 344 assertFalse(link2link2file.canWrite()); 345 346 assertTrue(file.setWritable(true)); // make writable 347 assertTrue(file.canWrite()); 348 assertTrue(link2file.canWrite()); 349 assertTrue(link2link2file.canWrite()); 350 351 assertTrue(link2file.setReadOnly()); // make read only 352 assertFalse(file.canWrite()); 353 assertFalse(link2file.canWrite()); 354 assertFalse(link2link2file.canWrite()); 355 356 assertTrue(link2link2file.setWritable(true)); // make writable 357 assertTrue(file.canWrite()); 358 assertTrue(link2file.canWrite()); 359 assertTrue(link2link2file.canWrite()); 360 } 361 } 362 363 public static void main(String[] args) throws IOException { 364 if (supportsSymLinks(top)) { 365 try { 366 setup(); 367 go(); 368 } finally { 369 cleanup(); 370 } 371 } 372 } 373 374 }