blob: 93859091c9be0c58b05b0f44f39dc16f5858ade4 [file] [log] [blame]
dfuchs26f473f2014-09-29 18:56:32 +02001/*
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 */
23import java.io.ByteArrayInputStream;
24import java.io.ByteArrayOutputStream;
25import java.io.File;
26import java.io.FilePermission;
27import java.io.IOException;
28import java.nio.channels.FileChannel;
29import java.nio.file.Files;
30import java.nio.file.Paths;
31import static java.nio.file.StandardOpenOption.CREATE_NEW;
32import static java.nio.file.StandardOpenOption.WRITE;
33import java.security.CodeSource;
34import java.security.Permission;
35import java.security.PermissionCollection;
36import java.security.Permissions;
37import java.security.Policy;
38import java.security.ProtectionDomain;
39import java.util.Arrays;
40import java.util.Collections;
41import java.util.Enumeration;
42import java.util.List;
43import java.util.Properties;
44import java.util.PropertyPermission;
45import java.util.UUID;
46import java.util.concurrent.atomic.AtomicBoolean;
47import java.util.logging.FileHandler;
48import java.util.logging.LogManager;
49import 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 */
60public 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}