1 /**
2 * WinPR: Windows Portable Runtime
3 * File Functions
4 *
5 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 * Copyright 2014 Hewlett-Packard Development Company, L.P.
7 * Copyright 2015 Thincast Technologies GmbH
8 * Copyright 2015 bernhard.miklautz@thincast.com
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <winpr/crt.h>
27 #include <winpr/path.h>
28 #include <winpr/file.h>
29
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33
34 #include "../log.h"
35 #define TAG WINPR_TAG("file")
36
37 #ifndef _WIN32
38
39 #ifdef ANDROID
40 #include <sys/vfs.h>
41 #else
42 #include <sys/statvfs.h>
43 #endif
44
45 #include "../handle/handle.h"
46
47 #include "../pipe/pipe.h"
48
49 static HANDLE_CREATOR _NamedPipeClientHandleCreator;
50
NamedPipeClientIsHandled(HANDLE handle)51 static BOOL NamedPipeClientIsHandled(HANDLE handle)
52 {
53 WINPR_NAMED_PIPE* pFile = (WINPR_NAMED_PIPE*)handle;
54
55 if (!pFile || (pFile->Type != HANDLE_TYPE_NAMED_PIPE) || (pFile == INVALID_HANDLE_VALUE))
56 {
57 SetLastError(ERROR_INVALID_HANDLE);
58 return FALSE;
59 }
60
61 return TRUE;
62 }
63
NamedPipeClientCloseHandle(HANDLE handle)64 static BOOL NamedPipeClientCloseHandle(HANDLE handle)
65 {
66 WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)handle;
67
68 if (!NamedPipeClientIsHandled(handle))
69 return FALSE;
70
71 if (pNamedPipe->clientfd != -1)
72 {
73 // WLOG_DBG(TAG, "closing clientfd %d", pNamedPipe->clientfd);
74 close(pNamedPipe->clientfd);
75 }
76
77 if (pNamedPipe->serverfd != -1)
78 {
79 // WLOG_DBG(TAG, "closing serverfd %d", pNamedPipe->serverfd);
80 close(pNamedPipe->serverfd);
81 }
82
83 if (pNamedPipe->pfnUnrefNamedPipe)
84 pNamedPipe->pfnUnrefNamedPipe(pNamedPipe);
85
86 free(pNamedPipe->lpFileName);
87 free(pNamedPipe->lpFilePath);
88 free(pNamedPipe->name);
89 free(pNamedPipe);
90 return TRUE;
91 }
92
NamedPipeClientGetFd(HANDLE handle)93 static int NamedPipeClientGetFd(HANDLE handle)
94 {
95 WINPR_NAMED_PIPE* file = (WINPR_NAMED_PIPE*)handle;
96
97 if (!NamedPipeClientIsHandled(handle))
98 return -1;
99
100 if (file->ServerMode)
101 return file->serverfd;
102 else
103 return file->clientfd;
104 }
105
106 static HANDLE_OPS ops = {
107 NamedPipeClientIsHandled,
108 NamedPipeClientCloseHandle,
109 NamedPipeClientGetFd,
110 NULL, /* CleanupHandle */
111 NamedPipeRead,
112 NULL, /* FileReadEx */
113 NULL, /* FileReadScatter */
114 NamedPipeWrite,
115 NULL, /* FileWriteEx */
116 NULL, /* FileWriteGather */
117 NULL, /* FileGetFileSize */
118 NULL, /* FlushFileBuffers */
119 NULL, /* FileSetEndOfFile */
120 NULL, /* FileSetFilePointer */
121 NULL, /* SetFilePointerEx */
122 NULL, /* FileLockFile */
123 NULL, /* FileLockFileEx */
124 NULL, /* FileUnlockFile */
125 NULL, /* FileUnlockFileEx */
126 NULL /* SetFileTime */
127 };
128
NamedPipeClientCreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)129 static HANDLE NamedPipeClientCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess,
130 DWORD dwShareMode,
131 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
132 DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
133 HANDLE hTemplateFile)
134 {
135 char* name;
136 int status;
137 HANDLE hNamedPipe;
138 struct sockaddr_un s;
139 WINPR_NAMED_PIPE* pNamedPipe;
140
141 if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
142 {
143 WLog_ERR(TAG, "WinPR %s does not support the FILE_FLAG_OVERLAPPED flag", __FUNCTION__);
144 SetLastError(ERROR_NOT_SUPPORTED);
145 return INVALID_HANDLE_VALUE;
146 }
147
148 if (!lpFileName)
149 return INVALID_HANDLE_VALUE;
150
151 if (!IsNamedPipeFileNameA(lpFileName))
152 return INVALID_HANDLE_VALUE;
153
154 name = GetNamedPipeNameWithoutPrefixA(lpFileName);
155
156 if (!name)
157 return INVALID_HANDLE_VALUE;
158
159 free(name);
160 pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE));
161
162 if (!pNamedPipe)
163 {
164 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
165 return INVALID_HANDLE_VALUE;
166 }
167
168 hNamedPipe = (HANDLE)pNamedPipe;
169 WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ);
170 pNamedPipe->name = _strdup(lpFileName);
171
172 if (!pNamedPipe->name)
173 {
174 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
175 free(pNamedPipe);
176 return INVALID_HANDLE_VALUE;
177 }
178
179 pNamedPipe->dwOpenMode = 0;
180 pNamedPipe->dwPipeMode = 0;
181 pNamedPipe->nMaxInstances = 0;
182 pNamedPipe->nOutBufferSize = 0;
183 pNamedPipe->nInBufferSize = 0;
184 pNamedPipe->nDefaultTimeOut = 0;
185 pNamedPipe->dwFlagsAndAttributes = dwFlagsAndAttributes;
186 pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName);
187
188 if (!pNamedPipe->lpFileName)
189 {
190 free((void*)pNamedPipe->name);
191 free(pNamedPipe);
192 return INVALID_HANDLE_VALUE;
193 }
194
195 pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName);
196
197 if (!pNamedPipe->lpFilePath)
198 {
199 free((void*)pNamedPipe->lpFileName);
200 free((void*)pNamedPipe->name);
201 free(pNamedPipe);
202 return INVALID_HANDLE_VALUE;
203 }
204
205 pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0);
206 pNamedPipe->serverfd = -1;
207 pNamedPipe->ServerMode = FALSE;
208 ZeroMemory(&s, sizeof(struct sockaddr_un));
209 s.sun_family = AF_UNIX;
210 sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath);
211 status = connect(pNamedPipe->clientfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un));
212 pNamedPipe->ops = &ops;
213
214 if (status != 0)
215 {
216 close(pNamedPipe->clientfd);
217 free((char*)pNamedPipe->name);
218 free((char*)pNamedPipe->lpFileName);
219 free((char*)pNamedPipe->lpFilePath);
220 free(pNamedPipe);
221 return INVALID_HANDLE_VALUE;
222 }
223
224 if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
225 {
226 #if 0
227 int flags = fcntl(pNamedPipe->clientfd, F_GETFL);
228
229 if (flags != -1)
230 fcntl(pNamedPipe->clientfd, F_SETFL, flags | O_NONBLOCK);
231
232 #endif
233 }
234
235 return hNamedPipe;
236 }
237
GetNamedPipeClientHandleCreator(void)238 HANDLE_CREATOR* GetNamedPipeClientHandleCreator(void)
239 {
240 _NamedPipeClientHandleCreator.IsHandled = IsNamedPipeFileNameA;
241 _NamedPipeClientHandleCreator.CreateFileA = NamedPipeClientCreateFileA;
242 return &_NamedPipeClientHandleCreator;
243 }
244
245 #endif
246
247 /* Extended API */
248
249 #define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\"
250
IsNamedPipeFileNameA(LPCSTR lpName)251 BOOL IsNamedPipeFileNameA(LPCSTR lpName)
252 {
253 if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0)
254 return FALSE;
255
256 return TRUE;
257 }
258
GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)259 char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)
260 {
261 char* lpFileName;
262
263 if (!lpName)
264 return NULL;
265
266 if (!IsNamedPipeFileNameA(lpName))
267 return NULL;
268
269 lpFileName = _strdup(&lpName[strnlen(NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH))]);
270 return lpFileName;
271 }
272
GetNamedPipeUnixDomainSocketBaseFilePathA()273 char* GetNamedPipeUnixDomainSocketBaseFilePathA()
274 {
275 char* lpTempPath;
276 char* lpPipePath;
277 lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
278
279 if (!lpTempPath)
280 return NULL;
281
282 lpPipePath = GetCombinedPath(lpTempPath, ".pipe");
283 free(lpTempPath);
284 return lpPipePath;
285 }
286
GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName)287 char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName)
288 {
289 char* lpPipePath;
290 char* lpFileName;
291 char* lpFilePath;
292 lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
293 lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
294 lpFilePath = GetCombinedPath(lpPipePath, (char*)lpFileName);
295 free(lpPipePath);
296 free(lpFileName);
297 return lpFilePath;
298 }
299
GetNamePipeFileDescriptor(HANDLE hNamedPipe)300 int GetNamePipeFileDescriptor(HANDLE hNamedPipe)
301 {
302 #ifndef _WIN32
303 int fd;
304 WINPR_NAMED_PIPE* pNamedPipe;
305 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
306
307 if (!pNamedPipe || pNamedPipe->Type != HANDLE_TYPE_NAMED_PIPE)
308 return -1;
309
310 fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
311 return fd;
312 #else
313 return -1;
314 #endif
315 }
316