IoUtils.java revision 8b15dcc5890963edad4dfcf558cc16027c7985e5
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 17package libcore.io; 18 19import java.io.Closeable; 20import java.io.FileDescriptor; 21import java.io.FileNotFoundException; 22import java.io.IOException; 23import java.io.RandomAccessFile; 24import java.net.Socket; 25import java.util.Arrays; 26import libcore.util.MutableInt; 27import static libcore.io.OsConstants.*; 28 29public final class IoUtils { 30 private IoUtils() { 31 } 32 33 /** 34 * Implements java.io/java.net "available" semantics. 35 */ 36 public static int available(FileDescriptor fd) throws IOException { 37 try { 38 MutableInt available = new MutableInt(0); 39 int rc = Libcore.os.ioctlInt(fd, FIONREAD, available); 40 if (available.value < 0) { 41 // If the fd refers to a regular file, the result is the difference between 42 // the file size and the file position. This may be negative if the position 43 // is past the end of the file. If the fd refers to a special file masquerading 44 // as a regular file, the result may be negative because the special file 45 // may appear to have zero size and yet a previous read call may have 46 // read some amount of data and caused the file position to be advanced. 47 available.value = 0; 48 } 49 return available.value; 50 } catch (ErrnoException errnoException) { 51 if (errnoException.errno == ENOTTY) { 52 // The fd is unwilling to opine about its read buffer. 53 return 0; 54 } 55 throw errnoException.rethrowAsIOException(); 56 } 57 } 58 59 /** 60 * java.io only throws FileNotFoundException when opening files, regardless of what actually 61 * went wrong. Additionally, java.io is more restrictive than POSIX when it comes to opening 62 * directories: POSIX says read-only is okay, but java.io doesn't even allow that. We also 63 * have an Android-specific hack to alter the default permissions. 64 */ 65 public static FileDescriptor open(String path, int flags) throws FileNotFoundException { 66 FileDescriptor fd = null; 67 try { 68 // On Android, we don't want default permissions to allow global access. 69 int mode = ((flags & O_ACCMODE) == O_RDONLY) ? 0 : 0600; 70 fd = Libcore.os.open(path, flags, mode); 71 if (fd.valid()) { 72 // Posix open(2) fails with EISDIR only if you ask for write permission. 73 // Java disallows reading directories too. 74 boolean isDirectory = false; 75 if (S_ISDIR(Libcore.os.fstat(fd).st_mode)) { 76 throw new ErrnoException("open", EISDIR); 77 } 78 } 79 return fd; 80 } catch (ErrnoException errnoException) { 81 try { 82 if (fd != null) { 83 close(fd); 84 } 85 } catch (IOException ignored) { 86 } 87 FileNotFoundException ex = new FileNotFoundException(path + ": " + errnoException.getMessage()); 88 ex.initCause(errnoException); 89 throw ex; 90 } 91 } 92 93 /** 94 * java.io thinks that a read at EOF is an error and should return -1, contrary to traditional 95 * Unix practice where you'd read until you got 0 bytes (and any future read would return -1). 96 */ 97 public static int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException { 98 Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount); 99 if (byteCount == 0) { 100 return 0; 101 } 102 try { 103 int readCount = Libcore.os.read(fd, bytes, byteOffset, byteCount); 104 if (readCount == 0) { 105 return -1; 106 } 107 return readCount; 108 } catch (ErrnoException errnoException) { 109 if (errnoException.errno == EAGAIN) { 110 // We return 0 rather than throw if we try to read from an empty non-blocking pipe. 111 return 0; 112 } 113 throw errnoException.rethrowAsIOException(); 114 } 115 } 116 117 /** 118 * java.io always writes every byte it's asked to, or fails with an error. (That is, unlike 119 * Unix it never just writes as many bytes as happens to be convenient.) 120 */ 121 public static void write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException { 122 Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount); 123 if (byteCount == 0) { 124 return; 125 } 126 try { 127 while (byteCount > 0) { 128 int bytesWritten = Libcore.os.write(fd, bytes, byteOffset, byteCount); 129 byteCount -= bytesWritten; 130 byteOffset += bytesWritten; 131 } 132 } catch (ErrnoException errnoException) { 133 throw errnoException.rethrowAsIOException(); 134 } 135 } 136 137 /** 138 * Calls close(2) on 'fd'. Also resets the internal int to -1. 139 */ 140 public static native void close(FileDescriptor fd) throws IOException; 141 142 /** 143 * Closes 'closeable', ignoring any exceptions. Does nothing if 'closeable' is null. 144 */ 145 public static void closeQuietly(Closeable closeable) { 146 if (closeable != null) { 147 try { 148 closeable.close(); 149 } catch (IOException ignored) { 150 } 151 } 152 } 153 154 /** 155 * Closes 'socket', ignoring any exceptions. Does nothing if 'socket' is null. 156 */ 157 public static void closeQuietly(Socket socket) { 158 if (socket != null) { 159 try { 160 socket.close(); 161 } catch (Exception ignored) { 162 } 163 } 164 } 165 166 /** 167 * Returns the int file descriptor from within the given FileDescriptor 'fd'. 168 */ 169 public static native int getFd(FileDescriptor fd); 170 171 /** 172 * Sets 'fd' to be blocking or non-blocking, according to the state of 'blocking'. 173 */ 174 public static void setBlocking(FileDescriptor fd, boolean blocking) throws IOException { 175 try { 176 int flags = Libcore.os.fcntlVoid(fd, F_GETFL); 177 if (!blocking) { 178 flags |= O_NONBLOCK; 179 } else { 180 flags &= ~O_NONBLOCK; 181 } 182 Libcore.os.fcntlLong(fd, F_SETFL, flags); 183 } catch (ErrnoException errnoException) { 184 throw errnoException.rethrowAsIOException(); 185 } 186 } 187 188 /** 189 * Returns the contents of 'path' as a byte array. 190 */ 191 public static byte[] readFileAsByteArray(String path) throws IOException { 192 RandomAccessFile f = null; 193 try { 194 f = new RandomAccessFile(path, "r"); 195 byte[] buf = new byte[(int) f.length()]; 196 f.readFully(buf); 197 return buf; 198 } finally { 199 IoUtils.closeQuietly(f); 200 } 201 } 202} 203