1 /*******************************************************************************
2 
3         Copyright:
4             Copyright (c) 2004 Kris Bell.
5             Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
6             All rights reserved.
7 
8         License:
9             Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
10             See LICENSE_TANGO.txt for details.
11 
12         Version: May 2005: Initial release
13 
14         Authors: Kris
15 
16 *******************************************************************************/
17 
18 module ocean.io.device.Device;
19 
20 import ocean.meta.types.Qualifiers;
21 
22 import ocean.sys.Common;
23 
24 public  import ocean.io.device.Conduit;
25 
26 /*******************************************************************************
27 
28         Implements a means of reading and writing a file device. Conduits
29         are the primary means of accessing external data, and this one is
30         used as a superclass for the console, for files, sockets etc.
31 
32 *******************************************************************************/
33 
34 class Device : Conduit, ISelectable
35 {
36         import core.stdc.errno;
37         import core.sys.posix.sys.types: off_t;
38 
39         /// expose superclass definition also
40         public alias Conduit.error error;
41 
42         /***********************************************************************
43 
44                 Throw an IOException noting the last error.
45 
46         ***********************************************************************/
47 
48         final void error ()
49         {
50                 error (this.toString ~ " :: " ~ SysError.lastMsg);
51         }
52 
53         /***********************************************************************
54 
55                 Return the name of this device.
56 
57         ***********************************************************************/
58 
59         override istring toString ()
60         {
61                 return "<device>";
62         }
63 
64         /***********************************************************************
65 
66                 Return a preferred size for buffering conduit I/O.
67 
68         ***********************************************************************/
69 
70         override size_t bufferSize ()
71         {
72                 return 1024 * 16;
73         }
74 
75         /***********************************************************************
76 
77             Sets the device in the non-blocking mode.
78 
79             Throws:
80                 IOException if setting the device mode fails
81 
82         ***********************************************************************/
83 
84         public void setNonBlock ()
85         {
86             auto existing_flags = fcntl(this.fileHandle(), F_GETFL, 0);
87 
88             if (existing_flags == -1)
89             {
90                 this.error(errno, "fcntl");
91             }
92 
93             if (fcntl(this.fileHandle(), F_SETFL, existing_flags | O_NONBLOCK) < 0)
94             {
95                 this.error(errno, "fcntl");
96             }
97         }
98 
99     protected int handle = -1;
100 
101     /***************************************************************************
102 
103         Allow adjustment of standard IO handles.
104 
105     ***************************************************************************/
106 
107     public void reopen (Handle handle)
108     {
109         this.handle = handle;
110     }
111 
112     /***************************************************************************
113 
114         Returns:
115             the file descriptor of this Conduit.
116 
117     ***************************************************************************/
118 
119     final Handle fileHandle ()
120     {
121         return cast(Handle) handle;
122     }
123 
124     /***************************************************************************
125 
126         Release the underlying file.
127 
128     ***************************************************************************/
129 
130     override void detach ()
131     {
132         if (handle >= 0)
133         {
134             //if (scheduler)
135             // TODO Not supported on Posix
136             // scheduler.close (handle, toString);
137             posix.close (handle);
138         }
139         handle = -1;
140     }
141 
142     /***************************************************************************
143 
144         Read a chunk of bytes from the file into the provided array
145 
146         Returns:
147             the number of bytes read, or Eof where there is no further data.
148 
149     ***************************************************************************/
150 
151     override size_t read (void[] dst)
152     {
153         ssize_t read;
154 
155         do
156         {
157             read = posix.read (handle, dst.ptr, dst.length);
158         }
159         while (read == -1 && errno == EINTR);
160 
161         if (read is -1)
162             error(errno, "read");
163         else
164             if (read is 0 && dst.length > 0)
165                 return Eof;
166         return read;
167     }
168 
169     /***************************************************************************
170 
171         Write a chunk of bytes to the file from the provided array.
172 
173         Returns:
174             the number of bytes written, or Eof if the output is
175             no longer available.
176 
177     ***************************************************************************/
178 
179     override size_t write (const(void)[] src)
180     {
181         ssize_t written;
182 
183         do
184         {
185             written = posix.write (handle, src.ptr, src.length);
186         }
187         while (written == -1 && errno == EINTR);
188 
189         if (written is -1)
190             error(errno, "write");
191         return written;
192     }
193 
194     /***************************************************************************
195 
196         Read a chunk of bytes from the file from the given offset,
197         into the provided array
198 
199         Params:
200             dst = destination buffer to fill
201             offset = offset to start reading from
202 
203         Returns:
204             number of bytes read or Eof if there's no further data
205 
206         Throws:
207             `File.IOException` on failure
208 
209     ***************************************************************************/
210 
211     public size_t pread (void[] dst, off_t offset)
212     {
213         ssize_t read;
214 
215         do
216         {
217             read = posix.pread (handle, dst.ptr, dst.length,
218                                 offset);
219         }
220         while (read == -1 && errno == EINTR);
221 
222         if (read is -1)
223             error(errno, "pread");
224         else
225             if (read is 0 && dst.length > 0)
226                 return Eof;
227         return read;
228     }
229 
230     /***************************************************************************
231 
232         Write a chunk of bytes to the file starting from the given offset,
233         from the provided array
234 
235         Params:
236             src = source buffer to write data from
237             offset = offset to start writing from
238 
239         Returns:
240             number of bytes written
241 
242         Throws:
243             `File.IOException` on failure
244 
245     ***************************************************************************/
246 
247     public size_t pwrite (const(void)[] src, off_t offset)
248     {
249         ssize_t written;
250 
251         do
252         {
253             written = posix.pwrite (handle, src.ptr, src.length,
254                                     offset);
255         }
256         while (written == -1 && errno == EINTR);
257 
258         if (written is -1)
259             error(errno, "pwrite");
260         return written;
261     }
262 }