]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/win32lib.c
Policy: Include config.h first in all .cc
[thirdparty/squid.git] / lib / win32lib.c
1
2 /*
3 * $Id$
4 *
5 * Windows support
6 * AUTHOR: Guido Serassio <serassio@squid-cache.org>
7 * inspired by previous work by Romeo Anghelache & Eric Stern.
8 *
9 * SQUID Web Proxy Cache http://www.squid-cache.org/
10 * ----------------------------------------------------------
11 *
12 * Squid is the result of efforts by numerous individuals from
13 * the Internet community; see the CONTRIBUTORS file for full
14 * details. Many organizations have provided support for Squid's
15 * development; see the SPONSORS file for full details. Squid is
16 * Copyrighted (C) 2001 by the Regents of the University of
17 * California; see the COPYRIGHT file for full details. Squid
18 * incorporates software developed and/or copyrighted by other
19 * sources; see the CREDITS file for full details.
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 *
35 */
36
37 #include "config.h"
38 #include "util.h"
39
40 /* The following code section is part of an EXPERIMENTAL native */
41 /* Windows NT/2000 Squid port - Compiles only on MS Visual C++ */
42 #if defined(_SQUID_MSWIN_)
43
44 #undef strerror
45 #define sys_nerr _sys_nerr
46
47 #undef assert
48 #include <assert.h>
49 #include <stdio.h>
50 #include <fcntl.h>
51 #include "squid_windows.h"
52 #include <string.h>
53 #include <sys/timeb.h>
54 #if HAVE_WIN32_PSAPI
55 #include <psapi.h>
56 #endif
57
58 THREADLOCAL int ws32_result;
59 LPCRITICAL_SECTION dbg_mutex = NULL;
60
61 void GetProcessName(pid_t, char *);
62
63 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
64 size_t
65 getpagesize()
66 {
67 static DWORD system_pagesize = 0;
68 if (!system_pagesize) {
69 SYSTEM_INFO system_info;
70 GetSystemInfo(&system_info);
71 system_pagesize = system_info.dwPageSize;
72 }
73 return system_pagesize;
74 }
75 #endif
76
77 uid_t
78 geteuid(void)
79 {
80 return 100;
81 }
82
83 uid_t
84 getuid(void)
85 {
86 return 100;
87 }
88
89 int
90 setuid(uid_t uid)
91 {
92 return 0;
93 }
94
95 int
96 seteuid(uid_t euid)
97 {
98 return 0;
99 }
100
101 gid_t
102 getegid(void)
103 {
104 return 100;
105 }
106
107 gid_t
108 getgid(void)
109 {
110 return 100;
111 }
112
113 int
114 setgid(gid_t gid)
115 {
116 return 0;
117 }
118
119 int
120 setegid(gid_t egid)
121 {
122 return 0;
123 }
124
125 int
126 chroot(const char *dirname)
127 {
128 if (SetCurrentDirectory(dirname))
129 return 0;
130 else
131 return GetLastError();
132 }
133
134 void
135 GetProcessName(pid_t pid, char *ProcessName)
136 {
137 HANDLE hProcess;
138
139 strcpy(ProcessName, "unknown");
140 #if HAVE_WIN32_PSAPI
141 /* Get a handle to the process. */
142 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
143 PROCESS_VM_READ,
144 FALSE, pid);
145 /* Get the process name. */
146 if (NULL != hProcess) {
147 HMODULE hMod;
148 DWORD cbNeeded;
149
150 if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))
151 GetModuleBaseName(hProcess, hMod, ProcessName, sizeof(ProcessName));
152 else {
153 CloseHandle(hProcess);
154 return;
155 }
156 } else
157 return;
158 CloseHandle(hProcess);
159 #endif
160 }
161
162 int
163 kill(pid_t pid, int sig)
164 {
165 HANDLE hProcess;
166 char MyProcessName[MAX_PATH];
167 char ProcessNameToCheck[MAX_PATH];
168
169 if (sig == 0) {
170 if ((hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
171 PROCESS_VM_READ,
172 FALSE, pid)) == NULL)
173 return -1;
174 else {
175 CloseHandle(hProcess);
176 GetProcessName(getpid(), MyProcessName);
177 GetProcessName(pid, ProcessNameToCheck);
178 if (strcmp(MyProcessName, ProcessNameToCheck) == 0)
179 return 0;
180 return -1;
181 }
182 } else
183 return 0;
184 }
185
186 #if !HAVE_GETTIMEOFDAY
187 int
188 gettimeofday(struct timeval *pcur_time, void *tzp)
189 {
190 struct _timeb current;
191 struct timezone *tz = (struct timezone *) tzp;
192
193 _ftime(&current);
194
195 pcur_time->tv_sec = current.time;
196 pcur_time->tv_usec = current.millitm * 1000L;
197 if (tz) {
198 tz->tz_minuteswest = current.timezone; /* minutes west of Greenwich */
199 tz->tz_dsttime = current.dstflag; /* type of dst correction */
200 }
201 return 0;
202 }
203 #endif
204
205 int
206 statfs(const char *path, struct statfs *sfs)
207 {
208 char drive[4];
209 DWORD spc, bps, freec, totalc;
210 DWORD vsn, maxlen, flags;
211
212 if (!sfs) {
213 errno = EINVAL;
214 return -1;
215 }
216 strncpy(drive, path, 2);
217 drive[2] = '\0';
218 strcat(drive, "\\");
219
220 if (!GetDiskFreeSpace(drive, &spc, &bps, &freec, &totalc)) {
221 errno = ENOENT;
222 return -1;
223 }
224 if (!GetVolumeInformation(drive, NULL, 0, &vsn, &maxlen, &flags, NULL, 0)) {
225 errno = ENOENT;
226 return -1;
227 }
228 sfs->f_type = flags;
229 sfs->f_bsize = spc * bps;
230 sfs->f_blocks = totalc;
231 sfs->f_bfree = sfs->f_bavail = freec;
232 sfs->f_files = -1;
233 sfs->f_ffree = -1;
234 sfs->f_fsid = vsn;
235 sfs->f_namelen = maxlen;
236 return 0;
237 }
238
239 int
240 WIN32_ftruncate(int fd, off_t size)
241 {
242 HANDLE hfile;
243 unsigned int curpos;
244
245 if (fd < 0)
246 return -1;
247
248 hfile = (HANDLE) _get_osfhandle(fd);
249 curpos = SetFilePointer(hfile, 0, NULL, FILE_CURRENT);
250 if (curpos == 0xFFFFFFFF
251 || SetFilePointer(hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF
252 || !SetEndOfFile(hfile)) {
253 int error = GetLastError();
254
255 switch (error) {
256 case ERROR_INVALID_HANDLE:
257 errno = EBADF;
258 break;
259 default:
260 errno = EIO;
261 break;
262 }
263
264 return -1;
265 }
266 return 0;
267 }
268
269 int
270 WIN32_truncate(const char *pathname, off_t length)
271 {
272 int fd;
273 int res = -1;
274
275 fd = open(pathname, O_RDWR);
276
277 if (fd == -1)
278 errno = EBADF;
279 else {
280 res = WIN32_ftruncate(fd, length);
281 _close(fd);
282 }
283
284 return res;
285 }
286
287 static struct _wsaerrtext {
288 int err;
289 const char *errconst;
290 const char *errdesc;
291 } _wsaerrtext[] = {
292
293 {
294 WSA_E_CANCELLED, "WSA_E_CANCELLED", "Lookup cancelled."
295 },
296 {
297 WSA_E_NO_MORE, "WSA_E_NO_MORE", "No more data available."
298 },
299 {
300 WSAEACCES, "WSAEACCES", "Permission denied."
301 },
302 {
303 WSAEADDRINUSE, "WSAEADDRINUSE", "Address already in use."
304 },
305 {
306 WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL", "Cannot assign requested address."
307 },
308 {
309 WSAEAFNOSUPPORT, "WSAEAFNOSUPPORT", "Address family not supported by protocol family."
310 },
311 {
312 WSAEALREADY, "WSAEALREADY", "Operation already in progress."
313 },
314 {
315 WSAEBADF, "WSAEBADF", "Bad file number."
316 },
317 {
318 WSAECANCELLED, "WSAECANCELLED", "Operation cancelled."
319 },
320 {
321 WSAECONNABORTED, "WSAECONNABORTED", "Software caused connection abort."
322 },
323 {
324 WSAECONNREFUSED, "WSAECONNREFUSED", "Connection refused."
325 },
326 {
327 WSAECONNRESET, "WSAECONNRESET", "Connection reset by peer."
328 },
329 {
330 WSAEDESTADDRREQ, "WSAEDESTADDRREQ", "Destination address required."
331 },
332 {
333 WSAEDQUOT, "WSAEDQUOT", "Disk quota exceeded."
334 },
335 {
336 WSAEFAULT, "WSAEFAULT", "Bad address."
337 },
338 {
339 WSAEHOSTDOWN, "WSAEHOSTDOWN", "Host is down."
340 },
341 {
342 WSAEHOSTUNREACH, "WSAEHOSTUNREACH", "No route to host."
343 },
344 {
345 WSAEINPROGRESS, "WSAEINPROGRESS", "Operation now in progress."
346 },
347 {
348 WSAEINTR, "WSAEINTR", "Interrupted function call."
349 },
350 {
351 WSAEINVAL, "WSAEINVAL", "Invalid argument."
352 },
353 {
354 WSAEINVALIDPROCTABLE, "WSAEINVALIDPROCTABLE", "Invalid procedure table from service provider."
355 },
356 {
357 WSAEINVALIDPROVIDER, "WSAEINVALIDPROVIDER", "Invalid service provider version number."
358 },
359 {
360 WSAEISCONN, "WSAEISCONN", "Socket is already connected."
361 },
362 {
363 WSAELOOP, "WSAELOOP", "Too many levels of symbolic links."
364 },
365 {
366 WSAEMFILE, "WSAEMFILE", "Too many open files."
367 },
368 {
369 WSAEMSGSIZE, "WSAEMSGSIZE", "Message too long."
370 },
371 {
372 WSAENAMETOOLONG, "WSAENAMETOOLONG", "File name is too long."
373 },
374 {
375 WSAENETDOWN, "WSAENETDOWN", "Network is down."
376 },
377 {
378 WSAENETRESET, "WSAENETRESET", "Network dropped connection on reset."
379 },
380 {
381 WSAENETUNREACH, "WSAENETUNREACH", "Network is unreachable."
382 },
383 {
384 WSAENOBUFS, "WSAENOBUFS", "No buffer space available."
385 },
386 {
387 WSAENOMORE, "WSAENOMORE", "No more data available."
388 },
389 {
390 WSAENOPROTOOPT, "WSAENOPROTOOPT", "Bad protocol option."
391 },
392 {
393 WSAENOTCONN, "WSAENOTCONN", "Socket is not connected."
394 },
395 {
396 WSAENOTEMPTY, "WSAENOTEMPTY", "Directory is not empty."
397 },
398 {
399 WSAENOTSOCK, "WSAENOTSOCK", "Socket operation on nonsocket."
400 },
401 {
402 WSAEOPNOTSUPP, "WSAEOPNOTSUPP", "Operation not supported."
403 },
404 {
405 WSAEPFNOSUPPORT, "WSAEPFNOSUPPORT", "Protocol family not supported."
406 },
407 {
408 WSAEPROCLIM, "WSAEPROCLIM", "Too many processes."
409 },
410 {
411 WSAEPROTONOSUPPORT, "WSAEPROTONOSUPPORT", "Protocol not supported."
412 },
413 {
414 WSAEPROTOTYPE, "WSAEPROTOTYPE", "Protocol wrong type for socket."
415 },
416 {
417 WSAEPROVIDERFAILEDINIT, "WSAEPROVIDERFAILEDINIT", "Unable to initialise a service provider."
418 },
419 {
420 WSAEREFUSED, "WSAEREFUSED", "Refused."
421 },
422 {
423 WSAEREMOTE, "WSAEREMOTE", "Too many levels of remote in path."
424 },
425 {
426 WSAESHUTDOWN, "WSAESHUTDOWN", "Cannot send after socket shutdown."
427 },
428 {
429 WSAESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT", "Socket type not supported."
430 },
431 {
432 WSAESTALE, "WSAESTALE", "Stale NFS file handle."
433 },
434 {
435 WSAETIMEDOUT, "WSAETIMEDOUT", "Connection timed out."
436 },
437 {
438 WSAETOOMANYREFS, "WSAETOOMANYREFS", "Too many references."
439 },
440 {
441 WSAEUSERS, "WSAEUSERS", "Too many users."
442 },
443 {
444 WSAEWOULDBLOCK, "WSAEWOULDBLOCK", "Resource temporarily unavailable."
445 },
446 {
447 WSANOTINITIALISED, "WSANOTINITIALISED", "Successful WSAStartup not yet performed."
448 },
449 {
450 WSASERVICE_NOT_FOUND, "WSASERVICE_NOT_FOUND", "Service not found."
451 },
452 {
453 WSASYSCALLFAILURE, "WSASYSCALLFAILURE", "System call failure."
454 },
455 {
456 WSASYSNOTREADY, "WSASYSNOTREADY", "Network subsystem is unavailable."
457 },
458 {
459 WSATYPE_NOT_FOUND, "WSATYPE_NOT_FOUND", "Class type not found."
460 },
461 {
462 WSAVERNOTSUPPORTED, "WSAVERNOTSUPPORTED", "Winsock.dll version out of range."
463 },
464 {
465 WSAEDISCON, "WSAEDISCON", "Graceful shutdown in progress."
466 }
467 };
468
469 /*
470 * wsastrerror() - description of WSAGetLastError()
471 */
472 const char *
473 wsastrerror(int err)
474 {
475 static char xwsaerror_buf[BUFSIZ];
476 int i, errind = -1;
477
478 if (err == 0)
479 return "(0) No error.";
480 for (i = 0; i < sizeof(_wsaerrtext) / sizeof(struct _wsaerrtext); i++) {
481 if (_wsaerrtext[i].err != err)
482 continue;
483 errind = i;
484 break;
485 }
486 if (errind == -1)
487 snprintf(xwsaerror_buf, BUFSIZ, "Unknown");
488 else
489 snprintf(xwsaerror_buf, BUFSIZ, "%s, %s", _wsaerrtext[errind].errconst, _wsaerrtext[errind].errdesc);
490 return xwsaerror_buf;
491 }
492
493 struct passwd *
494 getpwnam(char *unused) {
495 static struct passwd pwd = {NULL, NULL, 100, 100, NULL, NULL, NULL};
496 return &pwd;
497 }
498
499 struct group *
500 getgrnam(char *unused) {
501 static struct group grp = {NULL, NULL, 100, NULL};
502 return &grp;
503 }
504
505 /*
506 * WIN32_strerror with argument for late notification */
507
508 const char *
509 WIN32_strerror(int err)
510 {
511 static char xbstrerror_buf[BUFSIZ];
512
513 if (err < 0 || err >= sys_nerr)
514 strncpy(xbstrerror_buf, wsastrerror(err), BUFSIZ);
515 else
516 strncpy(xbstrerror_buf, strerror(err), BUFSIZ);
517 return xbstrerror_buf;
518 }
519
520 #if defined(__MINGW32__) /* MinGW environment */
521 int
522 _free_osfhnd(int filehandle)
523 {
524 if (((unsigned) filehandle < SQUID_MAXFD) &&
525 (_osfile(filehandle) & FOPEN) &&
526 (_osfhnd(filehandle) != (long) INVALID_HANDLE_VALUE)) {
527 switch (filehandle) {
528 case 0:
529 SetStdHandle(STD_INPUT_HANDLE, NULL);
530 break;
531 case 1:
532 SetStdHandle(STD_OUTPUT_HANDLE, NULL);
533 break;
534 case 2:
535 SetStdHandle(STD_ERROR_HANDLE, NULL);
536 break;
537 }
538 _osfhnd(filehandle) = (long) INVALID_HANDLE_VALUE;
539 return (0);
540 } else {
541 errno = EBADF; /* bad handle */
542 _doserrno = 0L; /* not an OS error */
543 return -1;
544 }
545 }
546 #endif
547
548 struct errorentry {
549 unsigned long WIN32_code;
550 int POSIX_errno;
551 };
552
553 static struct errorentry errortable[] = {
554 {ERROR_INVALID_FUNCTION, EINVAL},
555 {ERROR_FILE_NOT_FOUND, ENOENT},
556 {ERROR_PATH_NOT_FOUND, ENOENT},
557 {ERROR_TOO_MANY_OPEN_FILES, EMFILE},
558 {ERROR_ACCESS_DENIED, EACCES},
559 {ERROR_INVALID_HANDLE, EBADF},
560 {ERROR_ARENA_TRASHED, ENOMEM},
561 {ERROR_NOT_ENOUGH_MEMORY, ENOMEM},
562 {ERROR_INVALID_BLOCK, ENOMEM},
563 {ERROR_BAD_ENVIRONMENT, E2BIG},
564 {ERROR_BAD_FORMAT, ENOEXEC},
565 {ERROR_INVALID_ACCESS, EINVAL},
566 {ERROR_INVALID_DATA, EINVAL},
567 {ERROR_INVALID_DRIVE, ENOENT},
568 {ERROR_CURRENT_DIRECTORY, EACCES},
569 {ERROR_NOT_SAME_DEVICE, EXDEV},
570 {ERROR_NO_MORE_FILES, ENOENT},
571 {ERROR_LOCK_VIOLATION, EACCES},
572 {ERROR_BAD_NETPATH, ENOENT},
573 {ERROR_NETWORK_ACCESS_DENIED, EACCES},
574 {ERROR_BAD_NET_NAME, ENOENT},
575 {ERROR_FILE_EXISTS, EEXIST},
576 {ERROR_CANNOT_MAKE, EACCES},
577 {ERROR_FAIL_I24, EACCES},
578 {ERROR_INVALID_PARAMETER, EINVAL},
579 {ERROR_NO_PROC_SLOTS, EAGAIN},
580 {ERROR_DRIVE_LOCKED, EACCES},
581 {ERROR_BROKEN_PIPE, EPIPE},
582 {ERROR_DISK_FULL, ENOSPC},
583 {ERROR_INVALID_TARGET_HANDLE, EBADF},
584 {ERROR_INVALID_HANDLE, EINVAL},
585 {ERROR_WAIT_NO_CHILDREN, ECHILD},
586 {ERROR_CHILD_NOT_COMPLETE, ECHILD},
587 {ERROR_DIRECT_ACCESS_HANDLE, EBADF},
588 {ERROR_NEGATIVE_SEEK, EINVAL},
589 {ERROR_SEEK_ON_DEVICE, EACCES},
590 {ERROR_DIR_NOT_EMPTY, ENOTEMPTY},
591 {ERROR_NOT_LOCKED, EACCES},
592 {ERROR_BAD_PATHNAME, ENOENT},
593 {ERROR_MAX_THRDS_REACHED, EAGAIN},
594 {ERROR_LOCK_FAILED, EACCES},
595 {ERROR_ALREADY_EXISTS, EEXIST},
596 {ERROR_FILENAME_EXCED_RANGE, ENOENT},
597 {ERROR_NESTING_NOT_ALLOWED, EAGAIN},
598 {ERROR_NOT_ENOUGH_QUOTA, ENOMEM}
599 };
600
601 #define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
602 #define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
603
604 #define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
605 #define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
606
607 void
608 WIN32_maperror(unsigned long WIN32_oserrno)
609 {
610 int i;
611
612 _doserrno = WIN32_oserrno;
613 for (i = 0; i < (sizeof(errortable) / sizeof(struct errorentry)); ++i) {
614 if (WIN32_oserrno == errortable[i].WIN32_code) {
615 errno = errortable[i].POSIX_errno;
616 return;
617 }
618 }
619 if (WIN32_oserrno >= MIN_EACCES_RANGE && WIN32_oserrno <= MAX_EACCES_RANGE)
620 errno = EACCES;
621 else if (WIN32_oserrno >= MIN_EXEC_ERROR && WIN32_oserrno <= MAX_EXEC_ERROR)
622 errno = ENOEXEC;
623 else
624 errno = EINVAL;
625 }
626 #endif