1 /**
2 * WinPR: Windows Portable Runtime
3 * Asynchronous I/O Functions
4 *
5 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <winpr/io.h>
25
26 #ifndef _WIN32
27
28 #include "io.h"
29
30 #include <stdio.h>
31 #include <fcntl.h>
32 #include <stdlib.h>
33 #include <errno.h>
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41
42 #include <winpr/crt.h>
43 #include <winpr/path.h>
44 #include <winpr/file.h>
45
46 /**
47 * I/O Manager Routines
48 * http://msdn.microsoft.com/en-us/library/windows/hardware/ff551797/
49 *
50 * These routines are only accessible to kernel drivers, but we need
51 * similar functionality in WinPR in user space.
52 *
53 * This is a best effort non-conflicting port of this API meant for
54 * non-Windows, WinPR usage only.
55 *
56 * References:
57 *
58 * Device Objects and Device Stacks:
59 * http://msdn.microsoft.com/en-us/library/windows/hardware/ff543153/
60 *
61 * Driver Development Part 1: Introduction to Drivers:
62 * http://www.codeproject.com/Articles/9504/Driver-Development-Part-1-Introduction-to-Drivers/
63 */
64
65 #define DEVICE_FILE_PREFIX_PATH "\\Device\\"
66
GetDeviceFileNameWithoutPrefixA(LPCSTR lpName)67 static char* GetDeviceFileNameWithoutPrefixA(LPCSTR lpName)
68 {
69 char* lpFileName;
70
71 if (!lpName)
72 return NULL;
73
74 if (strncmp(lpName, DEVICE_FILE_PREFIX_PATH, sizeof(DEVICE_FILE_PREFIX_PATH) - 1) != 0)
75 return NULL;
76
77 lpFileName =
78 _strdup(&lpName[strnlen(DEVICE_FILE_PREFIX_PATH, sizeof(DEVICE_FILE_PREFIX_PATH))]);
79 return lpFileName;
80 }
81
GetDeviceFileUnixDomainSocketBaseFilePathA(void)82 static char* GetDeviceFileUnixDomainSocketBaseFilePathA(void)
83 {
84 char* lpTempPath;
85 char* lpPipePath;
86 lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
87
88 if (!lpTempPath)
89 return NULL;
90
91 lpPipePath = GetCombinedPath(lpTempPath, ".device");
92 free(lpTempPath);
93 return lpPipePath;
94 }
95
GetDeviceFileUnixDomainSocketFilePathA(LPCSTR lpName)96 static char* GetDeviceFileUnixDomainSocketFilePathA(LPCSTR lpName)
97 {
98 char* lpPipePath = NULL;
99 char* lpFileName = NULL;
100 char* lpFilePath = NULL;
101 lpPipePath = GetDeviceFileUnixDomainSocketBaseFilePathA();
102
103 if (!lpPipePath)
104 return NULL;
105
106 lpFileName = GetDeviceFileNameWithoutPrefixA(lpName);
107
108 if (!lpFileName)
109 {
110 free(lpPipePath);
111 return NULL;
112 }
113
114 lpFilePath = GetCombinedPath(lpPipePath, (char*)lpFileName);
115 free(lpPipePath);
116 free(lpFileName);
117 return lpFilePath;
118 }
119
120 /**
121 * IoCreateDevice:
122 * http://msdn.microsoft.com/en-us/library/windows/hardware/ff548397/
123 */
124
_IoCreateDeviceEx(PDRIVER_OBJECT_EX DriverObject,ULONG DeviceExtensionSize,PUNICODE_STRING DeviceName,DEVICE_TYPE DeviceType,ULONG DeviceCharacteristics,BOOLEAN Exclusive,PDEVICE_OBJECT_EX * DeviceObject)125 NTSTATUS _IoCreateDeviceEx(PDRIVER_OBJECT_EX DriverObject, ULONG DeviceExtensionSize,
126 PUNICODE_STRING DeviceName, DEVICE_TYPE DeviceType,
127 ULONG DeviceCharacteristics, BOOLEAN Exclusive,
128 PDEVICE_OBJECT_EX* DeviceObject)
129 {
130 int status;
131 char* DeviceBasePath;
132 DEVICE_OBJECT_EX* pDeviceObjectEx;
133 DeviceBasePath = GetDeviceFileUnixDomainSocketBaseFilePathA();
134
135 if (!DeviceBasePath)
136 return STATUS_NO_MEMORY;
137
138 if (!winpr_PathFileExists(DeviceBasePath))
139 {
140 if (mkdir(DeviceBasePath, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
141 {
142 free(DeviceBasePath);
143 return STATUS_ACCESS_DENIED;
144 }
145 }
146
147 free(DeviceBasePath);
148 pDeviceObjectEx = (DEVICE_OBJECT_EX*)calloc(1, sizeof(DEVICE_OBJECT_EX));
149
150 if (!pDeviceObjectEx)
151 return STATUS_NO_MEMORY;
152
153 ConvertFromUnicode(CP_UTF8, 0, DeviceName->Buffer, DeviceName->Length / 2,
154 &(pDeviceObjectEx->DeviceName), 0, NULL, NULL);
155
156 if (!pDeviceObjectEx->DeviceName)
157 {
158 free(pDeviceObjectEx);
159 return STATUS_NO_MEMORY;
160 }
161
162 pDeviceObjectEx->DeviceFileName =
163 GetDeviceFileUnixDomainSocketFilePathA(pDeviceObjectEx->DeviceName);
164
165 if (!pDeviceObjectEx->DeviceFileName)
166 {
167 free(pDeviceObjectEx->DeviceName);
168 free(pDeviceObjectEx);
169 return STATUS_NO_MEMORY;
170 }
171
172 if (winpr_PathFileExists(pDeviceObjectEx->DeviceFileName))
173 {
174 if (unlink(pDeviceObjectEx->DeviceFileName) == -1)
175 {
176 free(pDeviceObjectEx->DeviceName);
177 free(pDeviceObjectEx->DeviceFileName);
178 free(pDeviceObjectEx);
179 return STATUS_ACCESS_DENIED;
180 }
181 }
182
183 status = mkfifo(pDeviceObjectEx->DeviceFileName, 0666);
184
185 if (status != 0)
186 {
187 free(pDeviceObjectEx->DeviceName);
188 free(pDeviceObjectEx->DeviceFileName);
189 free(pDeviceObjectEx);
190
191 switch (errno)
192 {
193 case EACCES:
194 return STATUS_ACCESS_DENIED;
195
196 case EEXIST:
197 return STATUS_OBJECT_NAME_EXISTS;
198
199 case ENAMETOOLONG:
200 return STATUS_NAME_TOO_LONG;
201
202 case ENOENT:
203 case ENOTDIR:
204 return STATUS_NOT_A_DIRECTORY;
205
206 case ENOSPC:
207 return STATUS_DISK_FULL;
208
209 default:
210 return STATUS_INTERNAL_ERROR;
211 }
212 }
213
214 *((ULONG_PTR*)(DeviceObject)) = (ULONG_PTR)pDeviceObjectEx;
215 return STATUS_SUCCESS;
216 }
217
218 /**
219 * IoDeleteDevice:
220 * http://msdn.microsoft.com/en-us/library/windows/hardware/ff549083/
221 */
222
_IoDeleteDeviceEx(PDEVICE_OBJECT_EX DeviceObject)223 VOID _IoDeleteDeviceEx(PDEVICE_OBJECT_EX DeviceObject)
224 {
225 DEVICE_OBJECT_EX* pDeviceObjectEx;
226 pDeviceObjectEx = (DEVICE_OBJECT_EX*)DeviceObject;
227
228 if (!pDeviceObjectEx)
229 return;
230
231 unlink(pDeviceObjectEx->DeviceFileName);
232 free(pDeviceObjectEx->DeviceName);
233 free(pDeviceObjectEx->DeviceFileName);
234 free(pDeviceObjectEx);
235 }
236
237 #endif
238