1 /*
2 * Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
78 /**
79 * The system dependent file descriptor.
80 */
81 private final FileDescriptor fd;
82
83 /**
84 * The associated channel, initialized lazily.
85 */
86 private volatile FileChannel channel;
87
88 /**
89 * The path of the referenced file
90 * (null if the stream is created with a file descriptor)
91 */
92 private final String path;
93
94 private final Object closeLock = new Object();
95
96 private volatile boolean closed;
97
98 private final Object altFinalizer;
99
100 /**
101 * Creates a file output stream to write to the file with the
102 * specified name. A new <code>FileDescriptor</code> object is
103 * created to represent this file connection.
104 * <p>
105 * First, if there is a security manager, its <code>checkWrite</code>
106 * method is called with <code>name</code> as its argument.
107 * <p>
108 * If the file exists but is a directory rather than a regular file, does
109 * not exist but cannot be created, or cannot be opened for any other
110 * reason then a <code>FileNotFoundException</code> is thrown.
111 *
112 * @implSpec Invoking this constructor with the parameter {@code name} is
113 * equivalent to invoking {@link #FileOutputStream(String,boolean)
114 * new FileOutputStream(name, false)}.
115 *
116 * @param name the system-dependent filename
117 * @exception FileNotFoundException if the file exists but is a directory
118 * rather than a regular file, does not exist but cannot
119 * be created, or cannot be opened for any other reason
218 */
219 public FileOutputStream(File file, boolean append)
220 throws FileNotFoundException
221 {
222 String name = (file != null ? file.getPath() : null);
223 SecurityManager security = System.getSecurityManager();
224 if (security != null) {
225 security.checkWrite(name);
226 }
227 if (name == null) {
228 throw new NullPointerException();
229 }
230 if (file.isInvalid()) {
231 throw new FileNotFoundException("Invalid file path");
232 }
233 this.fd = new FileDescriptor();
234 fd.attach(this);
235 this.path = name;
236
237 open(name, append);
238 altFinalizer = getFinalizer(this);
239 if (altFinalizer == null) {
240 FileCleanable.register(fd); // open sets the fd, register the cleanup
241 }
242 }
243
244 /**
245 * Creates a file output stream to write to the specified file
246 * descriptor, which represents an existing connection to an actual
247 * file in the file system.
248 * <p>
249 * First, if there is a security manager, its <code>checkWrite</code>
250 * method is called with the file descriptor <code>fdObj</code>
251 * argument as its argument.
252 * <p>
253 * If <code>fdObj</code> is null then a <code>NullPointerException</code>
254 * is thrown.
255 * <p>
256 * This constructor does not throw an exception if <code>fdObj</code>
257 * is {@link java.io.FileDescriptor#valid() invalid}.
258 * However, if the methods are invoked on the resulting stream to attempt
259 * I/O on the stream, an <code>IOException</code> is thrown.
260 *
261 * @param fdObj the file descriptor to be opened for writing
262 * @exception SecurityException if a security manager exists and its
263 * <code>checkWrite</code> method denies
264 * write access to the file descriptor
265 * @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
266 */
267 public FileOutputStream(FileDescriptor fdObj) {
268 SecurityManager security = System.getSecurityManager();
269 if (fdObj == null) {
270 throw new NullPointerException();
271 }
272 if (security != null) {
273 security.checkWrite(fdObj);
274 }
275 this.fd = fdObj;
276 this.path = null;
277 this.altFinalizer = null;
278
279 fd.attach(this);
280 }
281
282 /**
283 * Opens a file, with the specified name, for overwriting or appending.
284 * @param name name of file to be opened
285 * @param append whether the file is to be opened in append mode
286 */
287 private native void open0(String name, boolean append)
288 throws FileNotFoundException;
289
290 // wrap native call to allow instrumentation
291 /**
292 * Opens a file, with the specified name, for overwriting or appending.
293 * @param name name of file to be opened
294 * @param append whether the file is to be opened in append mode
295 */
296 private void open(String name, boolean append)
297 throws FileNotFoundException {
440 synchronized (this) {
441 fc = this.channel;
442 if (fc == null) {
443 this.channel = fc = FileChannelImpl.open(fd, path, false,
444 true, false, this);
445 if (closed) {
446 try {
447 // possible race with close(), benign since
448 // FileChannel.close is final and idempotent
449 fc.close();
450 } catch (IOException ioe) {
451 throw new InternalError(ioe); // should not happen
452 }
453 }
454 }
455 }
456 }
457 return fc;
458 }
459
460 /**
461 * Cleans up the connection to the file, and ensures that the
462 * {@link #close} method of this file output stream is
463 * called when there are no more references to this stream.
464 * The {@link #finalize} method does not call {@link #close} directly.
465 *
466 * @apiNote
467 * To release resources used by this stream {@link #close} should be called
468 * directly or by try-with-resources.
469 *
470 * @implSpec
471 * If this FileOutputStream has been subclassed and the {@link #close}
472 * method has been overridden, the {@link #close} method will be
473 * called when the FileOutputStream is unreachable.
474 * Otherwise, it is implementation specific how the resource cleanup described in
475 * {@link #close} is performed.
476 *
477 * @deprecated The {@code finalize} method has been deprecated and will be removed.
478 * Subclasses that override {@code finalize} in order to perform cleanup
479 * should be modified to use alternative cleanup mechanisms and
480 * to remove the overriding {@code finalize} method.
481 * When overriding the {@code finalize} method, its implementation must explicitly
482 * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
483 * See the specification for {@link Object#finalize()} for further
484 * information about migration options.
485 *
486 * @exception IOException if an I/O error occurs.
487 * @see java.io.FileInputStream#close()
488 */
489 @Deprecated(since="9", forRemoval = true)
490 protected void finalize() throws IOException {
491 }
492
493 private static native void initIDs();
494
495 static {
496 initIDs();
497 }
498
499 /*
500 * Returns a finalizer object if the FOS needs a finalizer; otherwise null.
501 * If the FOS has a close method; it needs an AltFinalizer.
502 */
503 private static Object getFinalizer(FileOutputStream fos) {
504 Class<?> clazz = fos.getClass();
505 while (clazz != FileOutputStream.class) {
506 try {
507 clazz.getDeclaredMethod("close");
508 return new AltFinalizer(fos);
509 } catch (NoSuchMethodException nsme) {
510 // ignore
511 }
512 clazz = clazz.getSuperclass();
513 }
514 return null;
515 }
516
517 /**
518 * Class to call {@code FileOutputStream.close} when finalized.
519 * If finalization of the stream is needed, an instance is created
520 * in its constructor(s). When the set of instances
521 * related to the stream is unreachable, the AltFinalizer performs
522 * the needed call to the stream's {@code close} method.
523 */
524 static class AltFinalizer {
525 private final FileOutputStream fos;
526
527 AltFinalizer(FileOutputStream fos) {
528 this.fos = fos;
529 }
530
531 @Override
532 @SuppressWarnings("deprecation")
533 protected final void finalize() {
534 try {
535 if (fos.fd != null) {
536 if (fos.fd == FileDescriptor.out || fos.fd == FileDescriptor.err) {
537 // Subclass may override flush; otherwise it is no-op
538 fos.flush();
539 } else {
540 /* if fd is shared, the references in FileDescriptor
541 * will ensure that finalizer is only called when
542 * safe to do so. All references using the fd have
543 * become unreachable. We can call close()
544 */
545 fos.close();
546 }
547 }
548 } catch (IOException ioe) {
549 // ignore
550 }
551 }
552 }
553
554 }
|
1 /*
2 * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
78 /**
79 * The system dependent file descriptor.
80 */
81 private final FileDescriptor fd;
82
83 /**
84 * The associated channel, initialized lazily.
85 */
86 private volatile FileChannel channel;
87
88 /**
89 * The path of the referenced file
90 * (null if the stream is created with a file descriptor)
91 */
92 private final String path;
93
94 private final Object closeLock = new Object();
95
96 private volatile boolean closed;
97
98 /**
99 * Creates a file output stream to write to the file with the
100 * specified name. A new <code>FileDescriptor</code> object is
101 * created to represent this file connection.
102 * <p>
103 * First, if there is a security manager, its <code>checkWrite</code>
104 * method is called with <code>name</code> as its argument.
105 * <p>
106 * If the file exists but is a directory rather than a regular file, does
107 * not exist but cannot be created, or cannot be opened for any other
108 * reason then a <code>FileNotFoundException</code> is thrown.
109 *
110 * @implSpec Invoking this constructor with the parameter {@code name} is
111 * equivalent to invoking {@link #FileOutputStream(String,boolean)
112 * new FileOutputStream(name, false)}.
113 *
114 * @param name the system-dependent filename
115 * @exception FileNotFoundException if the file exists but is a directory
116 * rather than a regular file, does not exist but cannot
117 * be created, or cannot be opened for any other reason
216 */
217 public FileOutputStream(File file, boolean append)
218 throws FileNotFoundException
219 {
220 String name = (file != null ? file.getPath() : null);
221 SecurityManager security = System.getSecurityManager();
222 if (security != null) {
223 security.checkWrite(name);
224 }
225 if (name == null) {
226 throw new NullPointerException();
227 }
228 if (file.isInvalid()) {
229 throw new FileNotFoundException("Invalid file path");
230 }
231 this.fd = new FileDescriptor();
232 fd.attach(this);
233 this.path = name;
234
235 open(name, append);
236 FileCleanable.register(fd); // open sets the fd, register the cleanup
237 }
238
239 /**
240 * Creates a file output stream to write to the specified file
241 * descriptor, which represents an existing connection to an actual
242 * file in the file system.
243 * <p>
244 * First, if there is a security manager, its <code>checkWrite</code>
245 * method is called with the file descriptor <code>fdObj</code>
246 * argument as its argument.
247 * <p>
248 * If <code>fdObj</code> is null then a <code>NullPointerException</code>
249 * is thrown.
250 * <p>
251 * This constructor does not throw an exception if <code>fdObj</code>
252 * is {@link java.io.FileDescriptor#valid() invalid}.
253 * However, if the methods are invoked on the resulting stream to attempt
254 * I/O on the stream, an <code>IOException</code> is thrown.
255 *
256 * @param fdObj the file descriptor to be opened for writing
257 * @exception SecurityException if a security manager exists and its
258 * <code>checkWrite</code> method denies
259 * write access to the file descriptor
260 * @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
261 */
262 public FileOutputStream(FileDescriptor fdObj) {
263 SecurityManager security = System.getSecurityManager();
264 if (fdObj == null) {
265 throw new NullPointerException();
266 }
267 if (security != null) {
268 security.checkWrite(fdObj);
269 }
270 this.fd = fdObj;
271 this.path = null;
272
273 fd.attach(this);
274 }
275
276 /**
277 * Opens a file, with the specified name, for overwriting or appending.
278 * @param name name of file to be opened
279 * @param append whether the file is to be opened in append mode
280 */
281 private native void open0(String name, boolean append)
282 throws FileNotFoundException;
283
284 // wrap native call to allow instrumentation
285 /**
286 * Opens a file, with the specified name, for overwriting or appending.
287 * @param name name of file to be opened
288 * @param append whether the file is to be opened in append mode
289 */
290 private void open(String name, boolean append)
291 throws FileNotFoundException {
434 synchronized (this) {
435 fc = this.channel;
436 if (fc == null) {
437 this.channel = fc = FileChannelImpl.open(fd, path, false,
438 true, false, this);
439 if (closed) {
440 try {
441 // possible race with close(), benign since
442 // FileChannel.close is final and idempotent
443 fc.close();
444 } catch (IOException ioe) {
445 throw new InternalError(ioe); // should not happen
446 }
447 }
448 }
449 }
450 }
451 return fc;
452 }
453
454 private static native void initIDs();
455
456 static {
457 initIDs();
458 }
459 }
|