/* Distributed Checksum Clearinghouse * * routines to make WIN32 look sort of reasonable * * --C-LICENSE-- * $Revision: 1.26 $ */ #include "dcc_defs.h" #ifdef DCC_WIN32 static DCC_PATH path_tmp; const char *_PATH_TMP = path_tmp; static u_char is_nt; void dcc_win32_init(void) { OSVERSIONINFO ver; WSADATA WSAData; ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&ver); is_nt = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT); if (WSAStartup(MAKEWORD(2, 0), &WSAData)) dcc_logbad(EX_SOFTWARE, "WSAStartup(): %s", ERROR_STR()); atexit((void(*)(void))WSACleanup); GetTempPath(sizeof(path_tmp), path_tmp); #ifdef __BORLANDC__ _fmode = O_BINARY; #endif } int dcc_gettimeofday(struct timeval *tv, struct timezone *tzp) { static SYSTEMTIME epoch_st = {1970, 1, 0, 1, 0, 0, 0, 0}; static LONGLONG epoch; /* the first second of the UNIX epoch */ LONGLONG now; if (epoch == 0) SystemTimeToFileTime(&epoch_st, (FILETIME *)&epoch); GetSystemTimeAsFileTime((FILETIME *)&now); now -= epoch; now /= 10; tv->tv_sec = now/(1000*1000); tv->tv_usec = now%(1000*1000); return 0; } void dcc_win32_unmap(HANDLE *hp, void *p, const char *nm) { if (!UnmapViewOfFile(p)) dcc_error_msg("UnmapViewOfFile(%s): %s", nm, ERROR_STR()); if (!CloseHandle(*hp)) dcc_error_msg("CloseHandle(%s): %s", nm, ERROR_STR()); *hp = INVALID_HANDLE_VALUE; } void * dcc_win32_map(DCC_EMSG emsg, HANDLE *map_handle, /* put handle for the map here */ const char *nm, /* for this resolved path name */ int fd, /* with this C style file descriptor */ int size) /* with this size (to extend file) */ { static char junk; /* foil optimizer */ DCC_PATH map_nm; HANDLE h; void *p; int i; /* make a name for the mapping */ if (!dcc_fnm2abs(map_nm, nm, 0)) STRLCPY(map_nm, nm, sizeof(DCC_PATH)); for (i = 0; i < sizeof(DCC_PATH) && map_nm[i] != '\0'; ++i) { if (map_nm[i] == '/' || map_nm[i] == '\\') map_nm[i] = '-'; } h = CreateFileMapping((HANDLE)_get_osfhandle(fd), 0, PAGE_READWRITE, 0, size, map_nm); if (!h) { dcc_pemsg(EX_IOERR, emsg, "CreateFileMapping(%s): %s", nm, ERROR_STR()); *map_handle = INVALID_HANDLE_VALUE; return 0; } p = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0,0, size); if (!p) { dcc_pemsg(EX_IOERR, emsg, "MapViewOfFile(%s): %s", nm, ERROR_STR()); CloseHandle(h); *map_handle = INVALID_HANDLE_VALUE; return 0; } /* If you immediately lock the file, the mapping is garbage on Win98. * It seems to help to poke at the mapping. * One theory is that a page fault on a locked file fails */ for (i = 0; i < size; i += 512) junk += ((char *)p)[i]; *map_handle = h; return p; } /* get an exclusive lock on a file */ u_char dcc_win32_lock(HANDLE h, DWORD flags) { OVERLAPPED olap; int e; if (is_nt) { memset(&olap, 0, sizeof(olap)); return LockFileEx(h, flags, 0, 1,0, &olap); } /* this is ugly, but so is Win95 */ for (;;) { if (LockFile(h, 0,0, 1,0)) return 1; e = GetLastError(); if (e != ERROR_LOCKED && e != ERROR_LOCK_VIOLATION && e != ERROR_SHARING_VIOLATION) return 0; Sleep(100); } } u_char dcc_win32_unlock(HANDLE h) { return UnlockFile(h, 0,0, 1,0); } /* not all WIN32 systems have snprintf * At least some versions of FormatMessage() do not understand %f * There should be no unsafe sprintf's, so worry only a little */ int dcc_vsnprintf(char *tgt, int tgt_len, const char *pat, va_list args) { char buf[32*1024]; int len; len = vsprintf(buf, pat, args); STRLCPY(tgt, buf, tgt_len); return len; } int dcc_snprintf(char *buf, int buf_len, const char *pat, ...) { int len; va_list args; va_start(args, pat); len = dcc_vsnprintf(buf, buf_len, pat, args); va_end(args); return len; } /* in NT, this should probably have something to do with the event log */ char syslog_prefix[64]; #pragma argsused void dcc_openlog(const char *ident, int logopt, int facility) { BUFCPY(syslog_prefix, ident); } #pragma argsused void dcc_vsyslog(int priority, const char *msg, va_list args) { struct tm tm; char *bp, buf[sizeof(syslog_prefix)+256]; if (dcc_no_syslog) return; strcpy(buf, syslog_prefix); bp = buf+strlen(buf); dcc_localtime(time(0), &tm); bp += strftime(bp, &buf[sizeof(buf)-3]-bp, " %D %H:%M:%S ", &tm); if (bp >= &buf[sizeof(buf)-3]) bp = &buf[sizeof(buf)-3]; bp += vsnprintf(bp, &buf[sizeof(buf)-3]-bp, msg, args); if (bp >= &buf[sizeof(buf)-3]) bp = &buf[sizeof(buf)-3]; strcpy(bp, "\r\n"); puts(buf); } void dcc_syslog(int priority, const char *msg, ...) { va_list args; va_start(args, msg); dcc_vsyslog(priority, msg, args); va_end(args); } void dcc_closelog(void) { fflush(stdout); fflush(stderr); } /* Strip any CR or LF and convert the strange, non-ASCII * garbage from Microsoft messages * Trim the trailing blanks and '.' from Borland messages */ static void ws_strip(const char *begin, char *tgt, char *end) { const char *src; char c; src = begin; do { if (tgt >= end) { *tgt++ = '\0'; break; } c = *src++; if (c == '\r') /* skip carriage return */ continue; if (c == '\n') c = ' '; if ((c < ' ' && c != '\0') || c > 0x7e) c = '?'; *tgt++ = c; } while (c != '\0'); /* trim trailing whitespace */ --tgt; while (--tgt >= begin && ((c = *tgt) == ' ' || c == '\t' || c == '.')) { *tgt = '\0'; } } /* complete the lame strerror() from Borland for WIN95 */ const char * ws_strerror(int eno) { static struct { char s[256]; } ebufs[8]; static int ebuf_num; int bn; const char *src; char *begin; /* Borland fopen() and who knows what else does not set * the WIN32 GetLastError() value */ #ifdef __BORLANDC__ /* sometimes the Borland wrapper for errno works better */ if (eno == 0) eno = *__errno(); #endif if (eno == 0) return "unknown error"; /* Use an array of static buffers to kludge around problems with * threads */ bn = ebuf_num; ebuf_num = (bn+1) % DIM(ebufs); begin = ebufs[bn].s; /* Use the Microsoft message if it is not silly. */ if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, eno, 0, begin, sizeof(ebufs[bn].s), 0)) { /* strip any CR or LF and convert the strange, non-ASCII * garbage from Microsoft messages */ ws_strip(begin, begin, begin+sizeof(ebufs[bn].s)-1); if (strlen(begin) < 128) return begin; } /* If Microsoft fails, try the Borland messages, * and use anything other than "unknown error" */ src = strerror(eno); if (strcmp(src, "Unknown error\n")) { ws_strip(src, begin, begin+sizeof(ebufs[bn].s)-1); return begin; } /* MicroSoft has only some of the BSD standard error messages */ switch (eno) { case WSAEACCES: return "SO_BROADCAST not enabled"; case WSAEADDRINUSE: return "address already in use"; case WSAEADDRNOTAVAIL: return "address not available"; case WSAEAFNOSUPPORT: return "Address family not supported"; case WSAEALREADY: return "nonblocking connect in progress"; case WSAEBADF: return "Bad file descriptor"; case WSAECONNABORTED: return "Software caused connection abort"; case WSAECONNREFUSED: return "Connection refused"; case WSAECONNRESET: return "Connection reset by peer"; case WSAEDESTADDRREQ: return "Destination address required"; case WSAEDQUOT: return "Disc quota exceeded"; case WSAEFAULT: return "WS bad address"; case WSAEHOSTDOWN: return "Host is down"; case WSAEHOSTUNREACH: return "No route to host"; case WSAEINPROGRESS: return "winsock 1.1 call in progress"; case WSAEINTR: return "cancelled by WSACancelBlockingCall"; case WSAEINVAL: return "WS invalid argument"; case WSAEISCONN: return "Socket is already connected"; case WSAELOOP: return "Too many levels of symbolic links"; case WSAEMFILE: return "Too many open files"; case WSAEMSGSIZE: return "Message too long"; case WSAENAMETOOLONG: return "File name too long"; case WSAENETDOWN: return "network is down"; case WSAENETRESET: return "Network dropped connection on reset"; case WSAENETUNREACH: return "network is unreachable"; case WSAENOBUFS: return "No buffer space available"; case WSAENOPROTOOPT: return "Protocol not available"; case WSAENOTCONN: return "Socket is not connected"; case WSAENOTEMPTY: return "Directory not empty"; case WSAENOTSOCK: return "socket operation on non-socket"; case WSAEOPNOTSUPP: return "Operation not supported"; case WSAEPFNOSUPPORT: return "Protocol family not supported"; case WSAEPROCLIM: return "Too many processes"; case WSAEPROTONOSUPPORT:return "Protocol not supported"; case WSAEPROTOTYPE: return "Protocol wrong type for socket"; case WSAEREMOTE: return "Too many levels of remote in path"; case WSAESHUTDOWN: return "Can't send after socket shutdown"; case WSAESOCKTNOSUPPORT:return "Socket type not supported"; case WSAESTALE: return "Stale NFS file handle"; case WSAETIMEDOUT: return "Operation timed out"; case WSAETOOMANYREFS: return "Too many references: can't splice"; case WSAEUSERS: return "Too many users"; case WSAEWOULDBLOCK: return "Operation would block"; case WSANOTINITIALISED: return "WSAStartup not done"; case WSAHOST_NOT_FOUND: return "Unknown host"; case WSATRY_AGAIN: return "Host name lookup failure"; case WSANO_RECOVERY: return "Unknown server error"; case WSANO_DATA: return "No address associated with name"; } /* fall back on Borland's "unkonwn error", but admit the error # */ snprintf(begin, sizeof(ebufs[bn].s), "Unknown error %d", eno); return begin; } #endif /* !DCC_WIN32 */