1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 81    aio_xxx() POSIX emulation on Windows */
10 
11 #include "squid.h"
12 #include "comm.h"
13 #include "DiskIO/AIO/aio_win32.h"
14 #include "fd.h"
15 #include "StatCounters.h"
16 #include "win32.h"
17 
18 #include <cerrno>
19 
20 #if _SQUID_WINDOWS_
IoCompletionRoutine(DWORD dwErrorCode,DWORD dwNumberOfBytesTransfered,LPOVERLAPPED lpOverlapped)21 VOID CALLBACK IoCompletionRoutine(DWORD dwErrorCode,
22                                   DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
23 {
24 
25     struct aiocb *aiocbp = (struct aiocb *) lpOverlapped->hEvent;
26 
27     aiocbp->aio_sigevent.sigev_notify = dwErrorCode;
28     aiocbp->aio_sigevent.sigev_signo = dwNumberOfBytesTransfered;
29     debugs(81, 7, "AIO operation complete: errorcode=" << dwErrorCode << " nbytes=" << dwNumberOfBytesTransfered);
30     xfree(lpOverlapped);
31 }
32 
aio_read(struct aiocb * aiocbp)33 int aio_read(struct aiocb *aiocbp)
34 {
35     LPOVERLAPPED Overlapped;
36     BOOL IoOperationStatus;
37 
38     /* Allocate an overlapped structure. */
39     Overlapped = (LPOVERLAPPED) xcalloc(1, sizeof(OVERLAPPED));
40 
41     if (!Overlapped) {
42         errno = ENOMEM;
43         return -1;
44     }
45 
46 #if _FILE_OFFSET_BITS==64
47 #ifdef __GNUC__
48     Overlapped->Offset = (DWORD) (aiocbp->aio_offset % 0x100000000LL);
49 
50     Overlapped->OffsetHigh = (DWORD) (aiocbp->aio_offset / 0x100000000LL);
51 
52 #else
53 
54     Overlapped->Offset = (DWORD) (aiocbp->aio_offset % 0x100000000);
55 
56     Overlapped->OffsetHigh = (DWORD) (aiocbp->aio_offset / 0x100000000);
57 
58 #endif
59 #else
60 
61     Overlapped->Offset = aiocbp->aio_offset;
62 
63     Overlapped->OffsetHigh = 0;
64 
65 #endif
66 
67     Overlapped->hEvent = aiocbp;
68 
69     aiocbp->aio_sigevent.sigev_notify = EINPROGRESS;
70 
71     aiocbp->aio_sigevent.sigev_signo = -1;
72 
73     IoOperationStatus = ReadFileEx((HANDLE)_get_osfhandle(aiocbp->aio_fildes),
74                                    aiocbp->aio_buf,
75                                    aiocbp->aio_nbytes,
76                                    Overlapped,
77                                    IoCompletionRoutine);
78 
79     /* Test to see if the I/O was queued successfully. */
80     if (!IoOperationStatus) {
81         errno = GetLastError();
82         debugs(81, DBG_IMPORTANT, "aio_read: GetLastError=" << errno  );
83         return -1;
84     }
85 
86     /* The I/O queued successfully. Go back into the
87        alertable wait for I/O completion or for
88        more I/O requests. */
89     return 0;
90 }
91 
aio_read64(struct aiocb64 * aiocbp)92 int aio_read64(struct aiocb64 *aiocbp)
93 {
94     LPOVERLAPPED Overlapped;
95     BOOL IoOperationStatus;
96 
97     /* Allocate an overlapped structure. */
98     Overlapped = (LPOVERLAPPED) xcalloc(1, sizeof(OVERLAPPED));
99 
100     if (!Overlapped) {
101         errno = ENOMEM;
102         return -1;
103     }
104 
105 #ifdef __GNUC__
106     Overlapped->Offset = (DWORD) (aiocbp->aio_offset % 0x100000000LL);
107 
108     Overlapped->OffsetHigh = (DWORD) (aiocbp->aio_offset / 0x100000000LL);
109 
110 #else
111 
112     Overlapped->Offset = (DWORD) (aiocbp->aio_offset % 0x100000000);
113 
114     Overlapped->OffsetHigh = (DWORD) (aiocbp->aio_offset / 0x100000000);
115 
116 #endif
117 
118     Overlapped->hEvent = aiocbp;
119 
120     aiocbp->aio_sigevent.sigev_notify = EINPROGRESS;
121 
122     aiocbp->aio_sigevent.sigev_signo = -1;
123 
124     IoOperationStatus = ReadFileEx((HANDLE)_get_osfhandle(aiocbp->aio_fildes),
125                                    aiocbp->aio_buf,
126                                    aiocbp->aio_nbytes,
127                                    Overlapped,
128                                    IoCompletionRoutine);
129 
130     /* Test to see if the I/O was queued successfully. */
131     if (!IoOperationStatus) {
132         errno = GetLastError();
133         debugs(81, DBG_IMPORTANT, "aio_read: GetLastError=" << errno  );
134         return -1;
135     }
136 
137     /* The I/O queued successfully. Go back into the
138        alertable wait for I/O completion or for
139        more I/O requests. */
140     return 0;
141 }
142 
aio_write(struct aiocb * aiocbp)143 int aio_write(struct aiocb *aiocbp)
144 {
145     LPOVERLAPPED Overlapped;
146     BOOL IoOperationStatus;
147 
148     /* Allocate an overlapped structure. */
149     Overlapped = (LPOVERLAPPED) xcalloc(1, sizeof(OVERLAPPED));
150 
151     if (!Overlapped) {
152         errno = ENOMEM;
153         return -1;
154     }
155 
156 #if _FILE_OFFSET_BITS==64
157 #ifdef __GNUC__
158     Overlapped->Offset = (DWORD) (aiocbp->aio_offset % 0x100000000LL);
159 
160     Overlapped->OffsetHigh = (DWORD) (aiocbp->aio_offset / 0x100000000LL);
161 
162 #else
163 
164     Overlapped->Offset = (DWORD) (aiocbp->aio_offset % 0x100000000);
165 
166     Overlapped->OffsetHigh = (DWORD) (aiocbp->aio_offset / 0x100000000);
167 
168 #endif
169 #else
170 
171     Overlapped->Offset = aiocbp->aio_offset;
172 
173     Overlapped->OffsetHigh = 0;
174 
175 #endif
176 
177     Overlapped->hEvent = aiocbp;
178 
179     aiocbp->aio_sigevent.sigev_notify = EINPROGRESS;
180 
181     aiocbp->aio_sigevent.sigev_signo = -1;
182 
183     IoOperationStatus = WriteFileEx((HANDLE)_get_osfhandle(aiocbp->aio_fildes),
184                                     aiocbp->aio_buf,
185                                     aiocbp->aio_nbytes,
186                                     Overlapped,
187                                     IoCompletionRoutine);
188 
189     /* Test to see if the I/O was queued successfully. */
190     if (!IoOperationStatus) {
191         errno = GetLastError();
192         debugs(81, DBG_IMPORTANT, "aio_write: GetLastError=" << errno  );
193         return -1;
194     }
195 
196     /* The I/O queued successfully. Go back into the
197        alertable wait for I/O completion or for
198        more I/O requests. */
199     return 0;
200 }
201 
aio_write64(struct aiocb64 * aiocbp)202 int aio_write64(struct aiocb64 *aiocbp)
203 {
204     LPOVERLAPPED Overlapped;
205     BOOL IoOperationStatus;
206 
207     /* Allocate an overlapped structure. */
208     Overlapped = (LPOVERLAPPED) xcalloc(1, sizeof(OVERLAPPED));
209 
210     if (!Overlapped) {
211         errno = ENOMEM;
212         return -1;
213     }
214 
215 #ifdef __GNUC__
216     Overlapped->Offset = (DWORD) (aiocbp->aio_offset % 0x100000000LL);
217 
218     Overlapped->OffsetHigh = (DWORD) (aiocbp->aio_offset / 0x100000000LL);
219 
220 #else
221 
222     Overlapped->Offset = (DWORD) (aiocbp->aio_offset % 0x100000000);
223 
224     Overlapped->OffsetHigh = (DWORD) (aiocbp->aio_offset / 0x100000000);
225 
226 #endif
227 
228     Overlapped->hEvent = aiocbp;
229 
230     aiocbp->aio_sigevent.sigev_notify = EINPROGRESS;
231 
232     aiocbp->aio_sigevent.sigev_signo = -1;
233 
234     IoOperationStatus = WriteFileEx((HANDLE)_get_osfhandle(aiocbp->aio_fildes),
235                                     aiocbp->aio_buf,
236                                     aiocbp->aio_nbytes,
237                                     Overlapped,
238                                     IoCompletionRoutine);
239 
240     /* Test to see if the I/O was queued successfully. */
241     if (!IoOperationStatus) {
242         errno = GetLastError();
243         debugs(81, DBG_IMPORTANT, "aio_write: GetLastError=" << errno  );
244         return -1;
245     }
246 
247     /* The I/O queued successfully. Go back into the
248        alertable wait for I/O completion or for
249        more I/O requests. */
250     return 0;
251 }
252 
aio_error(const struct aiocb * aiocbp)253 int aio_error(const struct aiocb * aiocbp)
254 {
255     return aiocbp->aio_sigevent.sigev_notify;
256 }
257 
aio_error64(const struct aiocb64 * aiocbp)258 int aio_error64(const struct aiocb64 * aiocbp)
259 {
260     return aiocbp->aio_sigevent.sigev_notify;
261 }
262 
aio_open(const char * path,int mode)263 int aio_open(const char *path, int mode)
264 {
265     HANDLE hndl;
266     DWORD dwCreationDisposition;
267     DWORD dwDesiredAccess;
268     int fd;
269 
270     if (mode & O_WRONLY)
271         mode |= O_APPEND;
272 
273     mode |= O_BINARY;
274 
275     errno = 0;
276 
277     if (mode & O_WRONLY)
278         dwDesiredAccess = GENERIC_WRITE;
279     else
280         dwDesiredAccess = (mode & O_RDONLY) ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE;
281 
282     if (mode & O_TRUNC)
283         dwCreationDisposition = CREATE_ALWAYS;
284     else
285         dwCreationDisposition = (mode & O_CREAT) ? OPEN_ALWAYS : OPEN_EXISTING;
286 
287     if ((hndl = CreateFile(path,                    /* file name               */
288                            dwDesiredAccess,         /* access mode             */
289                            0,                       /* share mode              */
290                            NULL,                    /* SD                      */
291                            dwCreationDisposition,   /* how to create           */
292                            FILE_FLAG_OVERLAPPED,    /* file attributes         */
293                            NULL                     /* handle to template file */
294                           )) != INVALID_HANDLE_VALUE) {
295         ++ statCounter.syscalls.disk.opens;
296         fd = _open_osfhandle((long) hndl, 0);
297         commSetCloseOnExec(fd);
298         fd_open(fd, FD_FILE, path);
299     } else {
300         errno = GetLastError();
301         fd = DISK_ERROR;
302     }
303 
304     return fd;
305 }
306 
aio_close(int fd)307 void aio_close(int fd)
308 {
309     CloseHandle((HANDLE)_get_osfhandle(fd));
310     fd_close(fd);
311     ++ statCounter.syscalls.disk.closes;
312 }
313 
aio_return(struct aiocb * aiocbp)314 ssize_t aio_return(struct aiocb * aiocbp)
315 {
316     return aiocbp->aio_sigevent.sigev_signo;
317 }
318 
aio_return64(struct aiocb64 * aiocbp)319 ssize_t aio_return64(struct aiocb64 * aiocbp)
320 
321 {
322     return aiocbp->aio_sigevent.sigev_signo;
323 }
324 #endif /* _SQUID_WINDOWS_ */
325 
326