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