Home | History | Annotate | Download | only in io
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.io;
     18 
     19 import android.system.ErrnoException;
     20 import android.system.StructStat;
     21 import java.io.File;
     22 import java.io.FileDescriptor;
     23 import java.io.FileNotFoundException;
     24 import java.io.IOException;
     25 import java.io.InterruptedIOException;
     26 import java.net.Socket;
     27 import java.nio.charset.Charset;
     28 import java.nio.charset.StandardCharsets;
     29 import java.util.Random;
     30 import static android.system.OsConstants.*;
     31 
     32 public final class IoUtils {
     33     private static final Random TEMPORARY_DIRECTORY_PRNG = new Random();
     34 
     35     private IoUtils() {
     36     }
     37 
     38     /**
     39      * Calls close(2) on 'fd'. Also resets the internal int to -1. Does nothing if 'fd' is null
     40      * or invalid.
     41      */
     42     public static void close(FileDescriptor fd) throws IOException {
     43         try {
     44             if (fd != null && fd.valid()) {
     45                 Libcore.os.close(fd);
     46             }
     47         } catch (ErrnoException errnoException) {
     48             throw errnoException.rethrowAsIOException();
     49         }
     50     }
     51 
     52     /**
     53      * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null.
     54      */
     55     public static void closeQuietly(AutoCloseable closeable) {
     56         if (closeable != null) {
     57             try {
     58                 closeable.close();
     59             } catch (RuntimeException rethrown) {
     60                 throw rethrown;
     61             } catch (Exception ignored) {
     62             }
     63         }
     64     }
     65 
     66     /**
     67      * Closes 'fd', ignoring any exceptions. Does nothing if 'fd' is null or invalid.
     68      */
     69     public static void closeQuietly(FileDescriptor fd) {
     70         try {
     71             IoUtils.close(fd);
     72         } catch (IOException ignored) {
     73         }
     74     }
     75 
     76     /**
     77      * Closes 'socket', ignoring any exceptions. Does nothing if 'socket' is null.
     78      */
     79     public static void closeQuietly(Socket socket) {
     80         if (socket != null) {
     81             try {
     82                 socket.close();
     83             } catch (Exception ignored) {
     84             }
     85         }
     86     }
     87 
     88     /**
     89      * Sets 'fd' to be blocking or non-blocking, according to the state of 'blocking'.
     90      */
     91     public static void setBlocking(FileDescriptor fd, boolean blocking) throws IOException {
     92         try {
     93             int flags = Libcore.os.fcntlVoid(fd, F_GETFL);
     94             if (!blocking) {
     95                 flags |= O_NONBLOCK;
     96             } else {
     97                 flags &= ~O_NONBLOCK;
     98             }
     99             Libcore.os.fcntlLong(fd, F_SETFL, flags);
    100         } catch (ErrnoException errnoException) {
    101             throw errnoException.rethrowAsIOException();
    102         }
    103     }
    104 
    105     /**
    106      * Returns the contents of 'path' as a byte array.
    107      */
    108     public static byte[] readFileAsByteArray(String absolutePath) throws IOException {
    109         return new FileReader(absolutePath).readFully().toByteArray();
    110     }
    111 
    112     /**
    113      * Returns the contents of 'path' as a string. The contents are assumed to be UTF-8.
    114      */
    115     public static String readFileAsString(String absolutePath) throws IOException {
    116         return new FileReader(absolutePath).readFully().toString(StandardCharsets.UTF_8);
    117     }
    118 
    119     /**
    120      * Do not use. Use createTemporaryDirectory instead.
    121      *
    122      * Used by frameworks/base unit tests to clean up a temporary directory.
    123      * Deliberately ignores errors, on the assumption that test cleanup is only
    124      * supposed to be best-effort.
    125      *
    126      * @deprecated Use {@link #createTemporaryDirectory} instead.
    127      */
    128     public static void deleteContents(File dir) throws IOException {
    129         File[] files = dir.listFiles();
    130         if (files != null) {
    131             for (File file : files) {
    132                 if (file.isDirectory()) {
    133                     deleteContents(file);
    134                 }
    135                 file.delete();
    136             }
    137         }
    138     }
    139 
    140     /**
    141      * Creates a unique new temporary directory under "java.io.tmpdir".
    142      */
    143     public static File createTemporaryDirectory(String prefix) {
    144         while (true) {
    145             String candidateName = prefix + TEMPORARY_DIRECTORY_PRNG.nextInt();
    146             File result = new File(System.getProperty("java.io.tmpdir"), candidateName);
    147             if (result.mkdir()) {
    148                 return result;
    149             }
    150         }
    151     }
    152 
    153     /**
    154      * Do not use. This is for System.loadLibrary use only.
    155      *
    156      * Checks whether {@code path} can be opened read-only. Similar to File.exists, but doesn't
    157      * require read permission on the parent, so it'll work in more cases, and allow you to
    158      * remove read permission from more directories. Everyone else should just open(2) and then
    159      * use the fd, but the loadLibrary API is broken by its need to ask ClassLoaders where to
    160      * find a .so rather than just calling dlopen(3).
    161      */
    162     public static boolean canOpenReadOnly(String path) {
    163         try {
    164             // Use open(2) rather than stat(2) so we require fewer permissions. http://b/6485312.
    165             FileDescriptor fd = Libcore.os.open(path, O_RDONLY, 0);
    166             Libcore.os.close(fd);
    167             return true;
    168         } catch (ErrnoException errnoException) {
    169             return false;
    170         }
    171     }
    172 
    173     public static void throwInterruptedIoException() throws InterruptedIOException {
    174         // This is typically thrown in response to an
    175         // InterruptedException which does not leave the thread in an
    176         // interrupted state, so explicitly interrupt here.
    177         Thread.currentThread().interrupt();
    178         // TODO: set InterruptedIOException.bytesTransferred
    179         throw new InterruptedIOException();
    180     }
    181 
    182     /**
    183      * A convenience class for reading the contents of a file into a {@code String}
    184      * or a {@code byte[]}. This class attempts to minimize the number of allocations
    185      * and copies required to read this data.
    186      *
    187      * For the case where we know the "true" length of a file (most ordinary files)
    188      * we allocate exactly one byte[] and copy data into that. Calls to
    189      * {@link #toByteArray} will then return the internal array and <b>not</b> a copy.
    190      *
    191      * <b>Note that an absolute path must be supplied. Expect your reads to fail
    192      * if one isn't.</b>
    193      */
    194     private static class FileReader {
    195         private FileDescriptor fd;
    196         private boolean unknownLength;
    197 
    198         private byte[] bytes;
    199         private int count;
    200 
    201         public FileReader(String absolutePath) throws IOException {
    202             // We use IoBridge.open because callers might differentiate
    203             // between a FileNotFoundException and a general IOException.
    204             //
    205             // NOTE: This costs us an additional call to fstat(2) to test whether
    206             // "absolutePath" is a directory or not. We can eliminate it
    207             // at the cost of copying some code from IoBridge.open.
    208             try {
    209                 fd = IoBridge.open(absolutePath, O_RDONLY);
    210             } catch (FileNotFoundException fnfe) {
    211                 throw fnfe;
    212             }
    213 
    214             int capacity;
    215             try {
    216                 final StructStat stat = Libcore.os.fstat(fd);
    217                 // Like RAF & other APIs, we assume that the file size fits
    218                 // into a 32 bit integer.
    219                 capacity = (int) stat.st_size;
    220                 if (capacity == 0) {
    221                     unknownLength = true;
    222                     capacity = 8192;
    223                 }
    224             } catch (ErrnoException exception) {
    225                 closeQuietly(fd);
    226                 throw exception.rethrowAsIOException();
    227             }
    228 
    229             bytes = new byte[capacity];
    230         }
    231 
    232         public FileReader readFully() throws IOException {
    233             int read;
    234             int capacity = bytes.length;
    235             try {
    236                 while ((read = Libcore.os.read(fd, bytes, count, capacity - count)) != 0) {
    237                     count += read;
    238                     if (count == capacity) {
    239                         if (unknownLength) {
    240                             // If we don't know the length of this file, we need to continue
    241                             // reading until we reach EOF. Double the capacity in preparation.
    242                             final int newCapacity = capacity * 2;
    243                             byte[] newBytes = new byte[newCapacity];
    244                             System.arraycopy(bytes, 0, newBytes, 0, capacity);
    245                             bytes = newBytes;
    246                             capacity = newCapacity;
    247                         } else {
    248                             // We know the length of this file and we've read the right number
    249                             // of bytes from it, return.
    250                             break;
    251                         }
    252                     }
    253                 }
    254 
    255                 return this;
    256             } catch (ErrnoException e) {
    257                 throw e.rethrowAsIOException();
    258             } finally {
    259                 closeQuietly(fd);
    260             }
    261         }
    262 
    263         @FindBugsSuppressWarnings("EI_EXPOSE_REP")
    264         public byte[] toByteArray() {
    265             if (count == bytes.length) {
    266                 return bytes;
    267             }
    268             byte[] result = new byte[count];
    269             System.arraycopy(bytes, 0, result, 0, count);
    270             return result;
    271         }
    272 
    273         public String toString(Charset cs) {
    274             return new String(bytes, 0, count, cs);
    275         }
    276     }
    277 }
    278