sync with trunk r47227
[reactos.git] / dll / win32 / kernel32 / file / deviceio.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: kernel32/file/deviceio.c
5 * PURPOSE: Device I/O Base Client Functionality
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <k32.h>
12 #include <wine/debug.h>
13
14 /* FUNCTIONS ******************************************************************/
15
16 /*
17 * @implemented
18 */
19 BOOL
20 WINAPI
21 DeviceIoControl(IN HANDLE hDevice,
22 IN DWORD dwIoControlCode,
23 IN LPVOID lpInBuffer OPTIONAL,
24 IN DWORD nInBufferSize OPTIONAL,
25 OUT LPVOID lpOutBuffer OPTIONAL,
26 IN DWORD nOutBufferSize OPTIONAL,
27 OUT LPDWORD lpBytesReturned OPTIONAL,
28 IN LPOVERLAPPED lpOverlapped OPTIONAL)
29 {
30 BOOL FsIoCtl;
31 NTSTATUS Status;
32 PVOID ApcContext;
33 IO_STATUS_BLOCK Iosb;
34
35 /* Check what kind of IOCTL to send */
36 FsIoCtl = ((dwIoControlCode >> 16) == FILE_DEVICE_FILE_SYSTEM);
37
38 /* CHeck for async */
39 if (lpOverlapped != NULL)
40 {
41 /* Set pending status */
42 lpOverlapped->Internal = STATUS_PENDING;
43
44
45 /* Check if there's an APC context */
46 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
47
48
49 /* Send file system control? */
50 if (FsIoCtl)
51 {
52 /* Send it */
53 Status = NtFsControlFile(hDevice,
54 lpOverlapped->hEvent,
55 NULL,
56 ApcContext,
57 (PIO_STATUS_BLOCK)lpOverlapped,
58 dwIoControlCode,
59 lpInBuffer,
60 nInBufferSize,
61 lpOutBuffer,
62 nOutBufferSize);
63 }
64 else
65 {
66 /* Otherwise send a device control */
67 Status = NtDeviceIoControlFile(hDevice,
68 lpOverlapped->hEvent,
69 NULL,
70 ApcContext,
71 (PIO_STATUS_BLOCK)lpOverlapped,
72 dwIoControlCode,
73 lpInBuffer,
74 nInBufferSize,
75 lpOutBuffer,
76 nOutBufferSize);
77 }
78
79 /* Check for or information instead of failure */
80 if (!(NT_ERROR(Status)) && (lpBytesReturned))
81 {
82 /* Protect with SEH */
83 _SEH2_TRY
84 {
85 /* Return the bytes */
86 *lpBytesReturned = lpOverlapped->InternalHigh;
87 }
88 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
89 {
90 /* Return zero bytes */
91 *lpBytesReturned = 0;
92 }
93 _SEH2_END;
94 }
95
96 /* Now check for any kind of failure except pending*/
97 if (!(NT_SUCCESS(Status)) || (Status == STATUS_PENDING))
98 {
99 /* Fail */
100 SetLastErrorByStatus(Status);
101 return FALSE;
102 }
103 }
104 else
105 {
106 /* Sync case -- send file system code? */
107 if (FsIoCtl)
108 {
109 /* Do it */
110 Status = NtFsControlFile(hDevice,
111 NULL,
112 NULL,
113 NULL,
114 &Iosb,
115 dwIoControlCode,
116 lpInBuffer,
117 nInBufferSize,
118 lpOutBuffer,
119 nOutBufferSize);
120 }
121 else
122 {
123 /* Send device code instead */
124 Status = NtDeviceIoControlFile(hDevice,
125 NULL,
126 NULL,
127 NULL,
128 &Iosb,
129 dwIoControlCode,
130 lpInBuffer,
131 nInBufferSize,
132 lpOutBuffer,
133 nOutBufferSize);
134 }
135
136 /* Now check if the operation isn't done yet */
137 if (Status == STATUS_PENDING)
138 {
139 /* Wait for it and get the final status */
140 Status = NtWaitForSingleObject(hDevice, FALSE, NULL);
141 if (NT_SUCCESS(Status)) Status = Iosb.Status;
142 }
143
144 /* Check for success */
145 if (NT_SUCCESS(Status))
146 {
147 /* Return the byte count */
148 *lpBytesReturned = Iosb.Information;
149 }
150 else
151 {
152 /* Check for informational or warning failure */
153 if (!NT_ERROR(Status)) *lpBytesReturned = Iosb.Information;
154
155 /* Return a failure */
156 SetLastErrorByStatus(Status);
157 return FALSE;
158 }
159 }
160
161 /* Return success */
162 return TRUE;
163 }
164
165
166 /*
167 * @implemented
168 */
169 BOOL
170 WINAPI
171 GetOverlappedResult(IN HANDLE hFile,
172 IN LPOVERLAPPED lpOverlapped,
173 OUT LPDWORD lpNumberOfBytesTransferred,
174 IN BOOL bWait)
175 {
176 DWORD WaitStatus;
177 HANDLE hObject;
178
179
180 /* Check for pending operation */
181 if (lpOverlapped->Internal == STATUS_PENDING)
182 {
183 /* Check if the caller is okay with waiting */
184 if (!bWait)
185 {
186 /* Set timeout */
187 WaitStatus = WAIT_TIMEOUT;
188 }
189 else
190 {
191 /* Wait for the result */
192 hObject = lpOverlapped->hEvent ? lpOverlapped->hEvent : hFile;
193 WaitStatus = WaitForSingleObject(hObject, INFINITE);
194 }
195
196
197 /* Check for timeout */
198 if (WaitStatus == WAIT_TIMEOUT)
199 {
200 /* We have to override the last error with INCOMPLETE instead */
201 SetLastError(ERROR_IO_INCOMPLETE);
202 return FALSE;
203 }
204
205
206 /* Fail if we had an error -- the last error is already set */
207 if (WaitStatus != 0) return FALSE;
208 }
209
210
211 /* Return bytes transferred */
212 *lpNumberOfBytesTransferred = lpOverlapped->InternalHigh;
213
214
215 /* Check for failure during I/O */
216 if (!NT_SUCCESS(lpOverlapped->Internal))
217 {
218 /* Set the error and fail */
219 SetLastErrorByStatus(lpOverlapped->Internal);
220 return FALSE;
221 }
222
223
224 /* All done */
225 return TRUE;
226 }
227
228 /* EOF */
229