1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package libcore.java.nio.file; 18 19import org.junit.Before; 20import org.junit.Rule; 21import org.junit.Test; 22import org.junit.rules.TestRule; 23 24import java.io.IOException; 25import java.nio.ByteBuffer; 26import java.nio.channels.NonWritableChannelException; 27import java.nio.channels.SeekableByteChannel; 28import java.nio.file.ClosedDirectoryStreamException; 29import java.nio.file.DirectoryNotEmptyException; 30import java.nio.file.DirectoryStream; 31import java.nio.file.FileSystemException; 32import java.nio.file.Files; 33import java.nio.file.LinkOption; 34import java.nio.file.NoSuchFileException; 35import java.nio.file.NotDirectoryException; 36import java.nio.file.OpenOption; 37import java.nio.file.Path; 38import java.nio.file.Paths; 39import java.nio.file.SecureDirectoryStream; 40import java.nio.file.attribute.BasicFileAttributeView; 41import java.util.Arrays; 42import java.util.HashSet; 43import java.util.Iterator; 44import java.util.Set; 45 46import libcore.junit.util.ResourceLeakageDetector; 47import libcore.junit.util.ResourceLeakageDetector.LeakageDetectorRule; 48 49import static libcore.java.nio.file.FilesSetup.TEST_FILE_DATA; 50import static libcore.java.nio.file.FilesSetup.writeToFile; 51import static org.junit.Assert.assertEquals; 52import static org.junit.Assert.assertFalse; 53import static org.junit.Assert.assertTrue; 54import static org.junit.Assert.fail; 55 56public class DefaultSecureDirectoryStreamTest { 57 58 Path path_root; 59 Path path_dir1; 60 Path path_dir2; 61 Path path_dir3; 62 Path path_f1; 63 Path path_f2; 64 Path path_f3; 65 Path path_dir4; 66 67 @Rule 68 public FilesSetup filesSetup = new FilesSetup(); 69 @Rule 70 public LeakageDetectorRule resourceLeakageDetectorRule = ResourceLeakageDetector.getRule(); 71 72 @Before 73 public void setup() throws Exception { 74 75 // Initial setup of directory. 76 path_root = filesSetup.getPathInTestDir("dir"); 77 path_dir1 = filesSetup.getPathInTestDir("dir/dir1"); 78 path_dir2 = filesSetup.getPathInTestDir("dir/dir2"); 79 path_dir3 = filesSetup.getPathInTestDir("dir/dir3"); 80 path_dir4 = filesSetup.getPathInTestDir("dir/dir1/dir4"); 81 82 path_f1 = filesSetup.getPathInTestDir("dir/f1"); 83 path_f2 = filesSetup.getPathInTestDir("dir/f2"); 84 path_f3 = filesSetup.getPathInTestDir("dir/f3"); 85 86 Files.createDirectory(path_root); 87 Files.createDirectory(path_dir1); 88 Files.createDirectory(path_dir2); 89 Files.createDirectory(path_dir3); 90 Files.createDirectory(path_dir4); 91 Files.createFile(path_f1); 92 Files.createFile(path_f2); 93 Files.createFile(path_f3); 94 } 95 96 @Test 97 public void testIterator() throws IOException { 98 HashSet<Path> pathsSet = new HashSet<>(); 99 HashSet<Path> expectedPathsSet = new HashSet<>(); 100 101 expectedPathsSet.add(path_dir1); 102 expectedPathsSet.add(path_dir2); 103 expectedPathsSet.add(path_dir3); 104 105 // Filter all the directories. 106 try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path_root, 107 file -> Files.isDirectory(file))) { 108 Iterator<Path> directoryStreamIterator = directoryStream.iterator(); 109 directoryStreamIterator.forEachRemaining(path -> pathsSet.add(path)); 110 assertEquals(expectedPathsSet, pathsSet); 111 } 112 } 113 114 @Test 115 public void testIterator_calledTwice() throws IOException { 116 try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path_root, 117 file -> Files.isDirectory(file))) { 118 directoryStream.iterator(); 119 try { 120 directoryStream.iterator(); 121 fail(); 122 } catch (IllegalStateException expected) {} 123 } 124 } 125 126 @Test 127 public void testIterator_afterClose() throws IOException { 128 DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path_root, 129 file -> Files.isDirectory(file)); 130 directoryStream.close(); 131 try { 132 directoryStream.iterator(); 133 fail(); 134 } catch (IllegalStateException expected) {} 135 } 136 137 @Test 138 public void test_newDirectoryStream() throws IOException { 139 HashSet<Path> pathsSet = new HashSet<>(); 140 HashSet<Path> expectedPathsSet = new HashSet<>(); 141 142 expectedPathsSet.add(path_dir4); 143 144 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 145 Files.newDirectoryStream(path_root); 146 DirectoryStream<Path> ds_path_dir1 = ds_path_root.newDirectoryStream(path_root. 147 relativize(path_dir1))) { 148 149 ds_path_dir1.forEach(path -> pathsSet.add(path)); 150 assertEquals(expectedPathsSet, pathsSet); 151 } 152 } 153 154 @Test 155 public void test_newDirectoryStream_symbolicLink() throws IOException { 156 Path symlinkPath = Paths.get(path_dir1.toString(), "symlink"); 157 Files.createSymbolicLink(symlinkPath, path_dir3); 158 assertTrue(Files.isSymbolicLink(symlinkPath)); 159 160 try (SecureDirectoryStream<Path> ds_path_dir1 = (SecureDirectoryStream<Path>) 161 Files.newDirectoryStream(path_root)) { 162 try (DirectoryStream<Path> ds_path_dir2 = ds_path_dir1.newDirectoryStream(path_root. 163 relativize(symlinkPath), LinkOption.NOFOLLOW_LINKS)) { 164 fail(); 165 } catch (FileSystemException expected) {} 166 } 167 } 168 169 @Test 170 public void test_newDirectoryStream_Exception() throws IOException { 171 172 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 173 Files.newDirectoryStream(path_root)) { 174 // When file is not a directory. 175 try (DirectoryStream<Path> ds_path_dir1 = ds_path_root.newDirectoryStream(path_root. 176 relativize(path_f1))) { 177 fail(); 178 } catch (NotDirectoryException expected) {} 179 180 181 // NPE 182 try (DirectoryStream<Path> ds_path_dir1 = ds_path_root.newDirectoryStream(null)) { 183 fail(); 184 } catch (NullPointerException expected) {} 185 186 // NPE 187 try (DirectoryStream<Path> ds_path_dir1 = ds_path_root.newDirectoryStream(path_root. 188 relativize(path_f1), null)) { 189 fail(); 190 } catch (NullPointerException expected) {} 191 192 // When stream is closed. 193 ds_path_root.close(); 194 try (DirectoryStream<Path> ds_path_dir1 = ds_path_root.newDirectoryStream(path_root. 195 relativize(path_dir1))) { 196 fail(); 197 } catch (ClosedDirectoryStreamException expected) {} 198 } 199 } 200 201 @Test 202 public void test_newByteChannel() throws IOException { 203 Set<OpenOption> set = new HashSet<OpenOption>(); 204 205 // When file doesn't exist. 206 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 207 Files.newDirectoryStream(path_root)) { 208 209 try (SeekableByteChannel sbc = ds_path_root.newByteChannel(filesSetup.getTestPath(), 210 set)) { 211 fail(); 212 } catch (NoSuchFileException expected) { 213 assertTrue(expected.getMessage().contains(filesSetup.getTestPath().toString())); 214 } 215 216 // When file exists. 217 // File opens in READ mode by default. The channel is non writable by default. 218 try (SeekableByteChannel sbc = ds_path_root.newByteChannel( 219 path_root.relativize(path_f1), set)) { 220 sbc.write(ByteBuffer.allocate(10)); 221 fail(); 222 } catch (NonWritableChannelException expected) { 223 } 224 225 // Read a file. 226 writeToFile(path_f1, TEST_FILE_DATA); 227 try (SeekableByteChannel sbc = ds_path_root.newByteChannel( 228 path_root.relativize(path_f1), set)) { 229 ByteBuffer readBuffer = ByteBuffer.allocate(10); 230 int bytesReadCount = sbc.read(readBuffer); 231 232 String readData = new String(Arrays.copyOf(readBuffer.array(), bytesReadCount), 233 "UTF-8"); 234 assertEquals(TEST_FILE_DATA, readData); 235 } 236 237 // when directory stream is closed. 238 ds_path_root.close(); 239 try (SeekableByteChannel sbc = ds_path_root.newByteChannel( 240 path_root.relativize(path_f1), set)) { 241 fail(); 242 } catch (ClosedDirectoryStreamException expected) {} 243 } 244 } 245 246 @Test 247 public void test_newByteChannel_NPE() throws IOException { 248 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 249 Files.newDirectoryStream(path_root)) { 250 Set<OpenOption> set = new HashSet<OpenOption>(); 251 try (SeekableByteChannel sbc = ds_path_root.newByteChannel(null, set)) { 252 fail(); 253 } catch (NullPointerException expected) { 254 } 255 256 try (SeekableByteChannel sbc = ds_path_root.newByteChannel(filesSetup.getDataFilePath(), 257 null)) { 258 fail(); 259 } catch (NullPointerException expected) { 260 } 261 } 262 } 263 264 @Test 265 public void test_deleteFile() throws IOException { 266 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 267 Files.newDirectoryStream(path_root)) { 268 ds_path_root.deleteFile(path_root.relativize(path_f1)); 269 assertFalse(Files.exists(path_f1)); 270 271 // --- Exceptions --- 272 // When the file is a directory. 273 try { 274 ds_path_root.deleteFile(path_root.relativize(path_dir1)); 275 fail(); 276 } catch (FileSystemException expected) {} 277 278 // When file doesn't exists. 279 try { 280 ds_path_root.deleteFile(filesSetup.getTestPath()); 281 fail(); 282 } catch (NoSuchFileException expected) {} 283 284 // NullPointerException 285 try { 286 ds_path_root.deleteFile(null); 287 fail(); 288 } catch (NullPointerException expected) {} 289 290 // When the directory stream is closed. 291 ds_path_root.close(); 292 try { 293 ds_path_root.deleteFile(path_root.relativize(path_f2)); 294 fail(); 295 } catch (ClosedDirectoryStreamException expected) {} 296 297 } 298 } 299 300 @Test 301 public void test_deleteDirectory() throws IOException { 302 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 303 Files.newDirectoryStream(path_root)) { 304 ds_path_root.deleteDirectory(path_root.relativize(path_dir2)); 305 assertFalse(Files.exists(path_dir2)); 306 307 // When file is not a directory. 308 try { 309 ds_path_root.deleteDirectory(path_root.relativize(path_f1)); 310 fail(); 311 } catch (FileSystemException expected) {} 312 313 // When path doesn't exists. 314 try { 315 ds_path_root.deleteDirectory(filesSetup.getTestPath()); 316 fail(); 317 } catch (NoSuchFileException expected) {} 318 319 // When the directory is not empty. 320 try { 321 ds_path_root.deleteDirectory(path_root.relativize(path_dir1)); 322 fail(); 323 } catch (DirectoryNotEmptyException expected) {} 324 325 // --- Exceptions --- 326 // NullPointerException 327 try { 328 ds_path_root.deleteDirectory(null); 329 fail(); 330 } catch (NullPointerException expected) {} 331 332 // When the directory stream is closed. 333 ds_path_root.close(); 334 try { 335 ds_path_root.deleteDirectory(path_root.relativize(path_f2)); 336 fail(); 337 } catch (ClosedDirectoryStreamException expected) {} 338 } 339 } 340 341 @Test 342 public void test_move() throws IOException { 343 SecureDirectoryStream<Path> ds_path_dir1 = (SecureDirectoryStream<Path>) 344 Files.newDirectoryStream(path_dir1); 345 346 // moving a file. 347 ds_path_dir1.move(path_f1, ds_path_dir1, Paths.get("f1")); 348 assertTrue(Files.exists(Paths.get(path_dir1.toString(), "f1"))); 349 assertFalse(Files.exists(path_f1)); 350 351 // moving a directory. 352 ds_path_dir1.move(path_dir2, ds_path_dir1, Paths.get(path_dir4.toString(), "path_dir2")); 353 assertTrue(Files.exists(Paths.get(path_dir4.toString(), "path_dir2"))); 354 assertFalse(Files.exists(path_dir2)); 355 356 // when directory already exists of the same name. 357 ds_path_dir1.move(path_dir3, ds_path_dir1, Paths.get("path_dir2")); 358 assertTrue(Files.exists(Paths.get(path_dir1.toString(), "path_dir2"))); 359 assertFalse(Files.exists(path_dir3)); 360 361 // moving a non empty directory. 362 ds_path_dir1.move(path_dir1, ds_path_dir1, Paths.get(path_root.getParent().toString(), 363 "path_dir1")); 364 assertTrue(Files.exists(Paths.get(path_root.getParent().toString(), "path_dir1"))); 365 assertFalse(Files.exists(path_dir1)); 366 367 // --- Exceptions --- 368 // NullPointerException. 369 try { 370 ds_path_dir1.move(null, ds_path_dir1, 371 Paths.get(path_root.getParent().toString(), "path_dir1")); 372 fail(); 373 } catch (NullPointerException expected) {} 374 375 try { 376 ds_path_dir1.move(path_dir1, null, 377 Paths.get(path_root.getParent().toString(), "path_dir1")); 378 fail(); 379 } catch (NullPointerException expected) {} 380 381 try { 382 ds_path_dir1.move(path_dir1, ds_path_dir1, 383 Paths.get(path_root.getParent().toString(), null)); 384 fail(); 385 } catch (NullPointerException expected) {} 386 387 try { 388 // when targetDir stream is closed. 389 ds_path_dir1.close(); 390 ds_path_dir1.move(path_root, ds_path_dir1, path_f3); 391 fail(); 392 } catch (ClosedDirectoryStreamException expected) {} 393 } 394 395 @Test 396 public void test_getFileAttributeView() throws IOException { 397 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 398 Files.newDirectoryStream(path_root)) { 399 BasicFileAttributeView fileAttributeView = ds_path_root 400 .getFileAttributeView(BasicFileAttributeView.class); 401 402 assertFalse(fileAttributeView.readAttributes().isRegularFile()); 403 assertTrue(fileAttributeView.readAttributes().isDirectory()); 404 assertFalse(fileAttributeView.readAttributes().isSymbolicLink()); 405 406 // --- Exceptions --- 407 // NullPointerException 408 try { 409 ds_path_root.getFileAttributeView(null); 410 } catch (NullPointerException expected) {} 411 412 // When directory stream is closed. 413 ds_path_root.close(); 414 fileAttributeView = ds_path_root.getFileAttributeView(BasicFileAttributeView.class); 415 try { 416 fileAttributeView.readAttributes(); 417 fail(); 418 } catch (ClosedDirectoryStreamException expected) {} 419 } 420 } 421 422 @Test 423 public void test_getFileAttributeView_Path() throws IOException { 424 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 425 Files.newDirectoryStream(path_root)) { 426 BasicFileAttributeView fileAttributeView = ds_path_root.getFileAttributeView( 427 path_root.relativize(path_dir1), BasicFileAttributeView.class); 428 429 assertFalse(fileAttributeView.readAttributes().isRegularFile()); 430 assertTrue(fileAttributeView.readAttributes().isDirectory()); 431 assertFalse(fileAttributeView.readAttributes().isSymbolicLink()); 432 433 fileAttributeView = ds_path_root.getFileAttributeView(path_root.relativize(path_f1), 434 BasicFileAttributeView.class); 435 436 assertTrue(fileAttributeView.readAttributes().isRegularFile()); 437 assertFalse(fileAttributeView.readAttributes().isDirectory()); 438 assertFalse(fileAttributeView.readAttributes().isSymbolicLink()); 439 440 // When file is a symbolic link. 441 Path symlinkPath = Paths.get(path_root.toString(), "symlink"); 442 Files.createSymbolicLink(symlinkPath, path_dir1); 443 assertTrue(Files.isSymbolicLink(symlinkPath)); 444 // When file is a symbolic link and method is invoked with LinkOptions.NOFOLLOW_LINKS. 445 fileAttributeView = ds_path_root.getFileAttributeView(path_root.relativize(symlinkPath), 446 BasicFileAttributeView.class); 447 assertTrue(fileAttributeView.readAttributes().isDirectory()); 448 449 // --- Exceptions --- 450 try { 451 ds_path_root.getFileAttributeView(null, BasicFileAttributeView.class); 452 fail(); 453 } catch (NullPointerException expected) {} 454 455 try { 456 ds_path_root.getFileAttributeView(path_root.relativize(path_f1), null); 457 fail(); 458 } catch (NullPointerException expected) {} 459 460 // When directory stream is closed. 461 ds_path_root.close(); 462 fileAttributeView = ds_path_root.getFileAttributeView(path_root.relativize(path_f1), 463 BasicFileAttributeView.class); 464 try { 465 fileAttributeView.readAttributes(); 466 fail(); 467 } catch (ClosedDirectoryStreamException expected) {} 468 } 469 } 470 471 @Test 472 public void test_getFileAttributeView_Path_LinkOptions() throws IOException { 473 Path symlinkPath = Paths.get(path_root.toString(), "symlink"); 474 Files.createSymbolicLink(symlinkPath, path_dir1); 475 assertTrue(Files.isSymbolicLink(symlinkPath)); 476 // When file is a symbolic link and method is invoked with LinkOptions.NOFOLLOW_LINKS. 477 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 478 Files.newDirectoryStream(path_root)) { 479 BasicFileAttributeView fileAttributeView = ds_path_root.getFileAttributeView( 480 path_root.relativize(symlinkPath), BasicFileAttributeView.class, 481 LinkOption.NOFOLLOW_LINKS); 482 assertTrue(fileAttributeView.readAttributes().isSymbolicLink()); 483 } 484 485 // When file is not a symbolic link. 486 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 487 Files.newDirectoryStream(path_root)) { 488 BasicFileAttributeView fileAttributeView = ds_path_root 489 .getFileAttributeView(path_root.relativize(path_f1), 490 BasicFileAttributeView.class, LinkOption.NOFOLLOW_LINKS); 491 assertTrue(fileAttributeView.readAttributes().isRegularFile()); 492 assertFalse(fileAttributeView.readAttributes().isDirectory()); 493 assertFalse(fileAttributeView.readAttributes().isSymbolicLink()); 494 } 495 496 // --- Exceptions --- 497 // NullPointerException 498 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 499 Files.newDirectoryStream(path_root)) { 500 ds_path_root.getFileAttributeView(path_root.relativize(path_f1), 501 BasicFileAttributeView.class, null); 502 fail(); 503 } catch (NullPointerException expected) {} 504 } 505 506 @Test 507 public void testUnixSecureDirectoryStreamHasFinalizer() throws IOException { 508 try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>) 509 Files.newDirectoryStream(path_root)) { 510 resourceLeakageDetectorRule.assertUnreleasedResourceCount(ds_path_root, 1); 511 } 512 } 513} 514