1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.io; 28 29 import static android.system.OsConstants.O_APPEND; 30 import static android.system.OsConstants.O_CREAT; 31 import static android.system.OsConstants.O_TRUNC; 32 import static android.system.OsConstants.O_WRONLY; 33 34 import java.nio.channels.FileChannel; 35 36 import dalvik.annotation.optimization.ReachabilitySensitive; 37 import dalvik.system.BlockGuard; 38 import dalvik.system.CloseGuard; 39 import sun.nio.ch.FileChannelImpl; 40 import libcore.io.IoBridge; 41 import libcore.io.IoTracker; 42 import libcore.io.IoUtils; 43 44 /** 45 * A file output stream is an output stream for writing data to a 46 * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not 47 * a file is available or may be created depends upon the underlying 48 * platform. Some platforms, in particular, allow a file to be opened 49 * for writing by only one <tt>FileOutputStream</tt> (or other 50 * file-writing object) at a time. In such situations the constructors in 51 * this class will fail if the file involved is already open. 52 * 53 * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes 54 * such as image data. For writing streams of characters, consider using 55 * <code>FileWriter</code>. 56 * 57 * @author Arthur van Hoff 58 * @see java.io.File 59 * @see java.io.FileDescriptor 60 * @see java.io.FileInputStream 61 * @see java.nio.file.Files#newOutputStream 62 * @since JDK1.0 63 */ 64 public 65 class FileOutputStream extends OutputStream 66 { 67 /** 68 * The system dependent file descriptor. 69 */ 70 // Android-added: @ReachabilitySensitive 71 @ReachabilitySensitive 72 private final FileDescriptor fd; 73 74 /** 75 * True if the file is opened for append. 76 */ 77 private final boolean append; 78 79 /** 80 * The associated channel, initialized lazily. 81 */ 82 private FileChannel channel; 83 84 /** 85 * The path of the referenced file 86 * (null if the stream is created with a file descriptor) 87 */ 88 private final String path; 89 90 private final Object closeLock = new Object(); 91 private volatile boolean closed = false; 92 93 // Android-added: CloseGuard support: Log if the stream is not closed. 94 @ReachabilitySensitive 95 private final CloseGuard guard = CloseGuard.get(); 96 97 // Android-added: Field for tracking whether the stream owns the underlying FileDescriptor. 98 private final boolean isFdOwner; 99 100 // Android-added: Tracking of unbuffered I/O. 101 private final IoTracker tracker = new IoTracker(); 102 103 /** 104 * Creates a file output stream to write to the file with the 105 * specified name. A new <code>FileDescriptor</code> object is 106 * created to represent this file connection. 107 * <p> 108 * First, if there is a security manager, its <code>checkWrite</code> 109 * method is called with <code>name</code> as its argument. 110 * <p> 111 * If the file exists but is a directory rather than a regular file, does 112 * not exist but cannot be created, or cannot be opened for any other 113 * reason then a <code>FileNotFoundException</code> is thrown. 114 * 115 * @param name the system-dependent filename 116 * @exception FileNotFoundException if the file exists but is a directory 117 * rather than a regular file, does not exist but cannot 118 * be created, or cannot be opened for any other reason 119 * @exception SecurityException if a security manager exists and its 120 * <code>checkWrite</code> method denies write access 121 * to the file. 122 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 123 */ FileOutputStream(String name)124 public FileOutputStream(String name) throws FileNotFoundException { 125 this(name != null ? new File(name) : null, false); 126 } 127 128 /** 129 * Creates a file output stream to write to the file with the specified 130 * name. If the second argument is <code>true</code>, then 131 * bytes will be written to the end of the file rather than the beginning. 132 * A new <code>FileDescriptor</code> object is created to represent this 133 * file connection. 134 * <p> 135 * First, if there is a security manager, its <code>checkWrite</code> 136 * method is called with <code>name</code> as its argument. 137 * <p> 138 * If the file exists but is a directory rather than a regular file, does 139 * not exist but cannot be created, or cannot be opened for any other 140 * reason then a <code>FileNotFoundException</code> is thrown. 141 * 142 * @param name the system-dependent file name 143 * @param append if <code>true</code>, then bytes will be written 144 * to the end of the file rather than the beginning 145 * @exception FileNotFoundException if the file exists but is a directory 146 * rather than a regular file, does not exist but cannot 147 * be created, or cannot be opened for any other reason. 148 * @exception SecurityException if a security manager exists and its 149 * <code>checkWrite</code> method denies write access 150 * to the file. 151 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 152 * @since JDK1.1 153 */ FileOutputStream(String name, boolean append)154 public FileOutputStream(String name, boolean append) 155 throws FileNotFoundException 156 { 157 this(name != null ? new File(name) : null, append); 158 } 159 160 /** 161 * Creates a file output stream to write to the file represented by 162 * the specified <code>File</code> object. A new 163 * <code>FileDescriptor</code> object is created to represent this 164 * file connection. 165 * <p> 166 * First, if there is a security manager, its <code>checkWrite</code> 167 * method is called with the path represented by the <code>file</code> 168 * argument as its argument. 169 * <p> 170 * If the file exists but is a directory rather than a regular file, does 171 * not exist but cannot be created, or cannot be opened for any other 172 * reason then a <code>FileNotFoundException</code> is thrown. 173 * 174 * @param file the file to be opened for writing. 175 * @exception FileNotFoundException if the file exists but is a directory 176 * rather than a regular file, does not exist but cannot 177 * be created, or cannot be opened for any other reason 178 * @exception SecurityException if a security manager exists and its 179 * <code>checkWrite</code> method denies write access 180 * to the file. 181 * @see java.io.File#getPath() 182 * @see java.lang.SecurityException 183 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 184 */ FileOutputStream(File file)185 public FileOutputStream(File file) throws FileNotFoundException { 186 this(file, false); 187 } 188 189 /** 190 * Creates a file output stream to write to the file represented by 191 * the specified <code>File</code> object. If the second argument is 192 * <code>true</code>, then bytes will be written to the end of the file 193 * rather than the beginning. A new <code>FileDescriptor</code> object is 194 * created to represent this file connection. 195 * <p> 196 * First, if there is a security manager, its <code>checkWrite</code> 197 * method is called with the path represented by the <code>file</code> 198 * argument as its argument. 199 * <p> 200 * If the file exists but is a directory rather than a regular file, does 201 * not exist but cannot be created, or cannot be opened for any other 202 * reason then a <code>FileNotFoundException</code> is thrown. 203 * 204 * @param file the file to be opened for writing. 205 * @param append if <code>true</code>, then bytes will be written 206 * to the end of the file rather than the beginning 207 * @exception FileNotFoundException if the file exists but is a directory 208 * rather than a regular file, does not exist but cannot 209 * be created, or cannot be opened for any other reason 210 * @exception SecurityException if a security manager exists and its 211 * <code>checkWrite</code> method denies write access 212 * to the file. 213 * @see java.io.File#getPath() 214 * @see java.lang.SecurityException 215 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 216 * @since 1.4 217 */ FileOutputStream(File file, boolean append)218 public FileOutputStream(File file, boolean append) 219 throws FileNotFoundException 220 { 221 String name = (file != null ? file.getPath() : null); 222 SecurityManager security = System.getSecurityManager(); 223 if (security != null) { 224 security.checkWrite(name); 225 } 226 if (name == null) { 227 throw new NullPointerException(); 228 } 229 if (file.isInvalid()) { 230 throw new FileNotFoundException("Invalid file path"); 231 } 232 // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic. 233 // http://b/111268862 234 // this.fd = new FileDescriptor(); 235 int flags = O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC); 236 this.fd = IoBridge.open(name, flags); 237 // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic. 238 239 // Android-changed: Tracking mechanism for FileDescriptor sharing. 240 // fd.attach(this); 241 this.isFdOwner = true; 242 243 this.append = append; 244 this.path = name; 245 246 // Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic. 247 // open(name, append); 248 249 // Android-added: File descriptor ownership tracking. 250 IoUtils.setFdOwner(this.fd, this); 251 252 // Android-added: CloseGuard support. 253 guard.open("close"); 254 } 255 256 // Android-removed: Documentation around SecurityException. Not thrown on Android. 257 // Android-changed: Added doc for the Android-specific file descriptor ownership. 258 /** 259 * Creates a file output stream to write to the specified file 260 * descriptor, which represents an existing connection to an actual 261 * file in the file system. 262 * <p> 263 * First, if there is a security manager, its <code>checkWrite</code> 264 * method is called with the file descriptor <code>fdObj</code> 265 * argument as its argument. 266 * <p> 267 * If <code>fdObj</code> is null then a <code>NullPointerException</code> 268 * is thrown. 269 * <p> 270 * This constructor does not throw an exception if <code>fdObj</code> 271 * is {@link java.io.FileDescriptor#valid() invalid}. 272 * However, if the methods are invoked on the resulting stream to attempt 273 * I/O on the stream, an <code>IOException</code> is thrown. 274 * <p> 275 * Android-specific warning: {@link #close()} method doesn't close the {@code fdObj} provided, 276 * because this object doesn't own the file descriptor, but the caller does. The caller can 277 * call {@link android.system.Os#close(FileDescriptor)} to close the fd. 278 * 279 * @param fdObj the file descriptor to be opened for writing 280 */ FileOutputStream(FileDescriptor fdObj)281 public FileOutputStream(FileDescriptor fdObj) { 282 // Android-changed: Delegate to added hidden constructor. 283 this(fdObj, false /* isOwner */); 284 } 285 286 // Android-added: Internal/hidden constructor for specifying FileDescriptor ownership. 287 // Android-removed: SecurityManager calls. 288 /** 289 * Internal constructor for {@code FileOutputStream} objects where the file descriptor 290 * is owned by this tream. 291 * 292 * @hide 293 */ FileOutputStream(FileDescriptor fdObj, boolean isFdOwner)294 public FileOutputStream(FileDescriptor fdObj, boolean isFdOwner) { 295 if (fdObj == null) { 296 // Android-changed: Improved NullPointerException message. 297 throw new NullPointerException("fdObj == null"); 298 } 299 300 this.fd = fdObj; 301 this.append = false; 302 this.path = null; 303 304 // Android-changed: FileDescriptor ownership tracking mechanism. 305 // fd.attach(this); 306 this.isFdOwner = isFdOwner; 307 if (isFdOwner) { 308 IoUtils.setFdOwner(this.fd, this); 309 } 310 } 311 312 // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic. 313 // http://b/112107427 314 /* 315 /** 316 * Opens a file, with the specified name, for overwriting or appending. 317 * @param name name of file to be opened 318 * @param append whether the file is to be opened in append mode 319 * 320 private native void open0(String name, boolean append) 321 throws FileNotFoundException; 322 323 // wrap native call to allow instrumentation 324 /** 325 * Opens a file, with the specified name, for overwriting or appending. 326 * @param name name of file to be opened 327 * @param append whether the file is to be opened in append mode 328 * 329 private void open(String name, boolean append) 330 throws FileNotFoundException { 331 open0(name, append); 332 } 333 */ 334 // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic. 335 336 // Android-removed: write(int, boolean), use IoBridge instead. 337 /* 338 /** 339 * Writes the specified byte to this file output stream. 340 * 341 * @param b the byte to be written. 342 * @param append {@code true} if the write operation first 343 * advances the position to the end of file 344 * 345 private native void write(int b, boolean append) throws IOException; 346 */ 347 348 /** 349 * Writes the specified byte to this file output stream. Implements 350 * the <code>write</code> method of <code>OutputStream</code>. 351 * 352 * @param b the byte to be written. 353 * @exception IOException if an I/O error occurs. 354 */ write(int b)355 public void write(int b) throws IOException { 356 // Android-changed: Write methods delegate to write(byte[],int,int) to share Android logic. 357 write(new byte[] { (byte) b }, 0, 1); 358 } 359 360 // Android-removed: Write methods delegate to write(byte[],int,int) to share Android logic. 361 /* 362 /** 363 * Writes a sub array as a sequence of bytes. 364 * @param b the data to be written 365 * @param off the start offset in the data 366 * @param len the number of bytes that are written 367 * @param append {@code true} to first advance the position to the 368 * end of file 369 * @exception IOException If an I/O error has occurred. 370 * 371 private native void writeBytes(byte b[], int off, int len, boolean append) 372 throws IOException; 373 */ 374 375 /** 376 * Writes <code>b.length</code> bytes from the specified byte array 377 * to this file output stream. 378 * 379 * @param b the data. 380 * @exception IOException if an I/O error occurs. 381 */ write(byte b[])382 public void write(byte b[]) throws IOException { 383 // Android-changed: Write methods delegate to write(byte[],int,int) to share Android logic. 384 write(b, 0, b.length); 385 } 386 387 /** 388 * Writes <code>len</code> bytes from the specified byte array 389 * starting at offset <code>off</code> to this file output stream. 390 * 391 * @param b the data. 392 * @param off the start offset in the data. 393 * @param len the number of bytes to write. 394 * @exception IOException if an I/O error occurs. 395 */ write(byte b[], int off, int len)396 public void write(byte b[], int off, int len) throws IOException { 397 // Android-added: close() check before I/O. 398 if (closed && len > 0) { 399 throw new IOException("Stream Closed"); 400 } 401 402 // Android-added: Tracking of unbuffered I/O. 403 tracker.trackIo(len, IoTracker.Mode.WRITE); 404 405 // Android-changed: Use IoBridge instead of calling native method. 406 IoBridge.write(fd, b, off, len); 407 } 408 409 /** 410 * Closes this file output stream and releases any system resources 411 * associated with this stream. This file output stream may no longer 412 * be used for writing bytes. 413 * 414 * <p> If this stream has an associated channel then the channel is closed 415 * as well. 416 * 417 * @exception IOException if an I/O error occurs. 418 * 419 * @revised 1.4 420 * @spec JSR-51 421 */ close()422 public void close() throws IOException { 423 synchronized (closeLock) { 424 if (closed) { 425 return; 426 } 427 closed = true; 428 } 429 430 // Android-added: CloseGuard support. 431 guard.close(); 432 433 if (channel != null) { 434 channel.close(); 435 } 436 437 // BEGIN Android-changed: Close handling / notification of blocked threads. 438 if (isFdOwner) { 439 IoBridge.closeAndSignalBlockedThreads(fd); 440 } 441 // END Android-changed: Close handling / notification of blocked threads. 442 } 443 444 /** 445 * Returns the file descriptor associated with this stream. 446 * 447 * @return the <code>FileDescriptor</code> object that represents 448 * the connection to the file in the file system being used 449 * by this <code>FileOutputStream</code> object. 450 * 451 * @exception IOException if an I/O error occurs. 452 * @see java.io.FileDescriptor 453 */ 454 // Android-added: @ReachabilitySensitive 455 @ReachabilitySensitive getFD()456 public final FileDescriptor getFD() throws IOException { 457 if (fd != null) { 458 return fd; 459 } 460 throw new IOException(); 461 } 462 463 /** 464 * Returns the unique {@link java.nio.channels.FileChannel FileChannel} 465 * object associated with this file output stream. 466 * 467 * <p> The initial {@link java.nio.channels.FileChannel#position() 468 * position} of the returned channel will be equal to the 469 * number of bytes written to the file so far unless this stream is in 470 * append mode, in which case it will be equal to the size of the file. 471 * Writing bytes to this stream will increment the channel's position 472 * accordingly. Changing the channel's position, either explicitly or by 473 * writing, will change this stream's file position. 474 * 475 * @return the file channel associated with this file output stream 476 * 477 * @since 1.4 478 * @spec JSR-51 479 */ getChannel()480 public FileChannel getChannel() { 481 synchronized (this) { 482 if (channel == null) { 483 channel = FileChannelImpl.open(fd, path, false, true, append, this); 484 } 485 return channel; 486 } 487 } 488 489 /** 490 * Cleans up the connection to the file, and ensures that the 491 * <code>close</code> method of this file output stream is 492 * called when there are no more references to this stream. 493 * 494 * @exception IOException if an I/O error occurs. 495 * @see java.io.FileInputStream#close() 496 */ finalize()497 protected void finalize() throws IOException { 498 // Android-added: CloseGuard support. 499 if (guard != null) { 500 guard.warnIfOpen(); 501 } 502 503 if (fd != null) { 504 if (fd == FileDescriptor.out || fd == FileDescriptor.err) { 505 flush(); 506 } else { 507 // Android-removed: Obsoleted comment about shared FileDescriptor handling. 508 close(); 509 } 510 } 511 } 512 513 // BEGIN Android-removed: Unused code. 514 /* 515 private native void close0() throws IOException; 516 517 private static native void initIDs(); 518 519 static { 520 initIDs(); 521 } 522 */ 523 // END Android-removed: Unused code. 524 525 } 526