1 /*
2  * Copyright (c) 2008, 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 4313887 6838333
26  * @summary Unit test for java.nio.file.SecureDirectoryStream
27  * @library ..
28  */
29 
30 import java.nio.file.*;
31 import static java.nio.file.Files.*;
32 import static java.nio.file.StandardOpenOption.*;
33 import static java.nio.file.LinkOption.*;
34 import java.nio.file.attribute.*;
35 import java.nio.channels.*;
36 import java.io.IOException;
37 import java.util.*;
38 
39 public class SecureDS {
40     static boolean supportsLinks;
41 
main(String[] args)42     public static void main(String[] args) throws IOException {
43         Path dir = TestUtil.createTemporaryDirectory();
44         try {
45             DirectoryStream<Path> stream = newDirectoryStream(dir);
46             stream.close();
47             if (!(stream instanceof SecureDirectoryStream)) {
48                 if (System.getProperty("os.name").equals("Linux"))
49                     throw new AssertionError(
50                             "SecureDirectoryStream not supported.");
51                 System.out.println("SecureDirectoryStream not supported.");
52                 return;
53             }
54 
55             supportsLinks = TestUtil.supportsLinks(dir);
56 
57             // run tests
58             doBasicTests(dir);
59             doMoveTests(dir);
60             miscTests(dir);
61 
62         } finally {
63             TestUtil.removeAll(dir);
64         }
65     }
66 
67     // Exercise each of SecureDirectoryStream's method (except move)
doBasicTests(Path dir)68     static void doBasicTests(Path dir) throws IOException {
69         Path dir1 = createDirectory(dir.resolve("dir1"));
70         Path dir2 = dir.resolve("dir2");
71 
72         // create a file, directory, and two sym links in the directory
73         Path fileEntry = Paths.get("myfile");
74         createFile(dir1.resolve(fileEntry));
75         Path dirEntry = Paths.get("mydir");
76         createDirectory(dir1.resolve(dirEntry));
77         // myfilelink -> myfile
78         Path link1Entry = Paths.get("myfilelink");
79         if (supportsLinks)
80             createSymbolicLink(dir1.resolve(link1Entry), fileEntry);
81         // mydirlink -> mydir
82         Path link2Entry = Paths.get("mydirlink");
83         if (supportsLinks)
84             createSymbolicLink(dir1.resolve(link2Entry), dirEntry);
85 
86         // open directory and then move it so that it is no longer accessible
87         // via its original path.
88         SecureDirectoryStream<Path> stream =
89             (SecureDirectoryStream<Path>)newDirectoryStream(dir1);
90         move(dir1, dir2);
91 
92         // Test: iterate over all entries
93         int count = 0;
94         for (Path entry: stream) { count++; }
95         assertTrue(count == (supportsLinks ? 4 : 2));
96 
97         // Test: getFileAttributeView to access directory's attributes
98         assertTrue(stream
99             .getFileAttributeView(BasicFileAttributeView.class)
100                 .readAttributes()
101                     .isDirectory());
102 
103         // Test: getFileAttributeView to access attributes of entries
104         assertTrue(stream
105             .getFileAttributeView(fileEntry, BasicFileAttributeView.class)
106                 .readAttributes()
107                     .isRegularFile());
108         assertTrue(stream
109             .getFileAttributeView(fileEntry, BasicFileAttributeView.class, NOFOLLOW_LINKS)
110                 .readAttributes()
111                     .isRegularFile());
112         assertTrue(stream
113             .getFileAttributeView(dirEntry, BasicFileAttributeView.class)
114                 .readAttributes()
115                     .isDirectory());
116         assertTrue(stream
117             .getFileAttributeView(dirEntry, BasicFileAttributeView.class, NOFOLLOW_LINKS)
118                 .readAttributes()
119                     .isDirectory());
120         if (supportsLinks) {
121             assertTrue(stream
122                 .getFileAttributeView(link1Entry, BasicFileAttributeView.class)
123                     .readAttributes()
124                         .isRegularFile());
125             assertTrue(stream
126                 .getFileAttributeView(link1Entry, BasicFileAttributeView.class, NOFOLLOW_LINKS)
127                     .readAttributes()
128                         .isSymbolicLink());
129             assertTrue(stream
130                 .getFileAttributeView(link2Entry, BasicFileAttributeView.class)
131                     .readAttributes()
132                         .isDirectory());
133             assertTrue(stream
134                 .getFileAttributeView(link2Entry, BasicFileAttributeView.class, NOFOLLOW_LINKS)
135                     .readAttributes()
136                         .isSymbolicLink());
137         }
138 
139         // Test: newByteChannel
140         Set<StandardOpenOption> opts = Collections.emptySet();
141         stream.newByteChannel(fileEntry, opts).close();
142         if (supportsLinks) {
143             stream.newByteChannel(link1Entry, opts).close();
144             try {
145                 Set<OpenOption> mixed = new HashSet<>();
146                 mixed.add(READ);
147                 mixed.add(NOFOLLOW_LINKS);
148                 stream.newByteChannel(link1Entry, mixed).close();
149                 shouldNotGetHere();
150             } catch (IOException x) { }
151         }
152 
153         // Test: newDirectoryStream
154         stream.newDirectoryStream(dirEntry).close();
155         stream.newDirectoryStream(dirEntry, LinkOption.NOFOLLOW_LINKS).close();
156         if (supportsLinks) {
157             stream.newDirectoryStream(link2Entry).close();
158             try {
159                 stream.newDirectoryStream(link2Entry, LinkOption.NOFOLLOW_LINKS)
160                     .close();
161                 shouldNotGetHere();
162             } catch (IOException x) { }
163         }
164 
165         // Test: delete
166         if (supportsLinks) {
167             stream.deleteFile(link1Entry);
168             stream.deleteFile(link2Entry);
169         }
170         stream.deleteDirectory(dirEntry);
171         stream.deleteFile(fileEntry);
172 
173         // clean-up
174         stream.close();
175         delete(dir2);
176     }
177 
178     // Exercise SecureDirectoryStream's move method
doMoveTests(Path dir)179     static void doMoveTests(Path dir) throws IOException {
180         Path dir1 = createDirectory(dir.resolve("dir1"));
181         Path dir2 = createDirectory(dir.resolve("dir2"));
182 
183         // create dir1/myfile, dir1/mydir, dir1/mylink
184         Path fileEntry = Paths.get("myfile");
185         createFile(dir1.resolve(fileEntry));
186         Path dirEntry = Paths.get("mydir");
187         createDirectory(dir1.resolve(dirEntry));
188         Path linkEntry = Paths.get("mylink");
189         if (supportsLinks)
190             createSymbolicLink(dir1.resolve(linkEntry), Paths.get("missing"));
191 
192         // target name
193         Path target = Paths.get("newfile");
194 
195         // open stream to both directories
196         SecureDirectoryStream<Path> stream1 =
197             (SecureDirectoryStream<Path>)newDirectoryStream(dir1);
198         SecureDirectoryStream<Path> stream2 =
199             (SecureDirectoryStream<Path>)newDirectoryStream(dir2);
200 
201         // Test: move dir1/myfile -> dir2/newfile
202         stream1.move(fileEntry, stream2, target);
203         assertTrue(notExists(dir1.resolve(fileEntry)));
204         assertTrue(exists(dir2.resolve(target)));
205         stream2.deleteFile(target);
206 
207         // Test: move dir1/mydir -> dir2/newfile
208         stream1.move(dirEntry, stream2, target);
209         assertTrue(notExists(dir1.resolve(dirEntry)));
210         assertTrue(exists(dir2.resolve(target)));
211         stream2.deleteDirectory(target);
212 
213         // Test: move dir1/mylink -> dir2/newfile
214         if (supportsLinks) {
215             stream1.move(linkEntry, stream2, target);
216             assertTrue(isSymbolicLink(dir2.resolve(target)));
217             stream2.deleteFile(target);
218         }
219 
220         // Test: move between devices
221         String testDirAsString = System.getProperty("test.dir");
222         if (testDirAsString != null) {
223             Path testDir = Paths.get(testDirAsString);
224             if (!getFileStore(dir1).equals(getFileStore(testDir))) {
225                 SecureDirectoryStream<Path> ts =
226                     (SecureDirectoryStream<Path>)newDirectoryStream(testDir);
227                 createFile(dir1.resolve(fileEntry));
228                 try {
229                     stream1.move(fileEntry, ts, target);
230                     shouldNotGetHere();
231                 } catch (AtomicMoveNotSupportedException x) { }
232                 ts.close();
233                 stream1.deleteFile(fileEntry);
234             }
235         }
236 
237         // clean-up
238         delete(dir1);
239         delete(dir2);
240     }
241 
242     // null and ClosedDirectoryStreamException
miscTests(Path dir)243     static void miscTests(Path dir) throws IOException {
244         Path file = Paths.get("file");
245         createFile(dir.resolve(file));
246 
247         SecureDirectoryStream<Path> stream =
248             (SecureDirectoryStream<Path>)newDirectoryStream(dir);
249 
250         // NullPointerException
251         try {
252             stream.getFileAttributeView(null);
253             shouldNotGetHere();
254         } catch (NullPointerException x) { }
255         try {
256             stream.getFileAttributeView(null, BasicFileAttributeView.class);
257             shouldNotGetHere();
258         } catch (NullPointerException x) { }
259         try {
260             stream.getFileAttributeView(file, null);
261             shouldNotGetHere();
262         } catch (NullPointerException x) { }
263         try {
264             stream.newByteChannel(null, EnumSet.of(CREATE,WRITE));
265             shouldNotGetHere();
266         } catch (NullPointerException x) { }
267         try {
268             stream.newByteChannel(null, EnumSet.of(CREATE,WRITE,null));
269             shouldNotGetHere();
270         } catch (NullPointerException x) { }
271         try {
272             stream.newByteChannel(file, null);
273             shouldNotGetHere();
274         } catch (NullPointerException x) { }
275         try {
276             stream.move(null, stream, file);
277             shouldNotGetHere();
278         } catch (NullPointerException x) { }
279         try {
280             stream.move(file, null, file);
281             shouldNotGetHere();
282         } catch (NullPointerException x) { }
283         try {
284             stream.move(file, stream, null);
285             shouldNotGetHere();
286         } catch (NullPointerException x) { }
287         try {
288             stream.newDirectoryStream(null);
289             shouldNotGetHere();
290         } catch (NullPointerException x) { }
291         try {
292             stream.deleteFile(null);
293             shouldNotGetHere();
294         } catch (NullPointerException x) { }
295         try {
296             stream.deleteDirectory(null);
297             shouldNotGetHere();
298         } catch (NullPointerException x) { }
299 
300         // close stream
301         stream.close();
302         stream.close();     // should be no-op
303 
304         // ClosedDirectoryStreamException
305         try {
306             stream.newDirectoryStream(file);
307             shouldNotGetHere();
308         } catch (ClosedDirectoryStreamException x) { }
309         try {
310             stream.newByteChannel(file, EnumSet.of(READ));
311             shouldNotGetHere();
312         } catch (ClosedDirectoryStreamException x) { }
313         try {
314             stream.move(file, stream, file);
315             shouldNotGetHere();
316         } catch (ClosedDirectoryStreamException x) { }
317         try {
318             stream.deleteFile(file);
319             shouldNotGetHere();
320         } catch (ClosedDirectoryStreamException x) { }
321 
322         // clean-up
323         delete(dir.resolve(file));
324     }
325 
assertTrue(boolean b)326     static void assertTrue(boolean b) {
327         if (!b) throw new RuntimeException("Assertion failed");
328     }
329 
shouldNotGetHere()330     static void shouldNotGetHere() {
331         assertTrue(false);
332     }
333 }
334