1 /* 2 * Copyright (C) 2015 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 com.android.mtp; 18 19 import android.os.ParcelFileDescriptor; 20 import android.os.storage.StorageManager; 21 import android.system.ErrnoException; 22 import android.system.Os; 23 import android.test.AndroidTestCase; 24 import android.test.suitebuilder.annotation.MediumTest; 25 26 import libcore.io.IoUtils; 27 28 import java.io.File; 29 import java.io.FileNotFoundException; 30 import java.io.IOException; 31 import java.util.Arrays; 32 33 @MediumTest 34 public class AppFuseTest extends AndroidTestCase { 35 public void testMount() throws ErrnoException, IOException { 36 final StorageManager storageManager = getContext().getSystemService(StorageManager.class); 37 final AppFuse appFuse = new AppFuse("test", new TestCallback()); 38 appFuse.mount(storageManager); 39 final File file = appFuse.getMountPoint(); 40 assertTrue(file.isDirectory()); 41 assertEquals(1, Os.stat(file.getPath()).st_ino); 42 appFuse.close(); 43 assertTrue(1 != Os.stat(file.getPath()).st_ino); 44 } 45 46 public void testOpenFile() throws IOException { 47 final StorageManager storageManager = getContext().getSystemService(StorageManager.class); 48 final int INODE = 10; 49 final AppFuse appFuse = new AppFuse( 50 "test", 51 new TestCallback() { 52 @Override 53 public long getFileSize(int inode) throws FileNotFoundException { 54 if (INODE == inode) { 55 return 1024; 56 } 57 throw new FileNotFoundException(); 58 } 59 }); 60 appFuse.mount(storageManager); 61 final ParcelFileDescriptor fd = appFuse.openFile( 62 INODE, ParcelFileDescriptor.MODE_READ_ONLY); 63 fd.close(); 64 appFuse.close(); 65 } 66 67 public void testOpenFile_fileNotFound() throws IOException { 68 final StorageManager storageManager = getContext().getSystemService(StorageManager.class); 69 final int INODE = 10; 70 final AppFuse appFuse = new AppFuse("test", new TestCallback()); 71 appFuse.mount(storageManager); 72 try { 73 appFuse.openFile(INODE, ParcelFileDescriptor.MODE_READ_ONLY); 74 fail(); 75 } catch (FileNotFoundException exp) {} 76 appFuse.close(); 77 } 78 79 public void testOpenFile_illegalMode() throws IOException { 80 final StorageManager storageManager = getContext().getSystemService(StorageManager.class); 81 final int INODE = 10; 82 final AppFuse appFuse = new AppFuse("test", new TestCallback()); 83 appFuse.mount(storageManager); 84 try { 85 appFuse.openFile(INODE, ParcelFileDescriptor.MODE_READ_WRITE); 86 fail(); 87 } catch (IllegalArgumentException exp) {} 88 appFuse.close(); 89 } 90 91 public void testReadFile() throws IOException { 92 final StorageManager storageManager = getContext().getSystemService(StorageManager.class); 93 final int fileInode = 10; 94 final byte[] fileBytes = new byte[] { 'a', 'b', 'c', 'd', 'e' }; 95 final AppFuse appFuse = new AppFuse( 96 "test", 97 new TestCallback() { 98 @Override 99 public long getFileSize(int inode) throws FileNotFoundException { 100 if (inode == fileInode) { 101 return fileBytes.length; 102 } 103 return super.getFileSize(inode); 104 } 105 106 @Override 107 public long readObjectBytes(int inode, long offset, long size, byte[] bytes) 108 throws IOException { 109 if (inode == fileInode) { 110 int i = 0; 111 while (i < size && i + offset < fileBytes.length) { 112 bytes[i] = fileBytes[(int) (i + offset)]; 113 i++; 114 } 115 return i; 116 } 117 return super.readObjectBytes(inode, offset, size, bytes); 118 } 119 }); 120 appFuse.mount(storageManager); 121 final ParcelFileDescriptor fd = appFuse.openFile( 122 fileInode, ParcelFileDescriptor.MODE_READ_ONLY); 123 try (final ParcelFileDescriptor.AutoCloseInputStream stream = 124 new ParcelFileDescriptor.AutoCloseInputStream(fd)) { 125 final byte[] buffer = new byte[1024]; 126 final int size = stream.read(buffer, 0, buffer.length); 127 assertEquals(5, size); 128 } 129 appFuse.close(); 130 } 131 132 public void testWriteFile() throws IOException { 133 final StorageManager storageManager = getContext().getSystemService(StorageManager.class); 134 final int INODE = 10; 135 final byte[] resultBytes = new byte[5]; 136 final AppFuse appFuse = new AppFuse( 137 "test", 138 new TestCallback() { 139 @Override 140 public long getFileSize(int inode) throws FileNotFoundException { 141 if (inode != INODE) { 142 throw new FileNotFoundException(); 143 } 144 return resultBytes.length; 145 } 146 147 @Override 148 public int writeObjectBytes( 149 long fileHandle, int inode, long offset, int size, byte[] bytes) { 150 for (int i = 0; i < size; i++) { 151 resultBytes[(int)(offset + i)] = bytes[i]; 152 } 153 return size; 154 } 155 }); 156 appFuse.mount(storageManager); 157 final ParcelFileDescriptor fd = appFuse.openFile( 158 INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE); 159 try (final ParcelFileDescriptor.AutoCloseOutputStream stream = 160 new ParcelFileDescriptor.AutoCloseOutputStream(fd)) { 161 stream.write('a'); 162 stream.write('b'); 163 stream.write('c'); 164 stream.write('d'); 165 stream.write('e'); 166 } 167 final byte[] BYTES = new byte[] { 'a', 'b', 'c', 'd', 'e' }; 168 assertTrue(Arrays.equals(BYTES, resultBytes)); 169 appFuse.close(); 170 } 171 172 public void testWriteFile_writeError() throws IOException { 173 final StorageManager storageManager = getContext().getSystemService(StorageManager.class); 174 final int INODE = 10; 175 final AppFuse appFuse = new AppFuse( 176 "test", 177 new TestCallback() { 178 @Override 179 public long getFileSize(int inode) throws FileNotFoundException { 180 if (inode != INODE) { 181 throw new FileNotFoundException(); 182 } 183 return 5; 184 } 185 }); 186 appFuse.mount(storageManager); 187 final ParcelFileDescriptor fd = appFuse.openFile( 188 INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE); 189 try (final ParcelFileDescriptor.AutoCloseOutputStream stream = 190 new ParcelFileDescriptor.AutoCloseOutputStream(fd)) { 191 stream.write('a'); 192 fail(); 193 } catch (IOException e) { 194 } 195 appFuse.close(); 196 } 197 198 public void testWriteFile_flushError() throws IOException { 199 final StorageManager storageManager = getContext().getSystemService(StorageManager.class); 200 final int INODE = 10; 201 final AppFuse appFuse = new AppFuse( 202 "test", 203 new TestCallback() { 204 @Override 205 public long getFileSize(int inode) throws FileNotFoundException { 206 if (inode != INODE) { 207 throw new FileNotFoundException(); 208 } 209 return 5; 210 } 211 212 @Override 213 public int writeObjectBytes( 214 long fileHandle, int inode, long offset, int size, byte[] bytes) { 215 return size; 216 } 217 218 @Override 219 public void flushFileHandle(long fileHandle) throws IOException { 220 throw new IOException(); 221 } 222 }); 223 appFuse.mount(storageManager); 224 final ParcelFileDescriptor fd = appFuse.openFile( 225 INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE); 226 try (final ParcelFileDescriptor.AutoCloseOutputStream stream = 227 new ParcelFileDescriptor.AutoCloseOutputStream(fd)) { 228 stream.write('a'); 229 try { 230 IoUtils.close(fd.getFileDescriptor()); 231 fail(); 232 } catch (IOException e) { 233 } 234 } 235 appFuse.close(); 236 } 237 238 private static class TestCallback implements AppFuse.Callback { 239 @Override 240 public long getFileSize(int inode) throws FileNotFoundException { 241 throw new FileNotFoundException(); 242 } 243 244 @Override 245 public long readObjectBytes(int inode, long offset, long size, byte[] bytes) 246 throws IOException { 247 throw new IOException(); 248 } 249 250 @Override 251 public int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes) 252 throws IOException { 253 throw new IOException(); 254 } 255 256 @Override 257 public void flushFileHandle(long fileHandle) throws IOException {} 258 259 @Override 260 public void closeFileHandle(long fileHandle) {} 261 } 262 } 263