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