1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.stream.FileDescriptor; 13 14 import hunt.util.Common; 15 import hunt.Exceptions; 16 17 import std.container.array; 18 /** 19 * Instances of the file descriptor class serve as an opaque handle 20 * to the underlying machine-specific structure representing an 21 * open file, an open socket, or another source or sink of bytes. 22 * The main practical use for a file descriptor is to create a 23 * {@link FileInputStream} or {@link FileOutputStream} to contain it. 24 * 25 * <p>Applications should not create their own file descriptors. 26 * 27 * @author Pavani Diwanji 28 */ 29 final class FileDescriptor { 30 31 private int fd; 32 33 private long handle; 34 35 private Closeable parent; 36 private Array!Closeable otherParents; 37 private bool closed; 38 39 /** 40 * Constructs an (invalid) FileDescriptor 41 * object. 42 */ 43 this() { 44 fd = -1; 45 handle = -1; 46 } 47 48 shared static this() { 49 // initIDs(); 50 } 51 52 // Set up JavaIOFileDescriptorAccess in SharedSecrets 53 // static { 54 // sun.misc.SharedSecrets.setJavaIOFileDescriptorAccess( 55 // new sun.misc.JavaIOFileDescriptorAccess() { 56 // void set(FileDescriptor obj, int fd) { 57 // obj.fd = fd; 58 // } 59 60 // int get(FileDescriptor obj) { 61 // return obj.fd; 62 // } 63 64 // void setHandle(FileDescriptor obj, long handle) { 65 // obj.handle = handle; 66 // } 67 68 // long getHandle(FileDescriptor obj) { 69 // return obj.handle; 70 // } 71 // } 72 // ); 73 // } 74 75 /** 76 * A handle to the standard input stream. Usually, this file 77 * descriptor is not used directly, but rather via the input stream 78 * known as {@code System.in}. 79 * 80 * @see java.lang.System#in 81 */ 82 // __gshared FileDescriptor inHandle = standardStream(0); 83 84 /** 85 * A handle to the standard output stream. Usually, this file 86 * descriptor is not used directly, but rather via the output stream 87 * known as {@code System.out}. 88 * @see java.lang.System#out 89 */ 90 // __gshared FileDescriptor outHandle = standardStream(1); 91 92 /** 93 * A handle to the standard error stream. Usually, this file 94 * descriptor is not used directly, but rather via the output stream 95 * known as {@code System.err}. 96 * 97 * @see java.lang.System#err 98 */ 99 // static final FileDescriptor err = standardStream(2); 100 101 /** 102 * Tests if this file descriptor object is valid. 103 * 104 * @return {@code true} if the file descriptor object represents a 105 * valid, open file, socket, or other active I/O connection; 106 * {@code false} otherwise. 107 */ 108 bool valid() { 109 return ((handle != -1) || (fd != -1)); 110 } 111 112 /** 113 * Force all system buffers to synchronize with the underlying 114 * device. This method returns after all modified data and 115 * attributes of this FileDescriptor have been written to the 116 * relevant device(s). In particular, if this FileDescriptor 117 * refers to a physical storage medium, such as a file in a file 118 * system, sync will not return until all in-memory modified copies 119 * of buffers associated with this FileDesecriptor have been 120 * written to the physical medium. 121 * 122 * sync is meant to be used by code that requires physical 123 * storage (such as a file) to be in a known state For 124 * example, a class that provided a simple transaction facility 125 * might use sync to ensure that all changes to a file caused 126 * by a given transaction were recorded on a storage medium. 127 * 128 * sync only affects buffers downstream of this FileDescriptor. If 129 * any in-memory buffering is being done by the application (for 130 * example, by a BufferedOutputStream object), those buffers must 131 * be flushed into the FileDescriptor (for example, by invoking 132 * OutputStream.flush) before that data will be affected by sync. 133 * 134 * @exception SyncFailedException 135 * Thrown when the buffers cannot be flushed, 136 * or because the system cannot guarantee that all the 137 * buffers have been synchronized with physical media. 138 */ 139 void sync() { 140 implementationMissing(false); 141 } 142 143 /* This routine initializes JNI field offsets for the class */ 144 private static void initIDs() { 145 implementationMissing(false); 146 } 147 148 private static long set(int d) { 149 implementationMissing(false); 150 return 0; 151 } 152 153 private static FileDescriptor standardStream(int fd) { 154 FileDescriptor desc = new FileDescriptor(); 155 desc.handle = set(fd); 156 return desc; 157 } 158 159 /* 160 * Package private methods to track referents. 161 * If multiple streams point to the same FileDescriptor, we cycle 162 * through the list of all referents and call close() 163 */ 164 165 /** 166 * Attach a Closeable to this FD for tracking. 167 * parent reference is added to otherParents when 168 * needed to make closeAll simpler. 169 */ 170 void attach(Closeable c) { 171 if (parent is null) { 172 // first caller gets to do this 173 parent = c; 174 } else if (otherParents.length == 0) { 175 // otherParents = new ArrayList<>(); 176 otherParents.insertBack(parent); 177 otherParents.insertBack(c); 178 } else { 179 otherParents.insertBack(c); 180 } 181 } 182 183 /** 184 * Cycle through all Closeables sharing this FD and call 185 * close() on each one. 186 * 187 * The caller closeable gets to call close0(). 188 */ 189 void closeAll(Closeable releaser) { 190 if (!closed) { 191 closed = true; 192 IOException ioe = null; 193 try { 194 Closeable c = releaser; 195 foreach (Closeable referent ; otherParents) { 196 try { 197 referent.close(); 198 } catch(IOException x) { 199 if (ioe is null) { 200 ioe = x; 201 } else { 202 ioe.next = x; 203 } 204 } 205 } 206 } catch(IOException ex) { 207 /* 208 * If releaser close() throws IOException 209 * add other exceptions as suppressed. 210 */ 211 if (ioe !is null) 212 ex.next = ioe; 213 ioe = ex; 214 } finally { 215 if (ioe !is null) 216 throw ioe; 217 } 218 } 219 } 220 }