199a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes/*
299a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes * Copyright (C) 2010 The Android Open Source Project
399a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes *
499a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
599a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes * you may not use this file except in compliance with the License.
699a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes * You may obtain a copy of the License at
799a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes *
899a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
999a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes *
1099a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes * Unless required by applicable law or agreed to in writing, software
1199a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
1299a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1399a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes * See the License for the specific language governing permissions and
1499a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes * limitations under the License.
1599a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes */
1699a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes
1799a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughespackage libcore.io;
1899a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes
19433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilsonimport java.io.File;
2099a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughesimport java.io.FileDescriptor;
21c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamathimport java.io.FileNotFoundException;
2299a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughesimport java.io.IOException;
239726be51ed6f9695357bc8f11a547d9beaa79fceBrian Carlstromimport java.io.InterruptedIOException;
24a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilsonimport java.net.Socket;
25c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamathimport java.nio.charset.Charset;
262a6f23ff8690ac2f025588a360547ce96cde0943Elliott Hughesimport java.nio.charset.StandardCharsets;
274f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughesimport java.util.Random;
280ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughesimport static libcore.io.OsConstants.*;
2999a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes
3099a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughespublic final class IoUtils {
314f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes    private static final Random TEMPORARY_DIRECTORY_PRNG = new Random();
324f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes
3399a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes    private IoUtils() {
3499a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes    }
3599a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes
3699a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes    /**
37e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes     * Calls close(2) on 'fd'. Also resets the internal int to -1. Does nothing if 'fd' is null
38e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes     * or invalid.
3999a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes     */
40462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    public static void close(FileDescriptor fd) throws IOException {
41462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes        try {
42462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes            if (fd != null && fd.valid()) {
43462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes                Libcore.os.close(fd);
44462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes            }
45462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes        } catch (ErrnoException errnoException) {
46462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes            throw errnoException.rethrowAsIOException();
47462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes        }
48462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    }
4999a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes
5099a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes    /**
519b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes     * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null.
52f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes     */
539b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes    public static void closeQuietly(AutoCloseable closeable) {
54f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes        if (closeable != null) {
55f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes            try {
56f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes                closeable.close();
579b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes            } catch (RuntimeException rethrown) {
589b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes                throw rethrown;
599b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes            } catch (Exception ignored) {
60f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes            }
61f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes        }
62f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes    }
63f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes
64f14cadb15b06371fb9a6daf885dc1c4bccf975b9Elliott Hughes    /**
65e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes     * Closes 'fd', ignoring any exceptions. Does nothing if 'fd' is null or invalid.
66e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes     */
67e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes    public static void closeQuietly(FileDescriptor fd) {
68e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes        try {
69e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes            IoUtils.close(fd);
70e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes        } catch (IOException ignored) {
71e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes        }
72e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes    }
73e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes
74e8fad0e2a8787fd46654d1cc9e477b353a958451Elliott Hughes    /**
75a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson     * Closes 'socket', ignoring any exceptions. Does nothing if 'socket' is null.
76a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson     */
77a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson    public static void closeQuietly(Socket socket) {
78a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson        if (socket != null) {
79a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson            try {
80a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson                socket.close();
81a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson            } catch (Exception ignored) {
82a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson            }
83a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson        }
84a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson    }
85a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson
86220c0af1763283b75617226efe3919c3e3b044c8Elliott Hughes    /**
87440ba565fa5384bc23255fbc412f7b97fcbdccd9Elliott Hughes     * Sets 'fd' to be blocking or non-blocking, according to the state of 'blocking'.
8899a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes     */
89fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    public static void setBlocking(FileDescriptor fd, boolean blocking) throws IOException {
90fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        try {
91fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes            int flags = Libcore.os.fcntlVoid(fd, F_GETFL);
92fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes            if (!blocking) {
93fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes                flags |= O_NONBLOCK;
94fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes            } else {
95fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes                flags &= ~O_NONBLOCK;
96fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes            }
97fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes            Libcore.os.fcntlLong(fd, F_SETFL, flags);
98fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        } catch (ErrnoException errnoException) {
99fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes            throw errnoException.rethrowAsIOException();
100fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        }
101fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    }
102bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes
1030a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    /**
104bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes     * Returns the contents of 'path' as a byte array.
105bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes     */
106c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath    public static byte[] readFileAsByteArray(String absolutePath) throws IOException {
107c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        return new FileReader(absolutePath).readFully().toByteArray();
108a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    }
109a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes
110a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    /**
111a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes     * Returns the contents of 'path' as a string. The contents are assumed to be UTF-8.
112a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes     */
113c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath    public static String readFileAsString(String absolutePath) throws IOException {
114c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        return new FileReader(absolutePath).readFully().toString(StandardCharsets.UTF_8);
115bffb058e565a97f838247f1e092b0d17b26cb68eElliott Hughes    }
116433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson
117433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson    /**
1184f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     * Do not use. Use createTemporaryDirectory instead.
1194f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     *
1204f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     * Used by frameworks/base unit tests to clean up a temporary directory.
1214f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     * Deliberately ignores errors, on the assumption that test cleanup is only
1224f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     * supposed to be best-effort.
1234f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     *
12499b4489d0555c6e0e5df941cbfad4cf250c8f0b8Elliott Hughes     * @deprecated Use {@link #createTemporaryDirectory} instead.
1257653089cb7609f6269aecd68e839c40941cb1a46Elliott Hughes     */
1267653089cb7609f6269aecd68e839c40941cb1a46Elliott Hughes    public static void deleteContents(File dir) throws IOException {
1277653089cb7609f6269aecd68e839c40941cb1a46Elliott Hughes        File[] files = dir.listFiles();
1284f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes        if (files != null) {
1294f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes            for (File file : files) {
1304f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes                if (file.isDirectory()) {
1314f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes                    deleteContents(file);
1324f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes                }
1334f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes                file.delete();
1347653089cb7609f6269aecd68e839c40941cb1a46Elliott Hughes            }
1354f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes        }
1364f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes    }
1374f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes
1384f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes    /**
1394f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     * Creates a unique new temporary directory under "java.io.tmpdir".
1404f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     */
1414f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes    public static File createTemporaryDirectory(String prefix) {
1424f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes        while (true) {
1434f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes            String candidateName = prefix + TEMPORARY_DIRECTORY_PRNG.nextInt();
1444f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes            File result = new File(System.getProperty("java.io.tmpdir"), candidateName);
1454f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes            if (result.mkdir()) {
1464f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes                return result;
1477653089cb7609f6269aecd68e839c40941cb1a46Elliott Hughes            }
1487653089cb7609f6269aecd68e839c40941cb1a46Elliott Hughes        }
1497653089cb7609f6269aecd68e839c40941cb1a46Elliott Hughes    }
1507653089cb7609f6269aecd68e839c40941cb1a46Elliott Hughes
1517653089cb7609f6269aecd68e839c40941cb1a46Elliott Hughes    /**
1524f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     * Do not use. This is for System.loadLibrary use only.
1534f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     *
1546d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes     * Checks whether {@code path} can be opened read-only. Similar to File.exists, but doesn't
1556d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes     * require read permission on the parent, so it'll work in more cases, and allow you to
1564f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     * remove read permission from more directories. Everyone else should just open(2) and then
1574f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     * use the fd, but the loadLibrary API is broken by its need to ask ClassLoaders where to
1584f97bfe0d9e6f4bdb43fff91f341f4722af16301Elliott Hughes     * find a .so rather than just calling dlopen(3).
1596d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes     */
1606d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes    public static boolean canOpenReadOnly(String path) {
1616d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes        try {
1626d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes            // Use open(2) rather than stat(2) so we require fewer permissions. http://b/6485312.
1636d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes            FileDescriptor fd = Libcore.os.open(path, O_RDONLY, 0);
1646d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes            Libcore.os.close(fd);
1656d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes            return true;
1666d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes        } catch (ErrnoException errnoException) {
1676d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes            return false;
1686d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes        }
1696d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes    }
1706d17baa25d349e2659eb16fe5eef3088d48e5e22Elliott Hughes
1719726be51ed6f9695357bc8f11a547d9beaa79fceBrian Carlstrom    public static void throwInterruptedIoException() throws InterruptedIOException {
1729726be51ed6f9695357bc8f11a547d9beaa79fceBrian Carlstrom        // This is typically thrown in response to an
1739726be51ed6f9695357bc8f11a547d9beaa79fceBrian Carlstrom        // InterruptedException which does not leave the thread in an
1749726be51ed6f9695357bc8f11a547d9beaa79fceBrian Carlstrom        // interrupted state, so explicitly interrupt here.
1759726be51ed6f9695357bc8f11a547d9beaa79fceBrian Carlstrom        Thread.currentThread().interrupt();
1769726be51ed6f9695357bc8f11a547d9beaa79fceBrian Carlstrom        // TODO: set InterruptedIOException.bytesTransferred
1779726be51ed6f9695357bc8f11a547d9beaa79fceBrian Carlstrom        throw new InterruptedIOException();
1789726be51ed6f9695357bc8f11a547d9beaa79fceBrian Carlstrom    }
179c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath
180c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath    /**
181c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath     * A convenience class for reading the contents of a file into a {@code String}
182c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath     * or a {@code byte[]}. This class attempts to minimize the number of allocations
183c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath     * and copies required to read this data.
184c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath     *
185c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath     * For the case where we know the "true" length of a file (most ordinary files)
186c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath     * we allocate exactly one byte[] and copy data into that. Calls to
187c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath     * {@link #toByteArray} will then return the internal array and <b>not</b> a copy.
188c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath     *
189c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath     * <b>Note that an absolute path must be supplied. Expect your reads to fail
190c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath     * if one isn't.</b>
191c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath     */
192c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath    private static class FileReader {
193c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        private FileDescriptor fd;
194c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        private boolean unknownLength;
195c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath
196c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        private byte[] bytes;
197c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        private int count;
198c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath
199c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        public FileReader(String absolutePath) throws IOException {
200c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            // We use IoBridge.open because callers might differentiate
201c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            // between a FileNotFoundException and a general IOException.
202c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            //
203c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            // NOTE: This costs us an additional call to fstat(2) to test whether
204c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            // "absolutePath" is a directory or not. We can eliminate it
205c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            // at the cost of copying some code from IoBridge.open.
206c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            try {
207c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                fd = IoBridge.open(absolutePath, O_RDONLY);
208c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            } catch (FileNotFoundException fnfe) {
209c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                throw fnfe;
210c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            }
211c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath
212c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            int capacity;
213c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            try {
214c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                final StructStat stat = Libcore.os.fstat(fd);
215c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                // Like RAF & other APIs, we assume that the file size fits
216c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                // into a 32 bit integer.
217c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                capacity = (int) stat.st_size;
218c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                if (capacity == 0) {
219c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                    unknownLength = true;
220c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                    capacity = 8192;
221c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                }
222c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            } catch (ErrnoException exception) {
223c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                closeQuietly(fd);
224c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                throw exception.rethrowAsIOException();
225c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            }
226c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath
227c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            bytes = new byte[capacity];
228c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        }
229c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath
230c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        public FileReader readFully() throws IOException {
231c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            int read;
232c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            int capacity = bytes.length;
233c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            try {
234c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                while ((read = Libcore.os.read(fd, bytes, count, capacity - count)) != 0) {
235c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                    count += read;
236c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                    if (count == capacity) {
237c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                        if (unknownLength) {
238c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                            // If we don't know the length of this file, we need to continue
239c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                            // reading until we reach EOF. Double the capacity in preparation.
240c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                            final int newCapacity = capacity * 2;
241c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                            byte[] newBytes = new byte[newCapacity];
242c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                            System.arraycopy(bytes, 0, newBytes, 0, capacity);
243c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                            bytes = newBytes;
244c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                            capacity = newCapacity;
245c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                        } else {
246c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                            // We know the length of this file and we've read the right number
247c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                            // of bytes from it, return.
248c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                            break;
249c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                        }
250c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                    }
251c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                }
252c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath
253c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                return this;
254c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            } catch (ErrnoException e) {
255c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                throw e.rethrowAsIOException();
256c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            } finally {
257c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                closeQuietly(fd);
258c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            }
259c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        }
260c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath
261c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        @FindBugsSuppressWarnings("EI_EXPOSE_REP")
262c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        public byte[] toByteArray() {
263c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            if (count == bytes.length) {
264c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath                return bytes;
265c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            }
266c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            byte[] result = new byte[count];
267c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            System.arraycopy(bytes, 0, result, 0, count);
268c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            return result;
269c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        }
270c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath
271c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        public String toString(Charset cs) {
272c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath            return new String(bytes, 0, count, cs);
273c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath        }
274c7b35cdea3d660c8d4b77e11fa0ef19f6ca17db9Narayan Kamath    }
27599a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes}
276