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