Logo Search packages:      
Sourcecode: dcc version File versions  Download package

win32.c

/* Distributed Checksum Clearinghouse
 *
 * routines to make WIN32 look sort of reasonable
 *
 * Copyright (c) 2005 by Rhyolite Software
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE
 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 *
 * Rhyolite Software DCC 1.2.74-1.11 $Revision$
 */


#include "dcc_defs.h"

#ifdef DCC_WIN32

#ifdef DCC_WIN32
static DCC_PATH path_tmp;
const char *_PATH_TMP = path_tmp;
#endif

static u_char is_nt;


void
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
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
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 *
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 them mapping
       * use DCC_NM2PATH() in caller */
      STRLIMCPY(map_nm, sizeof(DCC_PATH), nm);
      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.
       * A working 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;
}



u_char
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
win32_unlock(HANDLE h)
{
      return UnlockFile(h, 0,0, 1,0);
}



/* not all WIN32 systems have snprintf */
int
dcc_vsnprintf(char *buf, int buf_len, const char *pat, va_list args)
{
#     define PATBUF_LEN 512
      char c, patbuf[PATBUF_LEN+5+1], msgbuf[PATBUF_LEN*2];
      DWORD lasterror;
      int patlen, patnum, i;

      /* translate from printf to FormatMessage pattern */
      patlen = 0;
      patnum = 0;
      while (patnum < 20 && patlen < PATBUF_LEN && (c = *pat++) != '\0') {
            patbuf[patlen++] = c;
            if (c != '%')
                  continue;

            if (*pat == '%') {
                  patbuf[patlen++] = '%';
                  ++pat;
                  continue;
            }

            if (++patnum >= 10)
                  patbuf[patlen++] = '1';
            patbuf[patlen++] = '0' + (patnum % 10);
            patbuf[patlen++] = '!';
            while (((c = *pat++) == '.' || c == '#' || c == '*'
                  || c == '+' || c == '-' || c == 'l'
                  || (c >= '0' && c <= '9'))
                   && patlen < PATBUF_LEN) {
                  patbuf[patlen++] = c;
            }
            patbuf[patlen++] = c;
            patbuf[patlen++] = '!';
      }
      patbuf[patlen] = '\0';

      /* FormatMessage() fails completely if the buffer is too short
       * so waste time with a temporary buffer. */
      lasterror = GetLastError();
      i = FormatMessage(FORMAT_MESSAGE_FROM_STRING, patbuf,
                    0, 0, msgbuf, sizeof(msgbuf), &args);
      if (!i) {
            sprintf(msgbuf, "FormatMessage() failed: %d", GetLastError());
            i = strlen(msgbuf);
      }
      STRLIMCPY(buf, buf_len, msgbuf);
      SetLastError(lasterror);
      return i;
}



int
dcc_snprintf(char *buf, int buf_len, const char *pat, ...)
{
      int i;
      va_list args;

      va_start(args, pat);
      i = dcc_vsnprintf(buf, buf_len, pat, args);
      va_end(args);
      return i;
}





/* in NT, this should probably have something to do with the event log */

char syslog_prefix[64];

#pragma argsused
void
openlog(const char *ident, int logopt, int facility)
{
      BUFCPY(syslog_prefix, ident);
}



#pragma argsused
void
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
syslog(int priority, const char *msg, ...)
{
      va_list args;

      va_start(args, msg);
      vsyslog(priority, msg, args);
      va_end(args);
}



/* 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[150];
      } 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);
            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";
      }

      /* 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 */

Generated by  Doxygen 1.6.0   Back to index