1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/* 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements. See the NOTICE file distributed with 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership. 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License. You may obtain a copy of the License at 8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License. 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 18ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughespackage java.nio; 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 205d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.ErrnoException; 215d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.StructFlock; 225d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.util.MutableLong; 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.Closeable; 24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileDescriptor; 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 268add3229ceb13f2aa5d15b84cc59f5ecc6b90214Neil Fullerimport java.nio.channels.ClosedByInterruptException; 27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.ClosedChannelException; 28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.FileChannel; 29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.FileLock; 308add3229ceb13f2aa5d15b84cc59f5ecc6b90214Neil Fullerimport java.nio.channels.FileLockInterruptionException; 316ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughesimport java.nio.channels.NonReadableChannelException; 32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.NonWritableChannelException; 33ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughesimport java.nio.channels.OverlappingFileLockException; 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.ReadableByteChannel; 35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.WritableByteChannel; 36a1603838fe9e865575c87982e32c6343740e464cElliott Hughesimport java.util.Arrays; 37ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughesimport java.util.Comparator; 38ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughesimport java.util.SortedSet; 39ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughesimport java.util.TreeSet; 4052724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughesimport libcore.io.Libcore; 415d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport static android.system.OsConstants.*; 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 436fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes/** 446fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes * Our concrete implementation of the abstract FileChannel class. 45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 466ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughesfinal class FileChannelImpl extends FileChannel { 47ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes private static final Comparator<FileLock> LOCK_COMPARATOR = new Comparator<FileLock>() { 48ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes public int compare(FileLock lock1, FileLock lock2) { 49ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes long position1 = lock1.position(); 50ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes long position2 = lock2.position(); 51ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes return position1 > position2 ? 1 : (position1 < position2 ? -1 : 0); 52ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 53ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes }; 54ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes 55f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller private final Closeable ioObject; 5652724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes private final FileDescriptor fd; 576ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes private final int mode; 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 59ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes // The set of acquired and pending locks. 60ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes private final SortedSet<FileLock> locks = new TreeSet<FileLock>(LOCK_COMPARATOR); 61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 62ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes /** 636ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes * Create a new file channel implementation class that wraps the given 646ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes * fd and operates in the specified mode. 65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 66f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller public FileChannelImpl(Closeable ioObject, FileDescriptor fd, int mode) { 676ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes this.fd = fd; 68f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller this.ioObject = ioObject; 696ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes this.mode = mode; 70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 726ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes private void checkOpen() throws ClosedChannelException { 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!isOpen()) { 74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project throw new ClosedChannelException(); 75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 786ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes private void checkReadable() { 796ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes if ((mode & O_ACCMODE) == O_WRONLY) { 806ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new NonReadableChannelException(); 816ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 826ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 836ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes 846ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes private void checkWritable() { 856ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes if ((mode & O_ACCMODE) == O_RDONLY) { 866ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new NonWritableChannelException(); 876ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 886ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 896ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes 90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected void implCloseChannel() throws IOException { 91f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller ioObject.close(); 92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 946ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes private FileLock basicLock(long position, long size, boolean shared, boolean wait) throws IOException { 956ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes int accessMode = (mode & O_ACCMODE); 966ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes if (accessMode == O_RDONLY) { 976ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes if (!shared) { 986ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new NonWritableChannelException(); 996ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 1006ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } else if (accessMode == O_WRONLY) { 1016ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes if (shared) { 1026ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new NonReadableChannelException(); 1036ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 1046ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 1056ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes 10603c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes if (position < 0 || size < 0) { 1076ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new IllegalArgumentException("position=" + position + " size=" + size); 108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 109fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes 110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project FileLock pendingLock = new FileLockImpl(this, position, size, shared); 111ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes addLock(pendingLock); 112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 113fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes StructFlock flock = new StructFlock(); 114fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes flock.l_type = (short) (shared ? F_RDLCK : F_WRLCK); 115fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes flock.l_whence = (short) SEEK_SET; 116fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes flock.l_start = position; 117fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes flock.l_len = translateLockLength(size); 118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1199b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes boolean success = false; 1209b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes try { 1219b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes success = (Libcore.os.fcntlFlock(fd, wait ? F_SETLKW64 : F_SETLK64, flock) != -1); 1229b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes } catch (ErrnoException errnoException) { 1239b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes throw errnoException.rethrowAsIOException(); 1249b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes } finally { 1259b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes if (!success) { 1269b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes removeLock(pendingLock); 1279b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes } 1289b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes } 1299b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes return success ? pendingLock : null; 130fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes } 131fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes 132fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes private static long translateLockLength(long byteCount) { 133fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes // FileChannel uses Long.MAX_VALUE to mean "lock the whole file" where POSIX uses 0. 134fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes return (byteCount == Long.MAX_VALUE) ? 0 : byteCount; 135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 137ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes private static final class FileLockImpl extends FileLock { 138ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes private boolean isReleased = false; 139ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes 140ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes public FileLockImpl(FileChannel channel, long position, long size, boolean shared) { 141ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes super(channel, position, size, shared); 142ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 143ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes 1446ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes public boolean isValid() { 145ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes return !isReleased && channel().isOpen(); 146ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 147ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes 1486ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes public void release() throws IOException { 149ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes if (!channel().isOpen()) { 150ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes throw new ClosedChannelException(); 151ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 152ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes if (!isReleased) { 153ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes ((FileChannelImpl) channel()).release(this); 154ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes isReleased = true; 155ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 156ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 157ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 158ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes 159ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes public final FileLock lock(long position, long size, boolean shared) throws IOException { 1606ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project FileLock resultLock = null; 162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project { 163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project boolean completed = false; 164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project begin(); 166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project resultLock = basicLock(position, size, shared, true); 167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project completed = true; 168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } finally { 1698add3229ceb13f2aa5d15b84cc59f5ecc6b90214Neil Fuller try { 1708add3229ceb13f2aa5d15b84cc59f5ecc6b90214Neil Fuller end(completed); 1718add3229ceb13f2aa5d15b84cc59f5ecc6b90214Neil Fuller } catch (ClosedByInterruptException e) { 1728add3229ceb13f2aa5d15b84cc59f5ecc6b90214Neil Fuller throw new FileLockInterruptionException(); 1738add3229ceb13f2aa5d15b84cc59f5ecc6b90214Neil Fuller } 174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return resultLock; 177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 179ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes public final FileLock tryLock(long position, long size, boolean shared) throws IOException { 1806ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return basicLock(position, size, shared, false); 182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 184ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes /** 185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Non-API method to release a given lock on a file channel. Assumes that 186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the lock will mark itself invalid after successful unlocking. 187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 1886ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes public void release(FileLock lock) throws IOException { 1896ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 190fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes 191fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes StructFlock flock = new StructFlock(); 192fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes flock.l_type = (short) F_UNLCK; 193fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes flock.l_whence = (short) SEEK_SET; 194fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes flock.l_start = lock.position(); 195fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes flock.l_len = translateLockLength(lock.size()); 196fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes try { 197fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes Libcore.os.fcntlFlock(fd, F_SETLKW64, flock); 198fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes } catch (ErrnoException errnoException) { 199fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes throw errnoException.rethrowAsIOException(); 200fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes } 201fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes 202ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes removeLock(lock); 203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 2056ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes public void force(boolean metadata) throws IOException { 2066ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 2076ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes if ((mode & O_ACCMODE) != O_RDONLY) { 20852724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes try { 20952724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes if (metadata) { 21052724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes Libcore.os.fsync(fd); 21152724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes } else { 21252724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes Libcore.os.fdatasync(fd); 21352724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes } 21452724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes } catch (ErrnoException errnoException) { 215f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes throw errnoException.rethrowAsIOException(); 21652724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes } 2176ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 2206ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes public final MappedByteBuffer map(MapMode mapMode, long position, long size) throws IOException { 2216ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 2226ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes if (mapMode == null) { 2236ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new NullPointerException("mapMode == null"); 2246ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 2256ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes if (position < 0 || size < 0 || size > Integer.MAX_VALUE) { 2266ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new IllegalArgumentException("position=" + position + " size=" + size); 2276ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 2286ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes int accessMode = (mode & O_ACCMODE); 2296ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes if (accessMode == O_RDONLY) { 2306ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes if (mapMode != MapMode.READ_ONLY) { 2316ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new NonWritableChannelException(); 2326ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 2336ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } else if (accessMode == O_WRONLY) { 2346ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new NonReadableChannelException(); 2356ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes } 236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (position + size > size()) { 237c03e4ba8cd93513aabda061b00d516b54717c5fbElliott Hughes // We can't defer to FileChannel.truncate because that will only make a file shorter, 238c03e4ba8cd93513aabda061b00d516b54717c5fbElliott Hughes // and we only care about making our backing file longer here. 239c03e4ba8cd93513aabda061b00d516b54717c5fbElliott Hughes try { 240c03e4ba8cd93513aabda061b00d516b54717c5fbElliott Hughes Libcore.os.ftruncate(fd, position + size); 241105a9405b2e059352185f9ca1138cc8480ccb9bcElliott Hughes } catch (ErrnoException ftruncateException) { 242385c6f4303341beb9b091b6d252811b7ca3b9f42Nick Kralevich // EINVAL can be thrown if we're dealing with non-regular 243385c6f4303341beb9b091b6d252811b7ca3b9f42Nick Kralevich // files, for example, character devices such as /dev/zero. 244385c6f4303341beb9b091b6d252811b7ca3b9f42Nick Kralevich // In those cases, we ignore the failed truncation and 245385c6f4303341beb9b091b6d252811b7ca3b9f42Nick Kralevich // continue on. 246105a9405b2e059352185f9ca1138cc8480ccb9bcElliott Hughes try { 247105a9405b2e059352185f9ca1138cc8480ccb9bcElliott Hughes if (S_ISREG(Libcore.os.fstat(fd).st_mode) || ftruncateException.errno != EINVAL) { 248105a9405b2e059352185f9ca1138cc8480ccb9bcElliott Hughes throw ftruncateException.rethrowAsIOException(); 249105a9405b2e059352185f9ca1138cc8480ccb9bcElliott Hughes } 250105a9405b2e059352185f9ca1138cc8480ccb9bcElliott Hughes } catch (ErrnoException fstatException) { 251105a9405b2e059352185f9ca1138cc8480ccb9bcElliott Hughes throw fstatException.rethrowAsIOException(); 252385c6f4303341beb9b091b6d252811b7ca3b9f42Nick Kralevich } 253c03e4ba8cd93513aabda061b00d516b54717c5fbElliott Hughes } 254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 2556fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes long alignment = position - position % Libcore.os.sysconf(_SC_PAGE_SIZE); 256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int offset = (int) (position - alignment); 2577e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes MemoryBlock block = MemoryBlock.mmap(fd, alignment, size + offset, mapMode); 258fe5da19e0e366286cd4d95f7628fe9442b9062c8Elliott Hughes return new DirectByteBuffer(block, (int) size, offset, (mapMode == MapMode.READ_ONLY), mapMode); 259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public long position() throws IOException { 2626ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 263dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes try { 264dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes return Libcore.os.lseek(fd, 0L, SEEK_CUR); 265dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes } catch (ErrnoException errnoException) { 266dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes throw errnoException.rethrowAsIOException(); 267dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes } 268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public FileChannel position(long newPosition) throws IOException { 2716ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (newPosition < 0) { 2736ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new IllegalArgumentException("position: " + newPosition); 274eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson } 275e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes try { 276e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes Libcore.os.lseek(fd, newPosition, SEEK_SET); 277e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } catch (ErrnoException errnoException) { 278e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes throw errnoException.rethrowAsIOException(); 279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return this; 281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int read(ByteBuffer buffer, long position) throws IOException { 284eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson if (position < 0) { 2856ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new IllegalArgumentException("position: " + position); 286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 287e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes return readImpl(buffer, position); 288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int read(ByteBuffer buffer) throws IOException { 291e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes return readImpl(buffer, -1); 292e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } 293e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes 294e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes private int readImpl(ByteBuffer buffer, long position) throws IOException { 295e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes buffer.checkWritable(); 2966ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 2976ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkReadable(); 298eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson if (!buffer.hasRemaining()) { 299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return 0; 300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 301e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes int bytesRead = 0; 302e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes boolean completed = false; 303e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes try { 304e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes begin(); 30526c7025a7a919044771fb89031161bd26fe03032Elliott Hughes try { 306e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes if (position == -1) { 30726c7025a7a919044771fb89031161bd26fe03032Elliott Hughes bytesRead = Libcore.os.read(fd, buffer); 308e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } else { 309e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes bytesRead = Libcore.os.pread(fd, buffer, position); 310e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } 311e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes if (bytesRead == 0) { 312e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes bytesRead = -1; 313e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } 314e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } catch (ErrnoException errnoException) { 315e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes if (errnoException.errno == EAGAIN) { 316e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes // We don't throw if we try to read from an empty non-blocking pipe. 317e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes bytesRead = 0; 318e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } else { 319e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes throw errnoException.rethrowAsIOException(); 320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 322e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes completed = true; 323e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } finally { 324e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes end(completed && bytesRead >= 0); 325e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } 326f3b61eaf1931ae8393e54202a717334a4971ebdfNarayan Kamath 327e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes return bytesRead; 328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 330bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes private int transferIoVec(IoVec ioVec) throws IOException { 331bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes if (ioVec.init() == 0) { 332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return 0; 333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 334bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes int bytesTransferred = 0; 335bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes boolean completed = false; 336bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes try { 337bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes begin(); 338e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes bytesTransferred = ioVec.doTransfer(fd); 339bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes completed = true; 340bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes } finally { 341bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes end(completed); 342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 343bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes ioVec.didTransfer(bytesTransferred); 344bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes return bytesTransferred; 345bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes } 346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 347bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes public long read(ByteBuffer[] buffers, int offset, int length) throws IOException { 348bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes Arrays.checkOffsetAndCount(buffers.length, offset, length); 349bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes checkOpen(); 350bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes checkReadable(); 351bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes return transferIoVec(new IoVec(buffers, offset, length, IoVec.Direction.READV)); 352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public long size() throws IOException { 3556ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 35647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes try { 35747cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes return Libcore.os.fstat(fd).st_size; 35847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes } catch (ErrnoException errnoException) { 359f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes throw errnoException.rethrowAsIOException(); 36047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes } 361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 3636ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException { 3646ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!src.isOpen()) { 366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project throw new ClosedChannelException(); 367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 3686ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkWritable(); 369eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson if (position < 0 || count < 0 || count > Integer.MAX_VALUE) { 3706ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new IllegalArgumentException("position=" + position + " count=" + count); 371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 372eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson if (position > size()) { 373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return 0; 374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 375eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson 376e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes // Although sendfile(2) originally supported writing to a regular file. 377e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes // In Linux 2.6 and later, it only supports writing to sockets. 378e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes 379e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes // If our source is a regular file, mmap(2) rather than reading. 380e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes // Callers should only be using transferFrom for large transfers, 381e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes // so the mmap(2) overhead isn't a concern. 382e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes if (src instanceof FileChannel) { 383e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes FileChannel fileSrc = (FileChannel) src; 384e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes long size = fileSrc.size(); 385e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes long filePosition = fileSrc.position(); 386e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes count = Math.min(count, size - filePosition); 387e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes ByteBuffer buffer = fileSrc.map(MapMode.READ_ONLY, filePosition, count); 388e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes try { 389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project fileSrc.position(filePosition + count); 390e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes return write(buffer, position); 391e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes } finally { 392e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes NioUtils.freeDirectBuffer(buffer); 393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 395e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes 396e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes // For non-file channels, all we can do is read and write via userspace. 397e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes ByteBuffer buffer = ByteBuffer.allocate((int) count); 398e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes src.read(buffer); 399e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes buffer.flip(); 400e3d7539b3cb1e763f1ed5832120684468e635d94Elliott Hughes return write(buffer, position); 401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 4032cff86c0c10588a35036fe5bbca83b07f53e1b1dElliott Hughes public long transferTo(long position, long count, WritableByteChannel target) throws IOException { 4046ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!target.isOpen()) { 406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project throw new ClosedChannelException(); 407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 4082cff86c0c10588a35036fe5bbca83b07f53e1b1dElliott Hughes checkReadable(); 4096ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes if (target instanceof FileChannelImpl) { 4106ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes ((FileChannelImpl) target).checkWritable(); 411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 412eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson if (position < 0 || count < 0) { 4136ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes throw new IllegalArgumentException("position=" + position + " count=" + count); 414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 415eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson 416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (count == 0 || position >= size()) { 417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return 0; 418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project count = Math.min(count, size() - position); 4208b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes 4218b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes // Try sendfile(2) first... 4228b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes boolean completed = false; 423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (target instanceof SocketChannelImpl) { 4248b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes FileDescriptor outFd = ((SocketChannelImpl) target).getFD(); 4258b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes try { 4268b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes begin(); 4278b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes try { 4288b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes MutableLong offset = new MutableLong(position); 4298b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes long rc = Libcore.os.sendfile(outFd, fd, offset, count); 4308b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes completed = true; 4318b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes return rc; 4328b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes } catch (ErrnoException errnoException) { 4338b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes // If the OS doesn't support what we asked for, we want to fall through and 4348b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes // try a different approach. If it does support it, but it failed, we're done. 4358b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes if (errnoException.errno != ENOSYS && errnoException.errno != EINVAL) { 4368b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes throw errnoException.rethrowAsIOException(); 4378b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes } 4388b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes } 4398b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes } finally { 4408b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes end(completed); 4418b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes } 442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 4438b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes // ...fall back to write(2). 4448b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes ByteBuffer buffer = null; 445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project buffer = map(MapMode.READ_ONLY, position, count); 447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return target.write(buffer); 448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } finally { 449c73a5be50cdd804ff3c12e7b43da08c33cdd6f21Elliott Hughes NioUtils.freeDirectBuffer(buffer); 450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public FileChannel truncate(long size) throws IOException { 4546ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (size < 0) { 456126ab1b546c71137a97cef68cc89267e7f7be634Elliott Hughes throw new IllegalArgumentException("size < 0: " + size); 457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 4586ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkWritable(); 459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (size < size()) { 460f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes try { 461f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes Libcore.os.ftruncate(fd, size); 462f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes } catch (ErrnoException errnoException) { 463f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes throw errnoException.rethrowAsIOException(); 464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 466a990ad5c834bd3292f8f4c5e45c7ff117ffae5ecNeil Fuller if (position() > size) { 467a990ad5c834bd3292f8f4c5e45c7ff117ffae5ecNeil Fuller position(size); 468a990ad5c834bd3292f8f4c5e45c7ff117ffae5ecNeil Fuller } 469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return this; 470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int write(ByteBuffer buffer, long position) throws IOException { 473eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson if (position < 0) { 474126ab1b546c71137a97cef68cc89267e7f7be634Elliott Hughes throw new IllegalArgumentException("position < 0: " + position); 475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 476e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes return writeImpl(buffer, position); 477e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } 478e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes 479e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes public int write(ByteBuffer buffer) throws IOException { 480e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes return writeImpl(buffer, -1); 481e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } 482e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes 483e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes private int writeImpl(ByteBuffer buffer, long position) throws IOException { 4846ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 4856ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkWritable(); 486e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes if (buffer == null) { 487e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes throw new NullPointerException("buffer == null"); 488e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } 489eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson if (!buffer.hasRemaining()) { 490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return 0; 491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int bytesWritten = 0; 493e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes boolean completed = false; 494e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes try { 495e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes begin(); 49678c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes try { 497e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes if (position == -1) { 49878c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes bytesWritten = Libcore.os.write(fd, buffer); 499e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } else { 500e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes bytesWritten = Libcore.os.pwrite(fd, buffer, position); 501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 502e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } catch (ErrnoException errnoException) { 503e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes throw errnoException.rethrowAsIOException(); 504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 505e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes completed = true; 506e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes } finally { 507e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes end(completed); 508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 509e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes return bytesWritten; 510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5122620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes public long write(ByteBuffer[] buffers, int offset, int length) throws IOException { 513a1603838fe9e865575c87982e32c6343740e464cElliott Hughes Arrays.checkOffsetAndCount(buffers.length, offset, length); 5146ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkOpen(); 5156ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes checkWritable(); 516bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes return transferIoVec(new IoVec(buffers, offset, length, IoVec.Direction.WRITEV)); 517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 518eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson 5192620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes /** 5202620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes * @param copyingIn true if we're copying data into the buffers (typically 5212620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes * because the caller is a file/network read operation), false if we're 5222620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes * copying data out of the buffers (for a file/network write operation). 5232620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes */ 5242620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes static int calculateTotalRemaining(ByteBuffer[] buffers, int offset, int length, boolean copyingIn) { 525d85168bd730e513cb0bd561030da3f7ea5044725Elliott Hughes int count = 0; 526d85168bd730e513cb0bd561030da3f7ea5044725Elliott Hughes for (int i = offset; i < offset + length; ++i) { 527d85168bd730e513cb0bd561030da3f7ea5044725Elliott Hughes count += buffers[i].remaining(); 5282620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes if (copyingIn) { 529e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes buffers[i].checkWritable(); 5302620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes } 531d85168bd730e513cb0bd561030da3f7ea5044725Elliott Hughes } 532d85168bd730e513cb0bd561030da3f7ea5044725Elliott Hughes return count; 533d85168bd730e513cb0bd561030da3f7ea5044725Elliott Hughes } 534d85168bd730e513cb0bd561030da3f7ea5044725Elliott Hughes 53552724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes public FileDescriptor getFD() { 5366ab5999b58777725b4556e4d81bdec56b6d6c182Elliott Hughes return fd; 537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 538ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes 539ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes /** 540ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes * Add a new pending lock to the manager. Throws an exception if the lock 541ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes * would overlap an existing lock. Once the lock is acquired it remains in 542ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes * this set as an acquired lock. 543ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes */ 544ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes private synchronized void addLock(FileLock lock) throws OverlappingFileLockException { 545ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes long lockEnd = lock.position() + lock.size(); 546ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes for (FileLock existingLock : locks) { 547ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes if (existingLock.position() > lockEnd) { 548ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes // This, and all remaining locks, start beyond our end (so 549ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes // cannot overlap). 550ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes break; 551ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 552ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes if (existingLock.overlaps(lock.position(), lock.size())) { 553ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes throw new OverlappingFileLockException(); 554ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 555ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 556ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes locks.add(lock); 557ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 558ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes 559ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes /** 560ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes * Removes an acquired lock from the lock manager. If the lock did not exist 561ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes * in the lock manager the operation is a no-op. 562ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes */ 563ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes private synchronized void removeLock(FileLock lock) { 564ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes locks.remove(lock); 565ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughes } 566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 567