1 /* 2 * Copyright (c) 2003, 2019, 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 23 * questions. 24 */ 25 26 package java.io; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.Objects; 31 32 import jdk.internal.access.JavaIOFileDescriptorAccess; 33 import jdk.internal.access.SharedSecrets; 34 import jdk.internal.ref.PhantomCleanable; 35 36 /** 37 * Instances of the file descriptor class serve as an opaque handle 38 * to the underlying machine-specific structure representing an open 39 * file, an open socket, or another source or sink of bytes. 40 * The main practical use for a file descriptor is to create a 41 * {@link FileInputStream} or {@link FileOutputStream} to contain it. 42 * <p> 43 * Applications should not create their own file descriptors. 44 * 45 * @author Pavani Diwanji 46 * @since 1.0 47 */ 48 public final class FileDescriptor { 49 50 private int fd; 51 52 private long handle; 53 54 private Closeable parent; 55 private List<Closeable> otherParents; 56 private boolean closed; 57 58 /** 59 * true, if file is opened for appending. 60 */ 61 private boolean append; 62 63 static { initIDs()64 initIDs(); 65 } 66 67 // Set up JavaIOFileDescriptorAccess in SharedSecrets 68 static { SharedSecrets.setJavaIOFileDescriptorAccess( new JavaIOFileDescriptorAccess() { public void set(FileDescriptor fdo, int fd) { fdo.set(fd); } public int get(FileDescriptor fdo) { return fdo.fd; } public void setAppend(FileDescriptor fdo, boolean append) { fdo.append = append; } public boolean getAppend(FileDescriptor fdo) { return fdo.append; } public void close(FileDescriptor fdo) throws IOException { fdo.close(); } public void registerCleanup(FileDescriptor fdo) { FileCleanable.register(fdo); } public void registerCleanup(FileDescriptor fdo, PhantomCleanable<FileDescriptor> cleanup) { fdo.registerCleanup(cleanup); } public void unregisterCleanup(FileDescriptor fdo) { fdo.unregisterCleanup(); } public void setHandle(FileDescriptor fdo, long handle) { fdo.setHandle(handle); } public long getHandle(FileDescriptor fdo) { return fdo.handle; } } )69 SharedSecrets.setJavaIOFileDescriptorAccess( 70 new JavaIOFileDescriptorAccess() { 71 public void set(FileDescriptor fdo, int fd) { 72 fdo.set(fd); 73 } 74 75 public int get(FileDescriptor fdo) { 76 return fdo.fd; 77 } 78 79 public void setAppend(FileDescriptor fdo, boolean append) { 80 fdo.append = append; 81 } 82 83 public boolean getAppend(FileDescriptor fdo) { 84 return fdo.append; 85 } 86 87 public void close(FileDescriptor fdo) throws IOException { 88 fdo.close(); 89 } 90 91 /* Register for a normal FileCleanable fd/handle cleanup. */ 92 public void registerCleanup(FileDescriptor fdo) { 93 FileCleanable.register(fdo); 94 } 95 96 /* Register a custom PhantomCleanup. */ 97 public void registerCleanup(FileDescriptor fdo, 98 PhantomCleanable<FileDescriptor> cleanup) { 99 fdo.registerCleanup(cleanup); 100 } 101 102 public void unregisterCleanup(FileDescriptor fdo) { 103 fdo.unregisterCleanup(); 104 } 105 106 public void setHandle(FileDescriptor fdo, long handle) { 107 fdo.setHandle(handle); 108 } 109 110 public long getHandle(FileDescriptor fdo) { 111 return fdo.handle; 112 } 113 } 114 ); 115 } 116 117 /** 118 * Cleanup in case FileDescriptor is not explicitly closed. 119 */ 120 private PhantomCleanable<FileDescriptor> cleanup; 121 122 /** 123 * Constructs an (invalid) FileDescriptor object. 124 * The fd or handle is set later. 125 */ FileDescriptor()126 public FileDescriptor() { 127 fd = -1; 128 handle = -1; 129 } 130 131 /** 132 * Used for standard input, output, and error only. 133 * For Windows the corresponding handle is initialized. 134 * For Unix the append mode is cached. 135 * @param fd the raw fd number (0, 1, 2) 136 */ FileDescriptor(int fd)137 private FileDescriptor(int fd) { 138 this.fd = fd; 139 this.handle = getHandle(fd); 140 this.append = getAppend(fd); 141 } 142 143 /** 144 * A handle to the standard input stream. Usually, this file 145 * descriptor is not used directly, but rather via the input stream 146 * known as {@code System.in}. 147 * 148 * @see java.lang.System#in 149 */ 150 public static final FileDescriptor in = new FileDescriptor(0); 151 152 /** 153 * A handle to the standard output stream. Usually, this file 154 * descriptor is not used directly, but rather via the output stream 155 * known as {@code System.out}. 156 * @see java.lang.System#out 157 */ 158 public static final FileDescriptor out = new FileDescriptor(1); 159 160 /** 161 * A handle to the standard error stream. Usually, this file 162 * descriptor is not used directly, but rather via the output stream 163 * known as {@code System.err}. 164 * 165 * @see java.lang.System#err 166 */ 167 public static final FileDescriptor err = new FileDescriptor(2); 168 169 /** 170 * Tests if this file descriptor object is valid. 171 * 172 * @return {@code true} if the file descriptor object represents a 173 * valid, open file, socket, or other active I/O connection; 174 * {@code false} otherwise. 175 */ valid()176 public boolean valid() { 177 return (handle != -1) || (fd != -1); 178 } 179 180 /** 181 * Force all system buffers to synchronize with the underlying 182 * device. This method returns after all modified data and 183 * attributes of this FileDescriptor have been written to the 184 * relevant device(s). In particular, if this FileDescriptor 185 * refers to a physical storage medium, such as a file in a file 186 * system, sync will not return until all in-memory modified copies 187 * of buffers associated with this FileDescriptor have been 188 * written to the physical medium. 189 * 190 * sync is meant to be used by code that requires physical 191 * storage (such as a file) to be in a known state For 192 * example, a class that provided a simple transaction facility 193 * might use sync to ensure that all changes to a file caused 194 * by a given transaction were recorded on a storage medium. 195 * 196 * sync only affects buffers downstream of this FileDescriptor. If 197 * any in-memory buffering is being done by the application (for 198 * example, by a BufferedOutputStream object), those buffers must 199 * be flushed into the FileDescriptor (for example, by invoking 200 * OutputStream.flush) before that data will be affected by sync. 201 * 202 * @throws SyncFailedException 203 * Thrown when the buffers cannot be flushed, 204 * or because the system cannot guarantee that all the 205 * buffers have been synchronized with physical media. 206 * @since 1.1 207 */ sync()208 public native void sync() throws SyncFailedException; 209 210 /* This routine initializes JNI field offsets for the class */ initIDs()211 private static native void initIDs(); 212 213 /* 214 * On Windows return the handle for the standard streams. 215 */ getHandle(int d)216 private static native long getHandle(int d); 217 218 /** 219 * Returns true, if the file was opened for appending. 220 */ getAppend(int fd)221 private static native boolean getAppend(int fd); 222 223 /** 224 * Set the fd. 225 * Used on Unix and for sockets on Windows and Unix. 226 * If setting to -1, clear the cleaner. 227 * The {@link #registerCleanup} method should be called for new fds. 228 * @param fd the raw fd or -1 to indicate closed 229 */ 230 @SuppressWarnings("unchecked") set(int fd)231 synchronized void set(int fd) { 232 if (fd == -1 && cleanup != null) { 233 cleanup.clear(); 234 cleanup = null; 235 } 236 this.fd = fd; 237 } 238 239 /** 240 * Set the handle. 241 * Used on Windows for regular files. 242 * If setting to -1, clear the cleaner. 243 * The {@link #registerCleanup} method should be called for new handles. 244 * @param handle the handle or -1 to indicate closed 245 */ 246 @SuppressWarnings("unchecked") setHandle(long handle)247 void setHandle(long handle) { 248 if (handle == -1 && cleanup != null) { 249 cleanup.clear(); 250 cleanup = null; 251 } 252 this.handle = handle; 253 } 254 255 /** 256 * Register a cleanup for the current handle. 257 * Used directly in java.io and indirectly via fdAccess. 258 * The cleanup should be registered after the handle is set in the FileDescriptor. 259 * @param cleanable a PhantomCleanable to register 260 */ 261 @SuppressWarnings("unchecked") registerCleanup(PhantomCleanable<FileDescriptor> cleanable)262 synchronized void registerCleanup(PhantomCleanable<FileDescriptor> cleanable) { 263 Objects.requireNonNull(cleanable, "cleanable"); 264 if (cleanup != null) { 265 cleanup.clear(); 266 } 267 cleanup = cleanable; 268 } 269 270 /** 271 * Unregister a cleanup for the current raw fd or handle. 272 * Used directly in java.io and indirectly via fdAccess. 273 * Normally {@link #close()} should be used except in cases where 274 * it is certain the caller will close the raw fd and the cleanup 275 * must not close the raw fd. {@link #unregisterCleanup()} must be 276 * called before the raw fd is closed to prevent a race that makes 277 * it possible for the fd to be reallocated to another use and later 278 * the cleanup might be invoked. 279 */ unregisterCleanup()280 synchronized void unregisterCleanup() { 281 if (cleanup != null) { 282 cleanup.clear(); 283 } 284 cleanup = null; 285 } 286 287 /** 288 * Close the raw file descriptor or handle, if it has not already been closed. 289 * The native code sets the fd and handle to -1. 290 * Clear the cleaner so the close does not happen twice. 291 * Package private to allow it to be used in java.io. 292 * @throws IOException if close fails 293 */ 294 @SuppressWarnings("unchecked") close()295 synchronized void close() throws IOException { 296 unregisterCleanup(); 297 close0(); 298 } 299 300 /* 301 * Close the raw file descriptor or handle, if it has not already been closed 302 * and set the fd and handle to -1. 303 */ close0()304 private native void close0() throws IOException; 305 306 /* 307 * Package private methods to track referents. 308 * If multiple streams point to the same FileDescriptor, we cycle 309 * through the list of all referents and call close() 310 */ 311 312 /** 313 * Attach a Closeable to this FD for tracking. 314 * parent reference is added to otherParents when 315 * needed to make closeAll simpler. 316 */ attach(Closeable c)317 synchronized void attach(Closeable c) { 318 if (parent == null) { 319 // first caller gets to do this 320 parent = c; 321 } else if (otherParents == null) { 322 otherParents = new ArrayList<>(); 323 otherParents.add(parent); 324 otherParents.add(c); 325 } else { 326 otherParents.add(c); 327 } 328 } 329 330 /** 331 * Cycle through all Closeables sharing this FD and call 332 * close() on each one. 333 * 334 * The caller closeable gets to call close0(). 335 */ 336 @SuppressWarnings("try") closeAll(Closeable releaser)337 synchronized void closeAll(Closeable releaser) throws IOException { 338 if (!closed) { 339 closed = true; 340 IOException ioe = null; 341 try (releaser) { 342 if (otherParents != null) { 343 for (Closeable referent : otherParents) { 344 try { 345 referent.close(); 346 } catch(IOException x) { 347 if (ioe == null) { 348 ioe = x; 349 } else { 350 ioe.addSuppressed(x); 351 } 352 } 353 } 354 } 355 } catch(IOException ex) { 356 /* 357 * If releaser close() throws IOException 358 * add other exceptions as suppressed. 359 */ 360 if (ioe != null) 361 ex.addSuppressed(ioe); 362 ioe = ex; 363 } finally { 364 if (ioe != null) 365 throw ioe; 366 } 367 } 368 } 369 } 370