1 /* 2 * Copyright (c) 2014, 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 import java.io.ByteArrayInputStream; 24 import java.io.ByteArrayOutputStream; 25 import java.io.File; 26 import java.io.FilePermission; 27 import java.io.IOException; 28 import java.nio.channels.FileChannel; 29 import java.nio.file.Files; 30 import java.nio.file.Paths; 31 import static java.nio.file.StandardOpenOption.CREATE_NEW; 32 import static java.nio.file.StandardOpenOption.WRITE; 33 import java.security.CodeSource; 34 import java.security.Permission; 35 import java.security.PermissionCollection; 36 import java.security.Permissions; 37 import java.security.Policy; 38 import java.security.ProtectionDomain; 39 import java.util.Arrays; 40 import java.util.Collections; 41 import java.util.Enumeration; 42 import java.util.List; 43 import java.util.Properties; 44 import java.util.PropertyPermission; 45 import java.util.UUID; 46 import java.util.concurrent.atomic.AtomicBoolean; 47 import java.util.logging.FileHandler; 48 import java.util.logging.LogManager; 49 import java.util.logging.LoggingPermission; 50 51 /** 52 * @test 53 * @bug 8059269 54 * @summary tests that using a simple (non composite) pattern does not lead 55 * to NPE when the lock file already exists. 56 * @run main/othervm FileHandlerPath UNSECURE 57 * @run main/othervm FileHandlerPath SECURE 58 * @author danielfuchs 59 */ 60 public class FileHandlerPath { 61 62 /** 63 * We will test the simple pattern in two configurations. 64 * UNSECURE: No security manager. 65 * SECURE: With the security manager present - and the required 66 * permissions granted. 67 */ 68 public static enum TestCase { 69 UNSECURE, SECURE; 70 public void run(Properties propertyFile) throws Exception { 71 System.out.println("Running test case: " + name()); 72 Configure.setUp(this, propertyFile); 73 test(this.name() + " " + propertyFile.getProperty("test.name"), propertyFile); 74 } 75 } 76 77 78 // Use a random name provided by UUID to avoid collision with other tests 79 final static String logFile = FileHandlerPath.class.getSimpleName() + "_" 80 + UUID.randomUUID().toString() + ".log"; 81 final static String tmpLogFile; 82 final static String userDir = System.getProperty("user.dir"); 83 final static String tmpDir = System.getProperty("java.io.tmpdir"); 84 private static final List<Properties> properties; 85 static { 86 tmpLogFile = new File(tmpDir, logFile).toString(); 87 Properties props1 = new Properties(); 88 Properties props2 = new Properties(); 89 props1.setProperty("test.name", "relative file"); 90 props1.setProperty("test.file.name", logFile); 91 props1.setProperty(FileHandler.class.getName() + ".pattern", logFile); 92 props1.setProperty(FileHandler.class.getName() + ".count", "1"); 93 props2.setProperty("test.name", "absoluste file"); 94 props2.setProperty("test.file.name", tmpLogFile); 95 props2.setProperty(FileHandler.class.getName() + ".pattern", "%t/" + logFile); 96 props2.setProperty(FileHandler.class.getName() + ".count", "1"); 97 properties = Collections.unmodifiableList(Arrays.asList( 98 props1, 99 props2)); 100 } 101 102 public static void main(String... args) throws Exception { 103 104 if (args == null || args.length == 0) { 105 args = new String[] { 106 TestCase.UNSECURE.name(), 107 TestCase.SECURE.name(), 108 }; 109 } 110 111 // Sanity checks 112 113 if (!Files.isWritable(Paths.get(userDir))) { 114 throw new RuntimeException(userDir + 115 ": user.dir is not writable - can't run test."); 116 } 117 if (!Files.isWritable(Paths.get(tmpDir))) { 118 throw new RuntimeException(tmpDir + 119 ": java.io.tmpdir is not writable - can't run test."); 120 } 121 122 File[] files = { 123 new File(logFile), 124 new File(tmpLogFile), 125 new File(logFile+".1"), 126 new File(tmpLogFile+".1"), 127 new File(logFile+".lck"), 128 new File(tmpLogFile+".lck"), 129 new File(logFile+".1.lck"), 130 new File(tmpLogFile+".1.lck") 131 }; 132 133 for (File log : files) { 134 if (log.exists()) { 135 throw new Exception(log +": file already exists - can't run test."); 136 } 137 } 138 139 // Now start the real test 140 141 try { 142 for (String testName : args) { 143 for (Properties propertyFile : properties) { 144 TestCase test = TestCase.valueOf(testName); 145 test.run(propertyFile); 146 } 147 } 148 } finally { 149 // Cleanup... 150 Configure.doPrivileged(() -> { 151 for(File log : files) { 152 try { 153 final boolean isLockFile = log.getName().endsWith(".lck"); 154 // lock file should already be deleted, except if the 155 // test failed in exception. 156 // log file should all be present, except if the test 157 // failed in exception. 158 if (log.exists()) { 159 if (!isLockFile) { 160 System.out.println("deleting "+log.toString()); 161 } else { 162 System.err.println("deleting lock file "+log.toString()); 163 } 164 log.delete(); 165 } else { 166 if (!isLockFile) { 167 System.err.println(log.toString() + ": not found."); 168 } 169 } 170 } catch (Throwable t) { 171 // should not happen 172 t.printStackTrace(); 173 } 174 } 175 }); 176 } 177 } 178 179 static class Configure { 180 static Policy policy = null; 181 static final AtomicBoolean allowAll = new AtomicBoolean(false); 182 static void setUp(TestCase test, Properties propertyFile) { 183 switch (test) { 184 case SECURE: 185 if (policy == null && System.getSecurityManager() != null) { 186 throw new IllegalStateException("SecurityManager already set"); 187 } else if (policy == null) { 188 policy = new SimplePolicy(TestCase.SECURE, allowAll); 189 Policy.setPolicy(policy); 190 System.setSecurityManager(new SecurityManager()); 191 } 192 if (System.getSecurityManager() == null) { 193 throw new IllegalStateException("No SecurityManager."); 194 } 195 if (policy == null) { 196 throw new IllegalStateException("policy not configured"); 197 } 198 break; 199 case UNSECURE: 200 if (System.getSecurityManager() != null) { 201 throw new IllegalStateException("SecurityManager already set"); 202 } 203 break; 204 default: 205 new InternalError("No such testcase: " + test); 206 } 207 doPrivileged(() -> { 208 try { 209 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 210 propertyFile.store(bytes, propertyFile.getProperty("test.name")); 211 ByteArrayInputStream bais = new ByteArrayInputStream(bytes.toByteArray()); 212 LogManager.getLogManager().readConfiguration(bais); 213 } catch (IOException ex) { 214 throw new RuntimeException(ex); 215 } 216 }); 217 } 218 static void doPrivileged(Runnable run) { 219 allowAll.set(true); 220 try { 221 run.run(); 222 } finally { 223 allowAll.set(false); 224 } 225 } 226 } 227 228 public static void test(String name, Properties props) throws Exception { 229 System.out.println("Testing: " + name); 230 String file = props.getProperty("test.file.name"); 231 // create the lock files first - in order to take the path that 232 // used to trigger the NPE 233 Files.createFile(Paths.get(file + ".lck")); 234 Files.createFile(Paths.get(file + ".1.lck")); 235 final FileHandler f1 = new FileHandler(); 236 final FileHandler f2 = new FileHandler(); 237 f1.close(); 238 f2.close(); 239 System.out.println("Success for " + name); 240 } 241 242 243 final static class PermissionsBuilder { 244 final Permissions perms; 245 public PermissionsBuilder() { 246 this(new Permissions()); 247 } 248 public PermissionsBuilder(Permissions perms) { 249 this.perms = perms; 250 } 251 public PermissionsBuilder add(Permission p) { 252 perms.add(p); 253 return this; 254 } 255 public PermissionsBuilder addAll(PermissionCollection col) { 256 if (col != null) { 257 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) { 258 perms.add(e.nextElement()); 259 } 260 } 261 return this; 262 } 263 public Permissions toPermissions() { 264 final PermissionsBuilder builder = new PermissionsBuilder(); 265 builder.addAll(perms); 266 return builder.perms; 267 } 268 } 269 270 public static class SimplePolicy extends Policy { 271 272 final Permissions permissions; 273 final Permissions allPermissions; 274 final AtomicBoolean allowAll; 275 public SimplePolicy(TestCase test, AtomicBoolean allowAll) { 276 this.allowAll = allowAll; 277 permissions = new Permissions(); 278 permissions.add(new LoggingPermission("control", null)); // needed by new FileHandler() 279 permissions.add(new FilePermission("<<ALL FILES>>", "read")); // needed by new FileHandler() 280 permissions.add(new FilePermission(logFile, "write,delete")); // needed by new FileHandler() 281 permissions.add(new FilePermission(logFile+".lck", "write,delete")); // needed by FileHandler.close() 282 permissions.add(new FilePermission(logFile+".1", "write,delete")); // needed by new FileHandler() 283 permissions.add(new FilePermission(logFile+".1.lck", "write,delete")); // needed by FileHandler.close() 284 permissions.add(new FilePermission(tmpLogFile, "write,delete")); // needed by new FileHandler() 285 permissions.add(new FilePermission(tmpLogFile+".lck", "write,delete")); // needed by FileHandler.close() 286 permissions.add(new FilePermission(tmpLogFile+".1", "write,delete")); // needed by new FileHandler() 287 permissions.add(new FilePermission(tmpLogFile+".1.lck", "write,delete")); // needed by FileHandler.close() 288 permissions.add(new FilePermission(userDir, "write")); // needed by new FileHandler() 289 permissions.add(new FilePermission(tmpDir, "write")); // needed by new FileHandler() 290 permissions.add(new PropertyPermission("user.dir", "read")); 291 permissions.add(new PropertyPermission("java.io.tmpdir", "read")); 292 allPermissions = new Permissions(); 293 allPermissions.add(new java.security.AllPermission()); 294 } 295 296 @Override 297 public boolean implies(ProtectionDomain domain, Permission permission) { 298 if (allowAll.get()) return allPermissions.implies(permission); 299 return permissions.implies(permission); 300 } 301 302 @Override 303 public PermissionCollection getPermissions(CodeSource codesource) { 304 return new PermissionsBuilder().addAll(allowAll.get() 305 ? allPermissions : permissions).toPermissions(); 306 } 307 308 @Override 309 public PermissionCollection getPermissions(ProtectionDomain domain) { 310 return new PermissionsBuilder().addAll(allowAll.get() 311 ? allPermissions : permissions).toPermissions(); 312 } 313 } 314 315 }