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