]> git.ipfire.org Git - thirdparty/squid.git/blob - compat/mswindows.cc
Merged from trunk (r12813).
[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 THREADLOCAL int ws32_result;
57 LPCRITICAL_SECTION dbg_mutex = NULL;
58
59 void GetProcessName(pid_t, char *);
60
61 #if HAVE_GETPAGESIZE > 1
62 size_t
63 getpagesize()
64 {
65 static DWORD system_pagesize = 0;
66 if (!system_pagesize) {
67 SYSTEM_INFO system_info;
68 GetSystemInfo(&system_info);
69 system_pagesize = system_info.dwPageSize;
70 }
71 return system_pagesize;
72 }
73 #endif /* HAVE_GETPAGESIZE > 1 */
74
75 int
76 chroot(const char *dirname)
77 {
78 if (SetCurrentDirectory(dirname))
79 return 0;
80 else
81 return GetLastError();
82 }
83
84 void
85 GetProcessName(pid_t pid, char *ProcessName)
86 {
87 strcpy(ProcessName, "unknown");
88 #if HAVE_WIN32_PSAPI
89 /* Get a handle to the process. */
90 HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
91 /* Get the process name. */
92 if (NULL != hProcess) {
93 HMODULE hMod;
94 DWORD cbNeeded;
95
96 if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))
97 GetModuleBaseName(hProcess, hMod, ProcessName, sizeof(ProcessName));
98 else {
99 CloseHandle(hProcess);
100 return;
101 }
102 } else
103 return;
104 CloseHandle(hProcess);
105 #endif /* HAVE_WIN32_PSAPI */
106 }
107
108 int
109 kill(pid_t pid, int sig)
110 {
111 HANDLE hProcess;
112 char MyProcessName[MAX_PATH];
113 char ProcessNameToCheck[MAX_PATH];
114
115 if (sig == 0) {
116 if ((hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
117 PROCESS_VM_READ,
118 FALSE, pid)) == NULL)
119 return -1;
120 else {
121 CloseHandle(hProcess);
122 GetProcessName(getpid(), MyProcessName);
123 GetProcessName(pid, ProcessNameToCheck);
124 if (strcmp(MyProcessName, ProcessNameToCheck) == 0)
125 return 0;
126 return -1;
127 }
128 } else
129 return 0;
130 }
131
132 #if !HAVE_GETTIMEOFDAY
133 int
134 gettimeofday(struct timeval *pcur_time, void *tzp)
135 {
136 struct _timeb current;
137 struct timezone *tz = (struct timezone *) tzp;
138
139 _ftime(&current);
140
141 pcur_time->tv_sec = current.time;
142 pcur_time->tv_usec = current.millitm * 1000L;
143 if (tz) {
144 tz->tz_minuteswest = current.timezone; /* minutes west of Greenwich */
145 tz->tz_dsttime = current.dstflag; /* type of dst correction */
146 }
147 return 0;
148 }
149 #endif /* !HAVE_GETTIMEOFDAY */
150
151 #if !_SQUID_MINGW_
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 #endif
186
187 #if !_SQUID_MINGW_
188 int
189 WIN32_ftruncate(int fd, off_t size)
190 {
191 HANDLE hfile;
192 unsigned int curpos;
193
194 if (fd < 0)
195 return -1;
196
197 hfile = (HANDLE) _get_osfhandle(fd);
198 curpos = SetFilePointer(hfile, 0, NULL, FILE_CURRENT);
199 if (curpos == 0xFFFFFFFF
200 || SetFilePointer(hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF
201 || !SetEndOfFile(hfile)) {
202 int error = GetLastError();
203
204 switch (error) {
205 case ERROR_INVALID_HANDLE:
206 errno = EBADF;
207 break;
208 default:
209 errno = EIO;
210 break;
211 }
212
213 return -1;
214 }
215 return 0;
216 }
217
218 int
219 WIN32_truncate(const char *pathname, off_t length)
220 {
221 int fd;
222 int res = -1;
223
224 fd = open(pathname, O_RDWR);
225
226 if (fd == -1)
227 errno = EBADF;
228 else {
229 res = WIN32_ftruncate(fd, length);
230 _close(fd);
231 }
232
233 return res;
234 }
235 #endif /* !_SQUID_MINGW_ */
236
237 struct passwd *
238 getpwnam(char *unused) {
239 static struct passwd pwd = {NULL, NULL, 100, 100, NULL, NULL, NULL};
240 return &pwd;
241 }
242
243 struct group *
244 getgrnam(char *unused) {
245 static struct group grp = {NULL, NULL, 100, NULL};
246 return &grp;
247 }
248
249 #if _SQUID_MINGW_
250 int
251 _free_osfhnd(int filehandle)
252 {
253 if (((unsigned) filehandle < SQUID_MAXFD) &&
254 (_osfile(filehandle) & FOPEN) &&
255 (_osfhnd(filehandle) != (long) INVALID_HANDLE_VALUE)) {
256 switch (filehandle) {
257 case 0:
258 SetStdHandle(STD_INPUT_HANDLE, NULL);
259 break;
260 case 1:
261 SetStdHandle(STD_OUTPUT_HANDLE, NULL);
262 break;
263 case 2:
264 SetStdHandle(STD_ERROR_HANDLE, NULL);
265 break;
266 }
267 _osfhnd(filehandle) = (long) INVALID_HANDLE_VALUE;
268 return (0);
269 } else {
270 errno = EBADF; /* bad handle */
271 _doserrno = 0L; /* not an OS error */
272 return -1;
273 }
274 }
275 #endif /* _SQUID_MINGW_ */
276
277 struct errorentry {
278 unsigned long WIN32_code;
279 int POSIX_errno;
280 };
281
282 static struct errorentry errortable[] = {
283 {ERROR_INVALID_FUNCTION, EINVAL},
284 {ERROR_FILE_NOT_FOUND, ENOENT},
285 {ERROR_PATH_NOT_FOUND, ENOENT},
286 {ERROR_TOO_MANY_OPEN_FILES, EMFILE},
287 {ERROR_ACCESS_DENIED, EACCES},
288 {ERROR_INVALID_HANDLE, EBADF},
289 {ERROR_ARENA_TRASHED, ENOMEM},
290 {ERROR_NOT_ENOUGH_MEMORY, ENOMEM},
291 {ERROR_INVALID_BLOCK, ENOMEM},
292 {ERROR_BAD_ENVIRONMENT, E2BIG},
293 {ERROR_BAD_FORMAT, ENOEXEC},
294 {ERROR_INVALID_ACCESS, EINVAL},
295 {ERROR_INVALID_DATA, EINVAL},
296 {ERROR_INVALID_DRIVE, ENOENT},
297 {ERROR_CURRENT_DIRECTORY, EACCES},
298 {ERROR_NOT_SAME_DEVICE, EXDEV},
299 {ERROR_NO_MORE_FILES, ENOENT},
300 {ERROR_LOCK_VIOLATION, EACCES},
301 {ERROR_BAD_NETPATH, ENOENT},
302 {ERROR_NETWORK_ACCESS_DENIED, EACCES},
303 {ERROR_BAD_NET_NAME, ENOENT},
304 {ERROR_FILE_EXISTS, EEXIST},
305 {ERROR_CANNOT_MAKE, EACCES},
306 {ERROR_FAIL_I24, EACCES},
307 {ERROR_INVALID_PARAMETER, EINVAL},
308 {ERROR_NO_PROC_SLOTS, EAGAIN},
309 {ERROR_DRIVE_LOCKED, EACCES},
310 {ERROR_BROKEN_PIPE, EPIPE},
311 {ERROR_DISK_FULL, ENOSPC},
312 {ERROR_INVALID_TARGET_HANDLE, EBADF},
313 {ERROR_INVALID_HANDLE, EINVAL},
314 {ERROR_WAIT_NO_CHILDREN, ECHILD},
315 {ERROR_CHILD_NOT_COMPLETE, ECHILD},
316 {ERROR_DIRECT_ACCESS_HANDLE, EBADF},
317 {ERROR_NEGATIVE_SEEK, EINVAL},
318 {ERROR_SEEK_ON_DEVICE, EACCES},
319 {ERROR_DIR_NOT_EMPTY, ENOTEMPTY},
320 {ERROR_NOT_LOCKED, EACCES},
321 {ERROR_BAD_PATHNAME, ENOENT},
322 {ERROR_MAX_THRDS_REACHED, EAGAIN},
323 {ERROR_LOCK_FAILED, EACCES},
324 {ERROR_ALREADY_EXISTS, EEXIST},
325 {ERROR_FILENAME_EXCED_RANGE, ENOENT},
326 {ERROR_NESTING_NOT_ALLOWED, EAGAIN},
327 {ERROR_NOT_ENOUGH_QUOTA, ENOMEM}
328 };
329
330 #define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
331 #define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
332
333 #define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
334 #define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
335
336 void
337 WIN32_maperror(unsigned long WIN32_oserrno)
338 {
339 _doserrno = WIN32_oserrno;
340 for (size_t i = 0; i < (sizeof(errortable) / sizeof(struct errorentry)); ++i) {
341 if (WIN32_oserrno == errortable[i].WIN32_code) {
342 errno = errortable[i].POSIX_errno;
343 return;
344 }
345 }
346 if (WIN32_oserrno >= MIN_EACCES_RANGE && WIN32_oserrno <= MAX_EACCES_RANGE)
347 errno = EACCES;
348 else if (WIN32_oserrno >= MIN_EXEC_ERROR && WIN32_oserrno <= MAX_EXEC_ERROR)
349 errno = ENOEXEC;
350 else
351 errno = EINVAL;
352 }
353
354 /* syslog emulation layer derived from git */
355 static HANDLE ms_eventlog;
356
357 void
358 openlog(const char *ident, int logopt, int facility)
359 {
360 if (ms_eventlog)
361 return;
362
363 ms_eventlog = RegisterEventSourceA(NULL, ident);
364
365 // note: RegisterEventAtSourceA may fail and return NULL.
366 // in that case we'll just retry at the next message or not log
367 }
368 #define SYSLOG_MAX_MSG_SIZE 1024
369
370 void
371 syslog(int priority, const char *fmt, ...)
372 {
373 WORD logtype;
374 char *str=static_cast<char *>(xmalloc(SYSLOG_MAX_MSG_SIZE));
375 int str_len;
376 va_list ap;
377
378 if (!ms_eventlog)
379 return;
380
381 va_start(ap, fmt);
382 str_len = vsnprintf(str, SYSLOG_MAX_MSG_SIZE-1, fmt, ap);
383 va_end(ap);
384
385 if (str_len < 0) {
386 /* vsnprintf failed */
387 return;
388 }
389
390 switch (priority) {
391 case LOG_EMERG:
392 case LOG_ALERT:
393 case LOG_CRIT:
394 case LOG_ERR:
395 logtype = EVENTLOG_ERROR_TYPE;
396 break;
397
398 case LOG_WARNING:
399 logtype = EVENTLOG_WARNING_TYPE;
400 break;
401
402 case LOG_NOTICE:
403 case LOG_INFO:
404 case LOG_DEBUG:
405 default:
406 logtype = EVENTLOG_INFORMATION_TYPE;
407 break;
408 }
409
410 //Windows API suck. They are overengineered
411 ReportEventA(ms_eventlog, logtype, 0, 0, NULL, 1, 0,
412 const_cast<const char **>(&str), NULL);
413 }
414
415 /* note: this is all MSWindows-specific code; all of it should be conditional */
416 #endif /* _SQUID_WINDOWS_ */