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 }