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