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