FuseAppLoop.java revision 9fb00183a04036a58ee208f5bfd6c9768982f0aa
1878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono/* 2878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * Copyright (C) 2016 The Android Open Source Project 3878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * 4878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * Licensed under the Apache License, Version 2.0 (the "License"); 5878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * you may not use this file except in compliance with the License. 6878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * You may obtain a copy of the License at 7878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * 8878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * http://www.apache.org/licenses/LICENSE-2.0 9878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * 10878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * Unless required by applicable law or agreed to in writing, software 11878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * distributed under the License is distributed on an "AS IS" BASIS, 12878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * See the License for the specific language governing permissions and 14878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * limitations under the License. 15878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono */ 16878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 17878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironopackage com.android.internal.os; 18878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 19878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.annotation.NonNull; 20878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.annotation.Nullable; 219fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hironoimport android.os.ProxyFileDescriptorCallback; 22878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.os.ParcelFileDescriptor; 23878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.system.ErrnoException; 24878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.system.OsConstants; 25878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.util.Log; 26878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.util.SparseArray; 27878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport com.android.internal.annotations.GuardedBy; 289fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hironoimport com.android.internal.annotations.VisibleForTesting; 29878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport com.android.internal.util.Preconditions; 30878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 31878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport java.io.IOException; 329fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hironoimport java.util.concurrent.ThreadFactory; 33878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 34878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironopublic class FuseAppLoop { 35878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private static final String TAG = "FuseAppLoop"; 36878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 37878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono public static final int ROOT_INODE = 1; 38878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private static final int MIN_INODE = 2; 399fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono private static final ThreadFactory sDefaultThreadFactory = new ThreadFactory() { 409fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono @Override 419fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono public Thread newThread(Runnable r) { 429fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return new Thread(r, TAG); 439fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } 449fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono }; 45878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 46878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private final Object mLock = new Object(); 479fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono private final int mMountPointId; 489fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono private final Thread mThread; 49878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 50878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @GuardedBy("mLock") 51878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private final SparseArray<CallbackEntry> mCallbackMap = new SparseArray<>(); 52878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 53878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono /** 54878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * Sequential number can be used as file name and inode in AppFuse. 55878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * 0 is regarded as an error, 1 is mount point. So we start the number from 2. 56878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono */ 57878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @GuardedBy("mLock") 58878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private int mNextInode = MIN_INODE; 59878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 609fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono private FuseAppLoop( 619fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono int mountPointId, @NonNull ParcelFileDescriptor fd, @Nullable ThreadFactory factory) { 629fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono mMountPointId = mountPointId; 63878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono final int rawFd = fd.detachFd(); 649fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono if (factory == null) { 659fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono factory = sDefaultThreadFactory; 669fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } 679fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono mThread = factory.newThread(new Runnable() { 68878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @Override 69878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono public void run() { 709fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono // rawFd is closed by native_start_loop. Java code does not need to close it. 719fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono native_start_loop(rawFd); 72878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 739fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono }); 749fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } 759fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono 769fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono public static @NonNull FuseAppLoop open(int mountPointId, @NonNull ParcelFileDescriptor fd, 779fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono @Nullable ThreadFactory factory) { 789fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono Preconditions.checkNotNull(fd); 799fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono final FuseAppLoop loop = new FuseAppLoop(mountPointId, fd, factory); 809fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono loop.mThread.start(); 819fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return loop; 82878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 83878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 849fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono public int registerCallback(@NonNull ProxyFileDescriptorCallback callback) 85878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono throws UnmountedException, IOException { 869fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono if (mThread.getState() == Thread.State.TERMINATED) { 879fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono throw new UnmountedException(); 889fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } 89878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono synchronized (mLock) { 90878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono if (mCallbackMap.size() >= Integer.MAX_VALUE - MIN_INODE) { 91878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono throw new IOException("Too many opened files."); 92878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 939fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono int id; 94878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono while (true) { 95878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono id = mNextInode; 96878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono mNextInode++; 97878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono if (mNextInode < 0) { 98878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono mNextInode = MIN_INODE; 99878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 100878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono if (mCallbackMap.get(id) == null) { 101878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono break; 102878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 103878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 104878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono mCallbackMap.put(id, new CallbackEntry(callback)); 1059fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return id; 106878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 107878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 108878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 1099fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono public void unregisterCallback(int id) { 1109fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono mCallbackMap.remove(id); 1119fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } 1129fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono 1139fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono public int getMountPointId() { 1149fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return mMountPointId; 115878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 116878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 117878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private CallbackEntry getCallbackEntryOrThrowLocked(long inode) throws ErrnoException { 118878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono final CallbackEntry entry = mCallbackMap.get(checkInode(inode)); 119878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono if (entry != null) { 120878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono return entry; 121878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } else { 122878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono throw new ErrnoException("getCallbackEntry", OsConstants.ENOENT); 123878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 124878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 125878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 126878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono // Called by JNI. 127878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @SuppressWarnings("unused") 128878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private long onGetSize(long inode) { 129878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono synchronized(mLock) { 130878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono try { 131878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono return getCallbackEntryOrThrowLocked(inode).callback.onGetSize(); 132878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } catch (ErrnoException exp) { 1339fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return getError(exp); 134878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 135878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 136878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 137878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 138878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono // Called by JNI. 139878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @SuppressWarnings("unused") 140878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private int onOpen(long inode) { 141878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono synchronized(mLock) { 142878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono try { 143878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono final CallbackEntry entry = getCallbackEntryOrThrowLocked(inode); 144878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono if (entry.opened) { 145878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono throw new ErrnoException("onOpen", OsConstants.EMFILE); 146878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 147878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono entry.opened = true; 148878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono // Use inode as file handle. It's OK because AppFuse does not allow to open the same 149878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono // file twice. 150878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono return (int) inode; 151878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } catch (ErrnoException exp) { 1529fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return getError(exp); 153878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 154878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 155878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 156878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 157878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono // Called by JNI. 158878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @SuppressWarnings("unused") 159878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private int onFsync(long inode) { 160878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono synchronized(mLock) { 161878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono try { 162878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono getCallbackEntryOrThrowLocked(inode).callback.onFsync(); 163878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono return 0; 164878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } catch (ErrnoException exp) { 1659fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return getError(exp); 166878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 167878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 168878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 169878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 170878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono // Called by JNI. 171878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @SuppressWarnings("unused") 172878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private int onRelease(long inode) { 173878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono synchronized(mLock) { 1749fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono try { 1759fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono getCallbackEntryOrThrowLocked(inode).callback.onRelease(); 1769fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return 0; 1779fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } catch (ErrnoException exp) { 1789fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return getError(exp); 1799fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } finally { 1809fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono mCallbackMap.remove(checkInode(inode)); 181878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 182878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 183878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 184878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 185878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono // Called by JNI. 186878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @SuppressWarnings("unused") 187878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private int onRead(long inode, long offset, int size, byte[] bytes) { 188878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono synchronized(mLock) { 189878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono try { 190878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono return getCallbackEntryOrThrowLocked(inode).callback.onRead(offset, size, bytes); 191878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } catch (ErrnoException exp) { 1929fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return getError(exp); 193878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 194878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 195878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 196878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 197878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono // Called by JNI. 198878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @SuppressWarnings("unused") 199878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private int onWrite(long inode, long offset, int size, byte[] bytes) { 200878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono synchronized(mLock) { 201878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono try { 202878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono return getCallbackEntryOrThrowLocked(inode).callback.onWrite(offset, size, bytes); 203878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } catch (ErrnoException exp) { 2049fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return getError(exp); 205878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 206878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 207878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 208878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 2099fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono private static int getError(@NonNull ErrnoException exp) { 2109fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono // Should not return ENOSYS because the kernel stops 2119fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono // dispatching the FUSE action once FUSE implementation returns ENOSYS for the action. 2129fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return exp.errno != OsConstants.ENOSYS ? -exp.errno : -OsConstants.EIO; 2139fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } 2149fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono 215878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono native boolean native_start_loop(int fd); 216878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 217878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private static int checkInode(long inode) { 218878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono Preconditions.checkArgumentInRange(inode, MIN_INODE, Integer.MAX_VALUE, "checkInode"); 219878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono return (int) inode; 220878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 221878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 222878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono public static class UnmountedException extends Exception {} 223878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 224878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private static class CallbackEntry { 2259fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono final ProxyFileDescriptorCallback callback; 226878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono boolean opened; 2279fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono CallbackEntry(ProxyFileDescriptorCallback callback) { 228878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono Preconditions.checkNotNull(callback); 229878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono this.callback = callback; 230878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 231878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 232878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono} 233