0
|
1 /* Distributed Checksum Clearinghouse |
|
2 * |
|
3 * routines to make WIN32 look sort of reasonable |
|
4 * |
|
5 * Copyright (c) 2008 by Rhyolite Software, LLC |
|
6 * |
|
7 * This agreement is not applicable to any entity which sells anti-spam |
|
8 * solutions to others or provides an anti-spam solution as part of a |
|
9 * security solution sold to other entities, or to a private network |
|
10 * which employs the DCC or uses data provided by operation of the DCC |
|
11 * but does not provide corresponding data to other users. |
|
12 * |
|
13 * Permission to use, copy, modify, and distribute this software without |
|
14 * changes for any purpose with or without fee is hereby granted, provided |
|
15 * that the above copyright notice and this permission notice appear in all |
|
16 * copies and any distributed versions or copies are either unchanged |
|
17 * or not called anything similar to "DCC" or "Distributed Checksum |
|
18 * Clearinghouse". |
|
19 * |
|
20 * Parties not eligible to receive a license under this agreement can |
|
21 * obtain a commercial license to use DCC by contacting Rhyolite Software |
|
22 * at sales@rhyolite.com. |
|
23 * |
|
24 * A commercial license would be for Distributed Checksum and Reputation |
|
25 * Clearinghouse software. That software includes additional features. This |
|
26 * free license for Distributed ChecksumClearinghouse Software does not in any |
|
27 * way grant permision to use Distributed Checksum and Reputation Clearinghouse |
|
28 * software |
|
29 * |
|
30 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL |
|
31 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
|
32 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC |
|
33 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES |
|
34 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
35 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
36 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
37 * SOFTWARE. |
|
38 * |
|
39 * Rhyolite Software DCC 1.3.103-1.23 $Revision$ |
|
40 */ |
|
41 |
|
42 |
|
43 #include "dcc_defs.h" |
|
44 |
|
45 #ifdef DCC_WIN32 |
|
46 |
|
47 static DCC_PATH path_tmp; |
|
48 const char *_PATH_TMP = path_tmp; |
|
49 |
|
50 static u_char is_nt; |
|
51 |
|
52 |
|
53 void |
|
54 win32_init(void) |
|
55 { |
|
56 OSVERSIONINFO ver; |
|
57 WSADATA WSAData; |
|
58 |
|
59 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); |
|
60 GetVersionEx(&ver); |
|
61 is_nt = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT); |
|
62 |
|
63 if (WSAStartup(MAKEWORD(2, 0), &WSAData)) |
|
64 dcc_logbad(EX_SOFTWARE, "WSAStartup(): %s", ERROR_STR()); |
|
65 |
|
66 atexit((void(*)(void))WSACleanup); |
|
67 |
|
68 GetTempPath(sizeof(path_tmp), path_tmp); |
|
69 |
|
70 #ifdef __BORLANDC__ |
|
71 _fmode = O_BINARY; |
|
72 #endif |
|
73 } |
|
74 |
|
75 |
|
76 |
|
77 int |
|
78 gettimeofday(struct timeval *tv, struct timezone *tzp) |
|
79 { |
|
80 static SYSTEMTIME epoch_st = {1970, 1, 0, 1, 0, 0, 0, 0}; |
|
81 static LONGLONG epoch; /* the first second of the UNIX epoch */ |
|
82 LONGLONG now; |
|
83 |
|
84 if (epoch == 0) |
|
85 SystemTimeToFileTime(&epoch_st, (FILETIME *)&epoch); |
|
86 GetSystemTimeAsFileTime((FILETIME *)&now); |
|
87 now -= epoch; |
|
88 now /= 10; |
|
89 tv->tv_sec = now/(1000*1000); |
|
90 tv->tv_usec = now%(1000*1000); |
|
91 return 0; |
|
92 } |
|
93 |
|
94 |
|
95 |
|
96 void |
|
97 win32_unmap(HANDLE *hp, void *p, const char *nm) |
|
98 { |
|
99 if (!UnmapViewOfFile(p)) |
|
100 dcc_error_msg("UnmapViewOfFile(%s): %s", nm, ERROR_STR()); |
|
101 if (!CloseHandle(*hp)) |
|
102 dcc_error_msg("CloseHandle(%s): %s", nm, ERROR_STR()); |
|
103 *hp = INVALID_HANDLE_VALUE; |
|
104 } |
|
105 |
|
106 |
|
107 |
|
108 void * |
|
109 win32_map(DCC_EMSG emsg, |
|
110 HANDLE *map_handle, /* put handle for the map here */ |
|
111 const char *nm, /* for this resolved path name */ |
|
112 int fd, /* with this C style file descriptor */ |
|
113 int size) /* with this size (to extend file) */ |
|
114 { |
|
115 static char junk; /* foil optimizer */ |
|
116 DCC_PATH map_nm; |
|
117 HANDLE h; |
|
118 void *p; |
|
119 int i; |
|
120 |
|
121 /* make a name for the mapping */ |
|
122 if (!fnm2abs(map_nm, nm, 0)) |
|
123 STRLCPY(map_nm, nm, sizeof(DCC_PATH)); |
|
124 for (i = 0; i < sizeof(DCC_PATH) && map_nm[i] != '\0'; ++i) { |
|
125 if (map_nm[i] == '/' || map_nm[i] == '\\') |
|
126 map_nm[i] = '-'; |
|
127 } |
|
128 |
|
129 h = CreateFileMapping((HANDLE)_get_osfhandle(fd), |
|
130 0, PAGE_READWRITE, 0, size, map_nm); |
|
131 if (!h) { |
|
132 dcc_pemsg(EX_IOERR, emsg, "CreateFileMapping(%s): %s", |
|
133 nm, ERROR_STR()); |
|
134 *map_handle = INVALID_HANDLE_VALUE; |
|
135 return 0; |
|
136 } |
|
137 p = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0,0, size); |
|
138 if (!p) { |
|
139 dcc_pemsg(EX_IOERR, emsg, "MapViewOfFile(%s): %s", |
|
140 nm, ERROR_STR()); |
|
141 CloseHandle(h); |
|
142 *map_handle = INVALID_HANDLE_VALUE; |
|
143 return 0; |
|
144 } |
|
145 |
|
146 /* If you immediately lock the file, the mapping is garbage on Win98. |
|
147 * It seems to help to poke at the mapping. |
|
148 * One theory is that a page fault on a locked file fails */ |
|
149 for (i = 0; i < size; i += 512) |
|
150 junk += ((char *)p)[i]; |
|
151 |
|
152 *map_handle = h; |
|
153 return p; |
|
154 } |
|
155 |
|
156 |
|
157 |
|
158 /* get an exclusive lock on a file */ |
|
159 u_char |
|
160 win32_lock(HANDLE h, DWORD flags) |
|
161 { |
|
162 OVERLAPPED olap; |
|
163 int e; |
|
164 |
|
165 if (is_nt) { |
|
166 memset(&olap, 0, sizeof(olap)); |
|
167 return LockFileEx(h, flags, 0, 1,0, &olap); |
|
168 } |
|
169 |
|
170 /* this is ugly, but so is Win95 */ |
|
171 for (;;) { |
|
172 if (LockFile(h, 0,0, 1,0)) |
|
173 return 1; |
|
174 e = GetLastError(); |
|
175 if (e != ERROR_LOCKED |
|
176 && e != ERROR_LOCK_VIOLATION |
|
177 && e != ERROR_SHARING_VIOLATION) |
|
178 return 0; |
|
179 Sleep(100); |
|
180 } |
|
181 } |
|
182 |
|
183 |
|
184 |
|
185 u_char |
|
186 win32_unlock(HANDLE h) |
|
187 { |
|
188 return UnlockFile(h, 0,0, 1,0); |
|
189 } |
|
190 |
|
191 |
|
192 |
|
193 /* not all WIN32 systems have snprintf |
|
194 * At least some versions of FormatMessage() do not understand %f |
|
195 * There should be no unsafe sprintf's, so worry only a little */ |
|
196 int |
|
197 dcc_vsnprintf(char *tgt, int tgt_len, const char *pat, va_list args) |
|
198 { |
|
199 char buf[32*1024]; |
|
200 int len; |
|
201 |
|
202 len = vsprintf(buf, pat, args); |
|
203 STRLCPY(tgt, buf, tgt_len); |
|
204 return len; |
|
205 } |
|
206 |
|
207 |
|
208 |
|
209 int |
|
210 dcc_snprintf(char *buf, int buf_len, const char *pat, ...) |
|
211 { |
|
212 int len; |
|
213 va_list args; |
|
214 |
|
215 va_start(args, pat); |
|
216 len = dcc_vsnprintf(buf, buf_len, pat, args); |
|
217 va_end(args); |
|
218 return len; |
|
219 } |
|
220 |
|
221 |
|
222 |
|
223 /* in NT, this should probably have something to do with the event log */ |
|
224 |
|
225 char syslog_prefix[64]; |
|
226 |
|
227 #pragma argsused |
|
228 void |
|
229 openlog(const char *ident, int logopt, int facility) |
|
230 { |
|
231 BUFCPY(syslog_prefix, ident); |
|
232 } |
|
233 |
|
234 |
|
235 |
|
236 #pragma argsused |
|
237 void |
|
238 vsyslog(int priority, const char *msg, va_list args) |
|
239 { |
|
240 struct tm tm; |
|
241 char *bp, buf[sizeof(syslog_prefix)+256]; |
|
242 |
|
243 if (dcc_no_syslog) |
|
244 return; |
|
245 |
|
246 strcpy(buf, syslog_prefix); |
|
247 bp = buf+strlen(buf); |
|
248 dcc_localtime(time(0), &tm); |
|
249 bp += strftime(bp, &buf[sizeof(buf)-3]-bp, " %D %H:%M:%S ", &tm); |
|
250 if (bp >= &buf[sizeof(buf)-3]) |
|
251 bp = &buf[sizeof(buf)-3]; |
|
252 |
|
253 bp += vsnprintf(bp, &buf[sizeof(buf)-3]-bp, msg, args); |
|
254 if (bp >= &buf[sizeof(buf)-3]) |
|
255 bp = &buf[sizeof(buf)-3]; |
|
256 strcpy(bp, "\r\n"); |
|
257 |
|
258 puts(buf); |
|
259 } |
|
260 |
|
261 |
|
262 |
|
263 void |
|
264 syslog(int priority, const char *msg, ...) |
|
265 { |
|
266 va_list args; |
|
267 |
|
268 va_start(args, msg); |
|
269 vsyslog(priority, msg, args); |
|
270 va_end(args); |
|
271 } |
|
272 |
|
273 |
|
274 |
|
275 void |
|
276 closelog(void) |
|
277 { |
|
278 fflush(stdout); |
|
279 fflush(stderr); |
|
280 } |
|
281 |
|
282 |
|
283 /* Strip any CR or LF and convert the strange, non-ASCII |
|
284 * garbage from Microsoft messages |
|
285 * Trim the trailing blanks and '.' from Borland messages */ |
|
286 static void |
|
287 ws_strip(const char *begin, char *tgt, char *end) |
|
288 { |
|
289 const char *src; |
|
290 char c; |
|
291 |
|
292 src = begin; |
|
293 do { |
|
294 if (tgt >= end) { |
|
295 *tgt++ = '\0'; |
|
296 break; |
|
297 } |
|
298 c = *src++; |
|
299 if (c == '\r') /* skip carriage return */ |
|
300 continue; |
|
301 if (c == '\n') |
|
302 c = ' '; |
|
303 if ((c < ' ' && c != '\0') || c > 0x7e) |
|
304 c = '?'; |
|
305 *tgt++ = c; |
|
306 } while (c != '\0'); |
|
307 |
|
308 /* trim trailing whitespace */ |
|
309 --tgt; |
|
310 while (--tgt >= begin |
|
311 && ((c = *tgt) == ' ' || c == '\t' || c == '.')) { |
|
312 *tgt = '\0'; |
|
313 } |
|
314 } |
|
315 |
|
316 |
|
317 |
|
318 /* complete the lame strerror() from Borland for WIN95 */ |
|
319 const char * |
|
320 ws_strerror(int eno) |
|
321 { |
|
322 static struct { |
|
323 char s[256]; |
|
324 } ebufs[8]; |
|
325 static int ebuf_num; |
|
326 int bn; |
|
327 const char *src; |
|
328 char *begin; |
|
329 |
|
330 /* Borland fopen() and who knows what else does not set |
|
331 * the WIN32 GetLastError() value */ |
|
332 #ifdef __BORLANDC__ |
|
333 /* sometimes the Borland wrapper for errno works better */ |
|
334 if (eno == 0) |
|
335 eno = *__errno(); |
|
336 #endif |
|
337 if (eno == 0) |
|
338 return "unknown error"; |
|
339 |
|
340 /* Use an array of static buffers to kludge around problems with |
|
341 * threads */ |
|
342 bn = ebuf_num; |
|
343 ebuf_num = (bn+1) % DIM(ebufs); |
|
344 begin = ebufs[bn].s; |
|
345 |
|
346 /* Use the Microsoft message if it is not silly. */ |
|
347 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, |
|
348 0, eno, 0, begin, sizeof(ebufs[bn].s), 0)) { |
|
349 |
|
350 /* strip any CR or LF and convert the strange, non-ASCII |
|
351 * garbage from Microsoft messages */ |
|
352 ws_strip(begin, begin, begin+sizeof(ebufs[bn].s)-1); |
|
353 if (strlen(begin) < 128) |
|
354 return begin; |
|
355 } |
|
356 |
|
357 /* If Microsoft fails, try the Borland messages, |
|
358 * and use anything other than "unknown error" */ |
|
359 src = strerror(eno); |
|
360 if (strcmp(src, "Unknown error\n")) { |
|
361 ws_strip(src, begin, begin+sizeof(ebufs[bn].s)-1); |
|
362 return begin; |
|
363 } |
|
364 |
|
365 /* MicroSoft has only some of the BSD standard error messages */ |
|
366 switch (eno) { |
|
367 case WSAEACCES: return "SO_BROADCAST not enabled"; |
|
368 case WSAEADDRINUSE: return "address already in use"; |
|
369 case WSAEADDRNOTAVAIL: return "address not available"; |
|
370 case WSAEAFNOSUPPORT: return "Address family not supported"; |
|
371 case WSAEALREADY: return "nonblocking connect in progress"; |
|
372 case WSAEBADF: return "Bad file descriptor"; |
|
373 case WSAECONNABORTED: return "Software caused connection abort"; |
|
374 case WSAECONNREFUSED: return "Connection refused"; |
|
375 case WSAECONNRESET: return "Connection reset by peer"; |
|
376 case WSAEDESTADDRREQ: return "Destination address required"; |
|
377 case WSAEDQUOT: return "Disc quota exceeded"; |
|
378 case WSAEFAULT: return "WS bad address"; |
|
379 case WSAEHOSTDOWN: return "Host is down"; |
|
380 case WSAEHOSTUNREACH: return "No route to host"; |
|
381 case WSAEINPROGRESS: return "winsock 1.1 call in progress"; |
|
382 case WSAEINTR: return "cancelled by WSACancelBlockingCall"; |
|
383 case WSAEINVAL: return "WS invalid argument"; |
|
384 case WSAEISCONN: return "Socket is already connected"; |
|
385 case WSAELOOP: return "Too many levels of symbolic links"; |
|
386 case WSAEMFILE: return "Too many open files"; |
|
387 case WSAEMSGSIZE: return "Message too long"; |
|
388 case WSAENAMETOOLONG: return "File name too long"; |
|
389 case WSAENETDOWN: return "network is down"; |
|
390 case WSAENETRESET: return "Network dropped connection on reset"; |
|
391 case WSAENETUNREACH: return "network is unreachable"; |
|
392 case WSAENOBUFS: return "No buffer space available"; |
|
393 case WSAENOPROTOOPT: return "Protocol not available"; |
|
394 case WSAENOTCONN: return "Socket is not connected"; |
|
395 case WSAENOTEMPTY: return "Directory not empty"; |
|
396 case WSAENOTSOCK: return "socket operation on non-socket"; |
|
397 case WSAEOPNOTSUPP: return "Operation not supported"; |
|
398 case WSAEPFNOSUPPORT: return "Protocol family not supported"; |
|
399 case WSAEPROCLIM: return "Too many processes"; |
|
400 case WSAEPROTONOSUPPORT:return "Protocol not supported"; |
|
401 case WSAEPROTOTYPE: return "Protocol wrong type for socket"; |
|
402 case WSAEREMOTE: return "Too many levels of remote in path"; |
|
403 case WSAESHUTDOWN: return "Can't send after socket shutdown"; |
|
404 case WSAESOCKTNOSUPPORT:return "Socket type not supported"; |
|
405 case WSAESTALE: return "Stale NFS file handle"; |
|
406 case WSAETIMEDOUT: return "Operation timed out"; |
|
407 case WSAETOOMANYREFS: return "Too many references: can't splice"; |
|
408 case WSAEUSERS: return "Too many users"; |
|
409 case WSAEWOULDBLOCK: return "Operation would block"; |
|
410 case WSANOTINITIALISED: return "WSAStartup not done"; |
|
411 case WSAHOST_NOT_FOUND: return "Unknown host"; |
|
412 case WSATRY_AGAIN: return "Host name lookup failure"; |
|
413 case WSANO_RECOVERY: return "Unknown server error"; |
|
414 case WSANO_DATA: return "No address associated with name"; |
|
415 } |
|
416 |
|
417 /* fall back on Borland's "unkonwn error", but admit the error # */ |
|
418 snprintf(begin, sizeof(ebufs[bn].s), "Unknown error %d", eno); |
|
419 return begin; |
|
420 } |
|
421 #endif /* !DCC_WIN32 */ |