1 /* 2 * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any 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.Path; 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 link2file.toPath().deleteIfExists(); 84 if (link2link2file != null) 85 link2link2file.toPath().deleteIfExists(); 86 if (dir != null) 87 dir.delete(); 88 if (link2dir != null) 89 link2dir.toPath().deleteIfExists(); 90 if (link2link2dir != null) 91 link2link2dir.toPath().deleteIfExists(); 92 if (link2nobody != null) 93 link2nobody.toPath().deleteIfExists(); 94 if (link2link2nobody != null) 95 link2link2nobody.toPath().deleteIfExists(); 96 } 97 98 /** 99 * Creates a sym link source->target 100 */ 101 static void mklink(File source, File target) throws IOException { 102 source.toPath().createSymbolicLink(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 try { 110 BasicFileAttributes attrs = 111 Attributes.readBasicFileAttributes(link.toPath(), NOFOLLOW_LINKS); 112 return attrs.isSymbolicLink(); 113 } catch (IOException x) { 114 return false; 115 } 116 } 117 118 /** 119 * Returns the last modified time of a sym link. 120 */ 121 static long lastModifiedOfSymLink(File link) throws IOException { 122 BasicFileAttributes attrs = 123 Attributes.readBasicFileAttributes(link.toPath(), NOFOLLOW_LINKS); 124 assertTrue(attrs.isSymbolicLink()); 125 return attrs.lastModifiedTime().toMillis(); 126 } 127 128 /** 129 * Returns true if sym links are supported on the file system where 130 * "dir" exists. 131 */ 132 static boolean supportsSymLinks(File dir) { 133 Path link = dir.toPath().resolve("link"); 134 Path target = dir.toPath().resolve("target"); 135 try { 136 link.createSymbolicLink(target); 137 link.delete(); 138 return true; 139 } catch (UnsupportedOperationException x) { 140 return false; 141 } catch (IOException x) { 142 return false; 143 } 144 } 145 146 static void assertTrue(boolean v) { 147 if (!v) throw new RuntimeException("Test failed"); 148 } 149 150 static void assertFalse(boolean v) { 151 assertTrue(!v); 152 } 153 154 static void header(String h) { 155 out.println(); 156 out.println(); 157 out.println("-- " + h + " --"); 158 } 159 160 /** 161 * Tests go here. 162 */ 163 static void go() throws IOException { 164 165 // check setup 166 assertTrue(file.isFile()); 167 assertTrue(isSymLink(link2file)); 168 assertTrue(isSymLink(link2link2file)); 169 assertTrue(dir.isDirectory()); 170 assertTrue(isSymLink(link2dir)); 171 assertTrue(isSymLink(link2link2dir)); 172 assertTrue(isSymLink(link2nobody)); 173 assertTrue(isSymLink(link2link2nobody)); 174 175 header("createNewFile"); 176 177 assertFalse(file.createNewFile()); 178 assertFalse(link2file.createNewFile()); 179 assertFalse(link2link2file.createNewFile()); 180 assertFalse(dir.createNewFile()); 181 assertFalse(link2dir.createNewFile()); 182 assertFalse(link2link2dir.createNewFile()); 183 assertFalse(link2nobody.createNewFile()); 184 assertFalse(link2link2nobody.createNewFile()); 185 186 header("mkdir"); 187 188 assertFalse(file.mkdir()); 189 assertFalse(link2file.mkdir()); 190 assertFalse(link2link2file.mkdir()); 191 assertFalse(dir.mkdir()); 192 assertFalse(link2dir.mkdir()); 193 assertFalse(link2link2dir.mkdir()); 194 assertFalse(link2nobody.mkdir()); 195 assertFalse(link2link2nobody.mkdir()); 196 197 header("delete"); 198 199 File link = new File(top, "mylink"); 200 try { 201 mklink(link, file); 202 assertTrue(link.delete()); 203 assertTrue(!isSymLink(link)); 204 assertTrue(file.exists()); 205 206 mklink(link, link2file); 207 assertTrue(link.delete()); 208 assertTrue(!isSymLink(link)); 209 assertTrue(link2file.exists()); 210 211 mklink(link, dir); 212 assertTrue(link.delete()); 213 assertTrue(!isSymLink(link)); 214 assertTrue(dir.exists()); 215 216 mklink(link, link2dir); 217 assertTrue(link.delete()); 218 assertTrue(!isSymLink(link)); 219 assertTrue(link2dir.exists()); 220 221 mklink(link, link2nobody); 222 assertTrue(link.delete()); 223 assertTrue(!isSymLink(link)); 224 assertTrue(isSymLink(link2nobody)); 225 226 } finally { 227 link.toPath().deleteIfExists(); 228 } 229 230 header("renameTo"); 231 232 File newlink = new File(top, "newlink"); 233 assertTrue(link2file.renameTo(newlink)); 234 try { 235 assertTrue(file.exists()); 236 assertTrue(isSymLink(newlink)); 237 assertTrue(!isSymLink(link2file)); 238 } finally { 239 newlink.renameTo(link2file); // restore link 240 } 241 242 assertTrue(link2dir.renameTo(newlink)); 243 try { 244 assertTrue(dir.exists()); 245 assertTrue(isSymLink(newlink)); 246 assertTrue(!isSymLink(link2dir)); 247 } finally { 248 newlink.renameTo(link2dir); // restore link 249 } 250 251 header("list"); 252 253 final String name = "entry"; 254 File entry = new File(dir, name); 255 try { 256 assertTrue(dir.list().length == 0); // directory should be empty 257 assertTrue(link2dir.list().length == 0); 258 assertTrue(link2link2dir.list().length == 0); 259 260 assertTrue(entry.createNewFile()); 261 assertTrue(dir.list().length == 1); 262 assertTrue(dir.list()[0].equals(name)); 263 264 // access directory by following links 265 assertTrue(link2dir.list().length == 1); 266 assertTrue(link2dir.list()[0].equals(name)); 267 assertTrue(link2link2dir.list().length == 1); 268 assertTrue(link2link2dir.list()[0].equals(name)); 269 270 // files that are not directories 271 assertTrue(link2file.list() == null); 272 assertTrue(link2nobody.list() == null); 273 274 } finally { 275 entry.delete(); 276 } 277 278 header("isXXX"); 279 280 assertTrue(file.isFile()); 281 assertTrue(link2file.isFile()); 282 assertTrue(link2link2file.isFile()); 283 284 assertTrue(dir.isDirectory()); 285 assertTrue(link2dir.isDirectory()); 286 assertTrue(link2link2dir.isDirectory()); 287 288 // on Windows we test with the DOS hidden attribute set 289 if (System.getProperty("os.name").startsWith("Windows")) { 290 DosFileAttributeView view = file.toPath() 291 .getFileAttributeView(DosFileAttributeView.class); 292 view.setHidden(true); 293 try { 294 assertTrue(file.isHidden()); 295 assertTrue(link2file.isHidden()); 296 assertTrue(link2link2file.isHidden()); 297 } finally { 298 view.setHidden(false); 299 } 300 assertFalse(file.isHidden()); 301 assertFalse(link2file.isHidden()); 302 assertFalse(link2link2file.isHidden()); 303 } 304 305 header("length"); 306 307 long len = file.length(); 308 assertTrue(len > 0L); 309 // these tests should follow links 310 assertTrue(link2file.length() == len); 311 assertTrue(link2link2file.length() == len); 312 assertTrue(link2nobody.length() == 0L); 313 314 header("lastModified / setLastModified"); 315 316 // need time to diff between link and file 317 long origLastModified = file.lastModified(); 318 assertTrue(origLastModified != 0L); 319 try { Thread.sleep(2000); } catch (InterruptedException x) { } 320 file.setLastModified(System.currentTimeMillis()); 321 322 long lastModified = file.lastModified(); 323 assertTrue(lastModified != origLastModified); 324 assertTrue(lastModifiedOfSymLink(link2file) != lastModified); 325 assertTrue(lastModifiedOfSymLink(link2link2file) != lastModified); 326 assertTrue(link2file.lastModified() == lastModified); 327 assertTrue(link2link2file.lastModified() == lastModified); 328 assertTrue(link2nobody.lastModified() == 0L); 329 330 origLastModified = dir.lastModified(); 331 assertTrue(origLastModified != 0L); 332 dir.setLastModified(0L); 333 assertTrue(dir.lastModified() == 0L); 334 assertTrue(link2dir.lastModified() == 0L); 335 assertTrue(link2link2dir.lastModified() == 0L); 336 dir.setLastModified(origLastModified); 337 338 header("setXXX / canXXX"); 339 340 assertTrue(file.canRead()); 341 assertTrue(file.canWrite()); 342 assertTrue(link2file.canRead()); 343 assertTrue(link2file.canWrite()); 344 assertTrue(link2link2file.canRead()); 345 assertTrue(link2link2file.canWrite()); 346 347 if (file.setReadOnly()) { 348 assertFalse(file.canWrite()); 349 assertFalse(link2file.canWrite()); 350 assertFalse(link2link2file.canWrite()); 351 352 assertTrue(file.setWritable(true)); // make writable 353 assertTrue(file.canWrite()); 354 assertTrue(link2file.canWrite()); 355 assertTrue(link2link2file.canWrite()); 356 357 assertTrue(link2file.setReadOnly()); // make read only 358 assertFalse(file.canWrite()); 359 assertFalse(link2file.canWrite()); 360 assertFalse(link2link2file.canWrite()); 361 362 assertTrue(link2link2file.setWritable(true)); // make writable 363 assertTrue(file.canWrite()); 364 assertTrue(link2file.canWrite()); 365 assertTrue(link2link2file.canWrite()); 366 } 367 } 368 369 public static void main(String[] args) throws IOException { 370 if (supportsSymLinks(top)) { 371 try { 372 setup(); 373 go(); 374 } finally { 375 cleanup(); 376 } 377 } 378 } 379 380 }