1 /*
2     Title:      Data structures shared between basioio.c and network.c.
3 
4     Copyright (c) 2000, 2016, 2018-19 David C. J. Matthews
5     Portions of this code are derived from the original stream io
6     package copyright CUTS 1983-2000.
7 
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Lesser General Public
10     License version 2.1 as published by the Free Software Foundation.
11 
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Lesser General Public License for more details.
16 
17     You should have received a copy of the GNU Lesser General Public
18     License along with this library; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 
21 */
22 
23 #ifndef IO_INTERNAL_H
24 #define IO_INTERNAL_H
25 
26 // Bits to define tests and results in poll.
27 // These are the values passed to and from ML.
28 #define POLL_BIT_IN     1
29 #define POLL_BIT_OUT    2
30 #define POLL_BIT_PRI    4
31 
32 // Return values from fileKind
33 #define FILEKIND_FILE   0
34 #define FILEKIND_DIR    1
35 #define FILEKIND_LINK   2
36 #define FILEKIND_TTY    3
37 #define FILEKIND_PIPE   4
38 #define FILEKIND_SKT    5
39 #define FILEKIND_DEV    6
40 #define FILEKIND_UNKNOWN 7
41 #define FILEKIND_ERROR  (-1)
42 
43 
44 #if (defined(_WIN32))
45 
46 #include <WinSock2.h>
47 #include "locking.h" // For PLock
48 
49 // Unlike Unix where select and poll can be used on both sockets and other
50 // streams, in Windows there is no single way of testing different sorts of
51 // streams.
52 class WinStreamBase
53 {
54 public:
~WinStreamBase()55     virtual ~WinStreamBase() {} // Quieten some warnings
pollTest()56     virtual int pollTest() { // Return the valid options for this descriptor
57         return 0;
58     }
poll(TaskData * taskData,int test)59     virtual int poll(TaskData *taskData, int test) { // Return the values set
60         return 0;
61     }
62     // These are not currently used but could be used to poll
63     // multiple sockets or streams.
getSocket()64     virtual SOCKET getSocket() {
65         return INVALID_SOCKET;
66     }
getHandle()67     virtual HANDLE getHandle() {
68         return INVALID_HANDLE_VALUE;
69     }
70 };
71 
72 typedef enum { OPENREAD, OPENWRITE, OPENAPPEND } openMode;
73 
74 // Abstract Windows stream
75 class WinStream : public WinStreamBase
76 {
77 public:
78     virtual void closeEntry(TaskData *taskData) = 0;
79 
80     // Block for a short time until either input is possible, returning true,
81     // or the time-out, which may be zero, has expired.
82     virtual bool testForInput(TaskData *taskData, unsigned waitMilliSecs) = 0;
83 
84     // The same for output.
85     virtual bool testForOutput(TaskData *taskData, unsigned waitMilliSecs) = 0;
86 
87     // These are really for backwards compatibility.
88     virtual void waitUntilAvailable(TaskData *taskData);
89     virtual void waitUntilOutputPossible(TaskData *taskData);
90 
readStream(TaskData * taskData,byte * base,size_t length)91     virtual size_t readStream(TaskData *taskData, byte *base, size_t length) {
92         unimplemented(taskData);
93         return 0;
94     }
getPos(TaskData * taskData)95     virtual uint64_t getPos(TaskData *taskData) {
96         unimplemented(taskData);
97         return 0;
98     }
setPos(TaskData * taskData,uint64_t pos)99     virtual void setPos(TaskData *taskData, uint64_t pos) {
100         unimplemented(taskData);
101     }
fileSize(TaskData * taskData)102     virtual uint64_t fileSize(TaskData *taskData) {
103         unimplemented(taskData);
104         return 0;
105     }
writeStream(TaskData * taskData,byte * base,size_t length)106     virtual size_t writeStream(TaskData *taskData, byte *base, size_t length) {
107         unimplemented(taskData);
108         return 0;
109     }
110     virtual int fileKind() = 0;
111     static int fileTypeOfHandle(HANDLE hStream);
112 
113 protected:
114     void unimplemented(TaskData *taskData);
115 };
116 
117 // Windows stream input using overlapped IO and the Windows calls.
118 class WinInOutStream : public WinStream
119 {
120 public:
121     WinInOutStream();
122     ~WinInOutStream();
123     virtual void closeEntry(TaskData *taskData);
124     virtual void openFile(TaskData * taskData, TCHAR *name, openMode mode, bool text);
125     virtual size_t readStream(TaskData *taskData, byte *base, size_t length);
126 
127     virtual bool testForInput(TaskData *taskData, unsigned waitMilliSecs);
128     virtual bool testForOutput(TaskData *taskData, unsigned waitMilliSecs);
129 
130     virtual uint64_t getPos(TaskData *taskData);
131     virtual void setPos(TaskData *taskData, uint64_t pos);
132     virtual uint64_t fileSize(TaskData *taskData);
133 
134     virtual size_t writeStream(TaskData *taskData, byte *base, size_t length);
135 
136     // Open on a handle.  This returns an error result rather than raising an exception
137     virtual bool openHandle(HANDLE hndl, openMode mode, bool isText);
138 
fileKind()139     virtual int fileKind() {
140         return WinStream::fileTypeOfHandle(hStream);
141     }
142 
pollTest()143     virtual int pollTest() {
144         // We can poll this to test for input.
145         return isRead ? POLL_BIT_IN : POLL_BIT_OUT;
146     }
147 
148     virtual int poll(TaskData *taskData, int test);
149 
getHandle()150     virtual HANDLE getHandle() {
151         return hEvent;
152     }
153 
154 protected:
155     bool beginReading();
156     void flushOut(TaskData *taskData);
getOverlappedPos()157     uint64_t getOverlappedPos() {
158         return ((uint64_t)(overlap.OffsetHigh) << 32) + overlap.Offset;
159     }
setOverlappedPos(uint64_t newPos)160     void setOverlappedPos(uint64_t newPos) {
161         overlap.Offset = (DWORD)newPos;
162         overlap.OffsetHigh = (DWORD)(newPos >> 32);
163     }
164 
165     bool isAvailable(TaskData *taskData);
166     bool canOutput(TaskData *taskData);
167 
168 protected:
169     bool isRead;
170     bool isText; // Remove CRs?
171     byte *buffer;
172     unsigned buffSize, currentInBuffer, currentPtr;
173     bool endOfStream;
174     HANDLE hStream;
175     HANDLE hEvent;
176     OVERLAPPED overlap;
177     PLock lock;
178 };
179 
180 // Create a new pipe.
181 extern void newPipeName(TCHAR *name);
182 
183 #else
184 
185 extern Handle wrapFileDescriptor(TaskData *taskData, int fd);
186 // Get a file descriptor and raise an exception if it is closed.
187 extern int getStreamFileDescriptor(TaskData *taskData, PolyWord strm);
188 extern int getStreamFileDescriptorWithoutCheck(PolyWord strm);
189 
190 #endif
191 
192 // This is used in both basicio and unix-specific
193 #if defined(HAVE_STRUCT_STAT_ST_ATIM)
194 # define STAT_SECS(stat,kind)    (stat)->st_##kind##tim.tv_sec
195 # define STAT_USECS(stat,kind) (((stat)->st_##kind##tim.tv_nsec + 500) / 1000)
196 #elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
197 # define STAT_SECS(stat,kind)    (stat)->st_##kind##time
198 # define STAT_USECS(stat,kind) (((stat)->st_##kind##timensec + 500) / 1000)
199 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
200 # define STAT_SECS(stat,kind)    (stat)->st_##kind##timespec.tv_sec
201 # define STAT_USECS(stat,kind) (((stat)->st_##kind##timespec.tv_nsec + 500) / 1000)
202 #elif defined(HAVE_STRUCT_STAT_ST_ATIME_N)
203 # define STAT_SECS(stat,kind)    (stat)->st_##kind##time
204 # define STAT_USECS(stat,kind) (((stat)->st_##kind##time_n + 500) / 1000)
205 #elif defined(HAVE_STRUCT_STAT_ST_UATIME)
206 # define STAT_SECS(stat,kind)    (stat)->st_##kind##time
207 # define STAT_USECS(stat,kind)   (stat)->st_u##kind##time
208 #else
209 # define STAT_SECS(stat,kind)    (stat)->st_##kind##time
210 # define STAT_USECS(stat,kind)   0
211 #endif
212 
213 #endif
214