1 /* 2 * Copyright (C) 2023 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 17 package android.scopedstorage.cts.lib; 18 19 import static android.scopedstorage.cts.lib.TestUtils.assertThrows; 20 import static android.scopedstorage.cts.lib.TestUtils.getAndroidDir; 21 import static android.system.OsConstants.F_OK; 22 import static android.system.OsConstants.R_OK; 23 import static android.system.OsConstants.W_OK; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import static org.junit.Assume.assumeFalse; 28 29 import android.system.ErrnoException; 30 import android.system.Os; 31 32 import java.io.File; 33 import java.util.Arrays; 34 import java.util.Set; 35 import java.util.stream.Collectors; 36 37 /** 38 * Utility class to test media access using the file system. 39 * 40 * Its twin class {@link ResolverAccessTestUtils } covers testing using the Content Resolver API. 41 */ 42 public class FilePathAccessTestUtils { assertFileAccess_existsOnly(File file)43 public static void assertFileAccess_existsOnly(File file) throws Exception { 44 assertThat(file.isFile()).isTrue(); 45 assertAccess(file, true /* file exists */, false /* can read */, false /* can write */); 46 } 47 assertFileAccess_readOnly(File file)48 public static void assertFileAccess_readOnly(File file) throws Exception { 49 assertThat(file.isFile()).isTrue(); 50 assertAccess(file, true /* file exists */, true /* can read */, false /* can write */); 51 } 52 assertFileAccess_readWrite(File file)53 public static void assertFileAccess_readWrite(File file) throws Exception { 54 assertThat(file.isFile()).isTrue(); 55 assertAccess(file, true/* file exists */, true /* can read */, true /* can write */); 56 } 57 assertDirectoryAccess(File dir, boolean exists, boolean canWrite)58 public static void assertDirectoryAccess(File dir, boolean exists, boolean canWrite) 59 throws Exception { 60 // This util does not handle app data directories. 61 assumeFalse(dir.getAbsolutePath().startsWith(getAndroidDir().getAbsolutePath()) 62 && !dir.equals(getAndroidDir())); 63 assertThat(dir.isDirectory()).isEqualTo(exists); 64 // For non-app data directories, exists => canRead(). 65 assertAccess(dir, exists, exists, exists && canWrite); 66 } 67 assertAccess(File file, boolean exists, boolean canRead, boolean canWrite)68 public static void assertAccess(File file, boolean exists, boolean canRead, boolean canWrite) 69 throws Exception { 70 assertAccess(file, exists, canRead, canWrite, true /* checkExists */); 71 } 72 assertCannotReadOrWrite(File file)73 public static void assertCannotReadOrWrite(File file) 74 throws Exception { 75 // App data directories have different 'x' bits on upgrading vs new devices. Let's not 76 // check 'exists', by passing checkExists=false. But assert this app cannot read or write 77 // the other app's file. 78 assertAccess(file, false /* value is moot */, false /* canRead */, 79 false /* canWrite */, false /* checkExists */); 80 } 81 assertCanAccessMyAppFile(File file)82 public static void assertCanAccessMyAppFile(File file) 83 throws Exception { 84 assertAccess(file, true, true /* canRead */, 85 true /*canWrite */, true /* checkExists */); 86 } 87 assertAccess(File file, boolean exists, boolean canRead, boolean canWrite, boolean checkExists)88 private static void assertAccess(File file, boolean exists, boolean canRead, boolean canWrite, 89 boolean checkExists) throws Exception { 90 if (checkExists) { 91 assertThat(file.exists()).isEqualTo(exists); 92 } 93 assertThat(file.canRead()).isEqualTo(canRead); 94 assertThat(file.canWrite()).isEqualTo(canWrite); 95 if (file.isDirectory()) { 96 if (checkExists) { 97 assertThat(file.canExecute()).isEqualTo(exists); 98 } 99 } else { 100 assertThat(file.canExecute()).isFalse(); // Filesytem is mounted with MS_NOEXEC 101 } 102 103 // Test some combinations of mask. 104 assertAccess(file, R_OK, canRead); 105 assertAccess(file, W_OK, canWrite); 106 assertAccess(file, R_OK | W_OK, canRead && canWrite); 107 assertAccess(file, W_OK | F_OK, canWrite); 108 109 if (checkExists) { 110 assertAccess(file, F_OK, exists); 111 } 112 } 113 assertAccess(File file, int mask, boolean expected)114 private static void assertAccess(File file, int mask, boolean expected) throws Exception { 115 if (expected) { 116 assertThat(Os.access(file.getAbsolutePath(), mask)).isTrue(); 117 } else { 118 assertThrows(ErrnoException.class, () -> Os.access(file.getAbsolutePath(), mask)); 119 } 120 } 121 122 /** 123 * Checks that specific files are visible and others are not in a given folder 124 */ assertFileAccess_listFiles(File dir, Set<File> expected, Set<File> notExpected)125 public static void assertFileAccess_listFiles(File dir, Set<File> expected, 126 Set<File> notExpected) { 127 assertThat(dir.isDirectory()).isTrue(); 128 Set<File> files = Arrays.stream(dir.listFiles()).collect(Collectors.toSet()); 129 assertThat(files).containsAtLeastElementsIn(expected); 130 assertThat(files).containsNoneIn(notExpected); 131 } 132 } 133