]> git.ipfire.org Git - thirdparty/squid.git/blob - compat/mswindows.cc
Portability: provide xstatvfs() shim for system call statvfs()
[thirdparty/squid.git] / compat / mswindows.cc
1 /*
2 * Copyright (C) 1996-2014 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 /* Windows support
10 * Inspired by previous work by Romeo Anghelache & Eric Stern. */
11
12 #include "squid.h"
13
14 // The following code section is part of an EXPERIMENTAL native Windows NT/2000 Squid port.
15 // Compiles only on MS Visual C++ or MinGW
16 // CygWin appears not to need any of these
17 #if _SQUID_WINDOWS_ && !_SQUID_CYGWIN_
18
19 #define sys_nerr _sys_nerr
20
21 #undef assert
22 #include <cassert>
23 #include <cstring>
24 #include <fcntl.h>
25 #include <sys/timeb.h>
26 #if HAVE_WIN32_PSAPI
27 #include <psapi.h>
28 #endif
29 #ifndef _MSWSOCK_
30 #include <mswsock.h>
31 #endif
32
33 THREADLOCAL int ws32_result;
34 LPCRITICAL_SECTION dbg_mutex = NULL;
35
36 void GetProcessName(pid_t, char *);
37
38 #if HAVE_GETPAGESIZE > 1
39 size_t
40 getpagesize()
41 {
42 static DWORD system_pagesize = 0;
43 if (!system_pagesize) {
44 SYSTEM_INFO system_info;
45 GetSystemInfo(&system_info);
46 system_pagesize = system_info.dwPageSize;
47 }
48 return system_pagesize;
49 }
50 #endif /* HAVE_GETPAGESIZE > 1 */
51
52 int
53 chroot(const char *dirname)
54 {
55 if (SetCurrentDirectory(dirname))
56 return 0;
57 else
58 return GetLastError();
59 }
60
61 void
62 GetProcessName(pid_t pid, char *ProcessName)
63 {
64 strcpy(ProcessName, "unknown");
65 #if HAVE_WIN32_PSAPI
66 /* Get a handle to the process. */
67 HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
68 /* Get the process name. */
69 if (NULL != hProcess) {
70 HMODULE hMod;
71 DWORD cbNeeded;
72
73 if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))
74 GetModuleBaseName(hProcess, hMod, ProcessName, sizeof(ProcessName));
75 else {
76 CloseHandle(hProcess);
77 return;
78 }
79 } else
80 return;
81 CloseHandle(hProcess);
82 #endif /* HAVE_WIN32_PSAPI */
83 }
84
85 int
86 kill(pid_t pid, int sig)
87 {
88 HANDLE hProcess;
89 char MyProcessName[MAX_PATH];
90 char ProcessNameToCheck[MAX_PATH];
91
92 if (sig == 0) {
93 if ((hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
94 PROCESS_VM_READ,
95 FALSE, pid)) == NULL)
96 return -1;
97 else {
98 CloseHandle(hProcess);
99 GetProcessName(getpid(), MyProcessName);
100 GetProcessName(pid, ProcessNameToCheck);
101 if (strcmp(MyProcessName, ProcessNameToCheck) == 0)
102 return 0;
103 return -1;
104 }
105 } else
106 return 0;
107 }
108
109 #if !HAVE_GETTIMEOFDAY
110 int
111 gettimeofday(struct timeval *pcur_time, void *tzp)
112 {
113 struct _timeb current;
114 struct timezone *tz = (struct timezone *) tzp;
115
116 _ftime(&current);
117
118 pcur_time->tv_sec = current.time;
119 pcur_time->tv_usec = current.millitm * 1000L;
120 if (tz) {
121 tz->tz_minuteswest = current.timezone; /* minutes west of Greenwich */
122 tz->tz_dsttime = current.dstflag; /* type of dst correction */
123 }
124 return 0;
125 }
126 #endif /* !HAVE_GETTIMEOFDAY */
127
128 #if !_SQUID_MINGW_
129 int
130 WIN32_ftruncate(int fd, off_t size)
131 {
132 HANDLE hfile;
133 unsigned int curpos;
134
135 if (fd < 0)
136 return -1;
137
138 hfile = (HANDLE) _get_osfhandle(fd);
139 curpos = SetFilePointer(hfile, 0, NULL, FILE_CURRENT);
140 if (curpos == 0xFFFFFFFF
141 || SetFilePointer(hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF
142 || !SetEndOfFile(hfile)) {
143 int error = GetLastError();
144
145 switch (error) {
146 case ERROR_INVALID_HANDLE:
147 errno = EBADF;
148 break;
149 default:
150 errno = EIO;
151 break;
152 }
153
154 return -1;
155 }
156 return 0;
157 }
158
159 int
160 WIN32_truncate(const char *pathname, off_t length)
161 {
162 int fd;
163 int res = -1;
164
165 fd = open(pathname, O_RDWR);
166
167 if (fd == -1)
168 errno = EBADF;
169 else {
170 res = WIN32_ftruncate(fd, length);
171 _close(fd);
172 }
173
174 return res;
175 }
176 #endif /* !_SQUID_MINGW_ */
177
178 struct passwd *
179 getpwnam(char *unused) {
180 static struct passwd pwd = {NULL, NULL, 100, 100, NULL, NULL, NULL};
181 return &pwd;
182 }
183
184 struct group *
185 getgrnam(char *unused) {
186 static struct group grp = {NULL, NULL, 100, NULL};
187 return &grp;
188 }
189
190 #if _SQUID_MINGW_
191 int
192 _free_osfhnd(int filehandle)
193 {
194 if (((unsigned) filehandle < SQUID_MAXFD) &&
195 (_osfile(filehandle) & FOPEN) &&
196 (_osfhnd(filehandle) != (long) INVALID_HANDLE_VALUE)) {
197 switch (filehandle) {
198 case 0:
199 SetStdHandle(STD_INPUT_HANDLE, NULL);
200 break;
201 case 1:
202 SetStdHandle(STD_OUTPUT_HANDLE, NULL);
203 break;
204 case 2:
205 SetStdHandle(STD_ERROR_HANDLE, NULL);
206 break;
207 }
208 _osfhnd(filehandle) = (long) INVALID_HANDLE_VALUE;
209 return (0);
210 } else {
211 errno = EBADF; /* bad handle */
212 _doserrno = 0L; /* not an OS error */
213 return -1;
214 }
215 }
216 #endif /* _SQUID_MINGW_ */
217
218 struct errorentry {
219 unsigned long WIN32_code;
220 int POSIX_errno;
221 };
222
223 static struct errorentry errortable[] = {
224 {ERROR_INVALID_FUNCTION, EINVAL},
225 {ERROR_FILE_NOT_FOUND, ENOENT},
226 {ERROR_PATH_NOT_FOUND, ENOENT},
227 {ERROR_TOO_MANY_OPEN_FILES, EMFILE},
228 {ERROR_ACCESS_DENIED, EACCES},
229 {ERROR_INVALID_HANDLE, EBADF},
230 {ERROR_ARENA_TRASHED, ENOMEM},
231 {ERROR_NOT_ENOUGH_MEMORY, ENOMEM},
232 {ERROR_INVALID_BLOCK, ENOMEM},
233 {ERROR_BAD_ENVIRONMENT, E2BIG},
234 {ERROR_BAD_FORMAT, ENOEXEC},
235 {ERROR_INVALID_ACCESS, EINVAL},
236 {ERROR_INVALID_DATA, EINVAL},
237 {ERROR_INVALID_DRIVE, ENOENT},
238 {ERROR_CURRENT_DIRECTORY, EACCES},
239 {ERROR_NOT_SAME_DEVICE, EXDEV},
240 {ERROR_NO_MORE_FILES, ENOENT},
241 {ERROR_LOCK_VIOLATION, EACCES},
242 {ERROR_BAD_NETPATH, ENOENT},
243 {ERROR_NETWORK_ACCESS_DENIED, EACCES},
244 {ERROR_BAD_NET_NAME, ENOENT},
245 {ERROR_FILE_EXISTS, EEXIST},
246 {ERROR_CANNOT_MAKE, EACCES},
247 {ERROR_FAIL_I24, EACCES},
248 {ERROR_INVALID_PARAMETER, EINVAL},
249 {ERROR_NO_PROC_SLOTS, EAGAIN},
250 {ERROR_DRIVE_LOCKED, EACCES},
251 {ERROR_BROKEN_PIPE, EPIPE},
252 {ERROR_DISK_FULL, ENOSPC},
253 {ERROR_INVALID_TARGET_HANDLE, EBADF},
254 {ERROR_INVALID_HANDLE, EINVAL},
255 {ERROR_WAIT_NO_CHILDREN, ECHILD},
256 {ERROR_CHILD_NOT_COMPLETE, ECHILD},
257 {ERROR_DIRECT_ACCESS_HANDLE, EBADF},
258 {ERROR_NEGATIVE_SEEK, EINVAL},
259 {ERROR_SEEK_ON_DEVICE, EACCES},
260 {ERROR_DIR_NOT_EMPTY, ENOTEMPTY},
261 {ERROR_NOT_LOCKED, EACCES},
262 {ERROR_BAD_PATHNAME, ENOENT},
263 {ERROR_MAX_THRDS_REACHED, EAGAIN},
264 {ERROR_LOCK_FAILED, EACCES},
265 {ERROR_ALREADY_EXISTS, EEXIST},
266 {ERROR_FILENAME_EXCED_RANGE, ENOENT},
267 {ERROR_NESTING_NOT_ALLOWED, EAGAIN},
268 {ERROR_NOT_ENOUGH_QUOTA, ENOMEM}
269 };
270
271 #define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
272 #define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
273
274 #define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
275 #define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
276
277 void
278 WIN32_maperror(unsigned long WIN32_oserrno)
279 {
280 _doserrno = WIN32_oserrno;
281 for (size_t i = 0; i < (sizeof(errortable) / sizeof(struct errorentry)); ++i) {
282 if (WIN32_oserrno == errortable[i].WIN32_code) {
283 errno = errortable[i].POSIX_errno;
284 return;
285 }
286 }
287 if (WIN32_oserrno >= MIN_EACCES_RANGE && WIN32_oserrno <= MAX_EACCES_RANGE)
288 errno = EACCES;
289 else if (WIN32_oserrno >= MIN_EXEC_ERROR && WIN32_oserrno <= MAX_EXEC_ERROR)
290 errno = ENOEXEC;
291 else
292 errno = EINVAL;
293 }
294
295 /* syslog emulation layer derived from git */
296 static HANDLE ms_eventlog;
297
298 void
299 openlog(const char *ident, int logopt, int facility)
300 {
301 if (ms_eventlog)
302 return;
303
304 ms_eventlog = RegisterEventSourceA(NULL, ident);
305
306 // note: RegisterEventAtSourceA may fail and return NULL.
307 // in that case we'll just retry at the next message or not log
308 }
309 #define SYSLOG_MAX_MSG_SIZE 1024
310
311 void
312 syslog(int priority, const char *fmt, ...)
313 {
314 WORD logtype;
315 char *str=static_cast<char *>(xmalloc(SYSLOG_MAX_MSG_SIZE));
316 int str_len;
317 va_list ap;
318
319 if (!ms_eventlog)
320 return;
321
322 va_start(ap, fmt);
323 str_len = vsnprintf(str, SYSLOG_MAX_MSG_SIZE-1, fmt, ap);
324 va_end(ap);
325
326 if (str_len < 0) {
327 /* vsnprintf failed */
328 return;
329 }
330
331 switch (priority) {
332 case LOG_EMERG:
333 case LOG_ALERT:
334 case LOG_CRIT:
335 case LOG_ERR:
336 logtype = EVENTLOG_ERROR_TYPE;
337 break;
338
339 case LOG_WARNING:
340 logtype = EVENTLOG_WARNING_TYPE;
341 break;
342
343 case LOG_NOTICE:
344 case LOG_INFO:
345 case LOG_DEBUG:
346 default:
347 logtype = EVENTLOG_INFORMATION_TYPE;
348 break;
349 }
350
351 //Windows API suck. They are overengineered
352 ReportEventA(ms_eventlog, logtype, 0, 0, NULL, 1, 0,
353 const_cast<const char **>(&str), NULL);
354 }
355
356 /* note: this is all MSWindows-specific code; all of it should be conditional */
357 #endif /* _SQUID_WINDOWS_ */