1 /*
2  * Copyright (c) 2012, 2013, 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 /*
25  * @test
26  * @bug     6244047
27  * @author Jim Gish
28  * @summary throw more precise IOException when pattern specifies invalid directory
29  *
30  * @run  main/othervm CheckLockLocationTest
31  */
32 import java.io.File;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 import java.io.OutputStream;
36 import java.nio.file.AccessDeniedException;
37 import java.nio.file.FileSystemException;
38 import java.nio.file.Files;
39 import java.nio.file.NoSuchFileException;
40 import java.nio.file.Path;
41 import java.nio.file.attribute.UserPrincipal;
42 import java.util.UUID;
43 import java.util.logging.FileHandler;
44 public class CheckLockLocationTest {
45 
46     private static final String NON_WRITABLE_DIR = "non-writable-dir";
47     private static final String NOT_A_DIR = "not-a-dir";
48     private static final String WRITABLE_DIR = "writable-dir";
49     private static final String NON_EXISTENT_DIR = "non-existent-dir";
50     private static boolean runNonWritableDirTest;
51 
main(String... args)52     public static void main(String... args) throws IOException {
53         // we'll base all file creation attempts on the system temp directory,
54         // %t and also try specifying non-existent directories and plain files
55         // that should be directories, and non-writable directories,
56         // to exercise all code paths of checking the lock location
57         // Note that on platforms like Windows that don't support
58         // setWritable() on a directory, we'll skip the non-writable
59         // directory test if setWritable(false) returns false.
60         //
61         File writableDir = setup();
62         // we now have three files/directories to work with:
63         //    writableDir
64         //    notAdir
65         //    nonWritableDir (may not be possible on some platforms)
66         //    nonExistentDir (which doesn't exist)
67         runTests(writableDir);
68     }
69 
70     /**
71      * @param writableDir in which log and lock file are created
72      * @throws SecurityException
73      * @throws RuntimeException
74      * @throws IOException
75      */
runTests(File writableDir)76     private static void runTests(File writableDir) throws SecurityException,
77             RuntimeException, IOException {
78         // Test 1: make sure we can create FileHandler in writable directory
79         try {
80             new FileHandler("%t/" + WRITABLE_DIR + "/log.log");
81         } catch (IOException ex) {
82             throw new RuntimeException("Test failed: should have been able"
83                     + " to create FileHandler for " + "%t/" + WRITABLE_DIR
84                     + "/log.log in writable directory"
85                     + (!writableDir.canRead() // concurrent tests running or user conf issue?
86                         ? ": directory not readable.\n\tPlease check your "
87                          + "environment and machine configuration."
88                         : "."), ex);
89         } finally {
90             // the above test leaves files in the directory.  Get rid of the
91             // files created and the directory
92             delete(writableDir);
93         }
94 
95         // Test 2: creating FileHandler in non-writable directory should fail
96         if (runNonWritableDirTest) {
97             try {
98                 new FileHandler("%t/" + NON_WRITABLE_DIR + "/log.log");
99                 throw new RuntimeException("Test failed: should not have been able"
100                         + " to create FileHandler for " + "%t/" + NON_WRITABLE_DIR
101                         + "/log.log in non-writable directory.");
102             } catch (AccessDeniedException ex) {
103                 // the right exception was thrown, so continue.
104             } catch (IOException ex) {
105                 throw new RuntimeException(
106                         "Test failed: Expected exception was not an "
107                                 + "AccessDeniedException", ex);
108             }
109         }
110 
111         // Test 3: creating FileHandler in non-directory should fail
112         try {
113             new FileHandler("%t/" + NOT_A_DIR + "/log.log");
114             throw new RuntimeException("Test failed: should not have been able"
115                     + " to create FileHandler for " + "%t/" + NOT_A_DIR
116                     + "/log.log in non-directory.");
117         } catch (FileSystemException ex) {
118             // the right exception was thrown, so continue.
119         } catch (IOException ex) {
120             throw new RuntimeException("Test failed: exception thrown was not a "
121                     + "FileSystemException", ex);
122         }
123 
124         // Test 4: make sure we can't create a FileHandler in a non-existent dir
125         try {
126             new FileHandler("%t/" + NON_EXISTENT_DIR + "/log.log");
127             throw new RuntimeException("Test failed: should not have been able"
128                     + " to create FileHandler for " + "%t/" + NON_EXISTENT_DIR
129                     + "/log.log in a non-existent directory.");
130         } catch (NoSuchFileException ex) {
131             // the right exception was thrown, so continue.
132         } catch (IOException ex) {
133             throw new RuntimeException("Test failed: Expected exception "
134                     + "was not a NoSuchFileException", ex);
135         }
136     }
137 
138     /**
139      * Setup all the files and directories needed for the tests
140      *
141      * @return writable directory created that needs to be deleted when done
142      * @throws RuntimeException
143      */
setup()144     private static File setup() throws RuntimeException {
145         // First do some setup in the temporary directory (using same logic as
146         // FileHandler for %t pattern)
147         String tmpDir = System.getProperty("java.io.tmpdir"); // i.e. %t
148         if (tmpDir == null) {
149             tmpDir = System.getProperty("user.home");
150         }
151         File tmpOrHomeDir = new File(tmpDir);
152         // Create a writable directory here (%t/writable-dir)
153         File writableDir = new File(tmpOrHomeDir, WRITABLE_DIR);
154         if (!createFile(writableDir, true)) {
155             throw new RuntimeException("Test setup failed: unable to create"
156                     + " writable working directory "
157                     + writableDir.getAbsolutePath() );
158         }
159 
160         if (!writableDir.canRead()) {
161             throw new RuntimeException("Test setup failed: can't read "
162                     + " writable working directory "
163                     + writableDir.getAbsolutePath() );
164         }
165 
166         // writableDirectory and its contents will be deleted after the test
167         // that uses it.
168 
169         // check that we can write in the new writable dir.
170         File dummyFile = new File(writableDir, UUID.randomUUID().toString() + ".txt" );
171         try {
172             if (!dummyFile.createNewFile()) {
173                 throw new RuntimeException("Test setup failed: can't create "
174                         + " dummy file in writable working directory "
175                         + dummyFile.getAbsolutePath() );
176             }
177             try (OutputStream os = new FileOutputStream(dummyFile)) {
178                 os.write('A');
179             } finally {
180                 dummyFile.delete();
181             }
182             if (dummyFile.canRead()) {
183                 throw new RuntimeException("Test setup failed: can't delete "
184                         + " dummy file in writable working directory "
185                         + dummyFile.getAbsolutePath() );
186             }
187             System.out.println("Successfully created and deleted dummy file: " +
188                 dummyFile.getAbsolutePath());
189         } catch(IOException x) {
190             throw new RuntimeException("Test setup failed: can't write "
191                         + " or delete dummy file in writable working directory "
192                         + dummyFile.getAbsolutePath(), x);
193         }
194 
195         // Create a plain file which we will attempt to use as a directory
196         // (%t/not-a-dir)
197         File notAdir = new File(tmpOrHomeDir, NOT_A_DIR);
198         if (!createFile(notAdir, false)) {
199             throw new RuntimeException("Test setup failed: unable to a plain"
200                     + " working file " + notAdir.getAbsolutePath() );
201         }
202         notAdir.deleteOnExit();
203 
204         // Create a non-writable directory (%t/non-writable-dir)
205         File nonWritableDir = new File(tmpOrHomeDir, NON_WRITABLE_DIR);
206         if (!createFile(nonWritableDir, true)) {
207             throw new RuntimeException("Test setup failed: unable to create"
208                     + " a non-"
209                     + "writable working directory "
210                     + nonWritableDir.getAbsolutePath() );
211         }
212         nonWritableDir.deleteOnExit();
213 
214         // make it non-writable
215         Path path = nonWritableDir.toPath();
216         final boolean nonWritable = nonWritableDir.setWritable(false);
217         final boolean isWritable = Files.isWritable(path);
218         if (nonWritable && !isWritable) {
219             runNonWritableDirTest = true;
220             System.out.println("Created non writable dir for "
221                     + getOwner(path) + " at: " + path.toString());
222         } else {
223             runNonWritableDirTest = false;
224             System.out.println( "Test Setup WARNING: unable to make"
225                     + " working directory " + nonWritableDir.getAbsolutePath()
226                     + "\n\t non-writable for " + getOwner(path)
227                     +  " on platform " + System.getProperty("os.name"));
228         }
229 
230         // make sure non-existent directory really doesn't exist
231         File nonExistentDir = new File(tmpOrHomeDir, NON_EXISTENT_DIR);
232         if (nonExistentDir.exists()) {
233             nonExistentDir.delete();
234         }
235         System.out.println("Setup completed - writableDir is: " + writableDir.getPath());
236         return writableDir;
237     }
238 
getOwner(Path path)239     private static String getOwner(Path path) {
240         UserPrincipal user = null;
241         try {
242             user = Files.getOwner(path);
243         } catch (Exception x) {
244             System.err.println("Failed to get owner of: " + path);
245             System.err.println("\terror is: " + x);
246         }
247         return user == null ? "???" : user.getName();
248     }
249 
250     /**
251      * @param newFile
252      * @return true if file already exists or creation succeeded
253      */
createFile(File newFile, boolean makeDirectory)254     private static boolean createFile(File newFile, boolean makeDirectory) {
255         if (newFile.exists()) {
256             return true;
257         }
258         if (makeDirectory) {
259             return newFile.mkdir();
260         } else {
261             try {
262                 return newFile.createNewFile();
263             } catch (IOException ioex) {
264                 ioex.printStackTrace();
265                 return false;
266             }
267         }
268     }
269 
270     /*
271      * Recursively delete all files starting at specified file
272      */
delete(File f)273     private static void delete(File f) {
274         if (f != null && f.isDirectory()) {
275             for (File c : f.listFiles())
276                 delete(c);
277         }
278         if (!f.delete())
279             System.err.println(
280                     "WARNING: unable to delete/cleanup writable test directory: "
281                     + f );
282         }
283 }
284