#include "../git-compat-util.h" unsigned int _CRT_fmode = _O_BINARY; #undef open int mingw_open (const char *filename, int oflags, ...) { va_list args; unsigned mode; va_start(args, oflags); mode = va_arg(args, int); va_end(args); if (!strcmp(filename, "/dev/null")) filename = "nul"; int fd = open(filename, oflags, mode); if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) { DWORD attrs = GetFileAttributes(filename); if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } return fd; } unsigned int sleep (unsigned int seconds) { Sleep(seconds*1000); return 0; } int mkstemp(char *template) { char *filename = mktemp(template); if (filename == NULL) return -1; return open(filename, O_RDWR | O_CREAT, 0600); } int gettimeofday(struct timeval *tv, void *tz) { SYSTEMTIME st; struct tm tm; GetSystemTime(&st); tm.tm_year = st.wYear-1900; tm.tm_mon = st.wMonth-1; tm.tm_mday = st.wDay; tm.tm_hour = st.wHour; tm.tm_min = st.wMinute; tm.tm_sec = st.wSecond; tv->tv_sec = tm_to_time_t(&tm); if (tv->tv_sec < 0) return -1; tv->tv_usec = st.wMilliseconds*1000; return 0; } int poll(struct pollfd *ufds, unsigned int nfds, int timeout) { return -1; } struct tm *gmtime_r(const time_t *timep, struct tm *result) { /* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */ memcpy(result, gmtime(timep), sizeof(struct tm)); return result; } struct tm *localtime_r(const time_t *timep, struct tm *result) { /* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */ memcpy(result, localtime(timep), sizeof(struct tm)); return result; } #undef getcwd char *mingw_getcwd(char *pointer, int len) { int i; char *ret = getcwd(pointer, len); if (!ret) return ret; for (i = 0; pointer[i]; i++) if (pointer[i] == '\\') pointer[i] = '/'; return ret; } #undef rename int mingw_rename(const char *pold, const char *pnew) { /* * Try native rename() first to get errno right. * It is based on MoveFile(), which cannot overwrite existing files. */ if (!rename(pold, pnew)) return 0; if (errno != EEXIST) return -1; if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; /* TODO: translate more errors */ if (GetLastError() == ERROR_ACCESS_DENIED) { DWORD attrs = GetFileAttributes(pnew); if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { errno = EISDIR; return -1; } } errno = EACCES; return -1; } struct passwd *getpwuid(int uid) { static char user_name[100]; static struct passwd p; DWORD len = sizeof(user_name); if (!GetUserName(user_name, &len)) return NULL; p.pw_name = user_name; p.pw_gecos = "unknown"; p.pw_dir = NULL; return &p; } static HANDLE timer_event; static HANDLE timer_thread; static int timer_interval; static int one_shot; static sig_handler_t timer_fn = SIG_DFL; /* The timer works like this: * The thread, ticktack(), is a trivial routine that most of the time * only waits to receive the signal to terminate. The main thread tells * the thread to terminate by setting the timer_event to the signalled * state. * But ticktack() interrupts the wait state after the timer's interval * length to call the signal handler. */ static __stdcall unsigned ticktack(void *dummy) { while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) { if (timer_fn == SIG_DFL) die("Alarm"); if (timer_fn != SIG_IGN) timer_fn(SIGALRM); if (one_shot) break; } return 0; } static int start_timer_thread(void) { timer_event = CreateEvent(NULL, FALSE, FALSE, NULL); if (timer_event) { timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL); if (!timer_thread ) return errno = ENOMEM, error("cannot start timer thread"); } else return errno = ENOMEM, error("cannot allocate resources for timer"); return 0; } static void stop_timer_thread(void) { if (timer_event) SetEvent(timer_event); /* tell thread to terminate */ if (timer_thread) { int rc = WaitForSingleObject(timer_thread, 1000); if (rc == WAIT_TIMEOUT) error("timer thread did not terminate timely"); else if (rc != WAIT_OBJECT_0) error("waiting for timer thread failed: %lu", GetLastError()); CloseHandle(timer_thread); } if (timer_event) CloseHandle(timer_event); timer_event = NULL; timer_thread = NULL; } static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2) { return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec; } int setitimer(int type, struct itimerval *in, struct itimerval *out) { static const struct timeval zero; static int atexit_done; if (out != NULL) return errno = EINVAL, error("setitimer param 3 != NULL not implemented"); if (!is_timeval_eq(&in->it_interval, &zero) && !is_timeval_eq(&in->it_interval, &in->it_value)) return errno = EINVAL, error("setitimer: it_interval must be zero or eq it_value"); if (timer_thread) stop_timer_thread(); if (is_timeval_eq(&in->it_value, &zero) && is_timeval_eq(&in->it_interval, &zero)) return 0; timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000; one_shot = is_timeval_eq(&in->it_interval, &zero); if (!atexit_done) { atexit(stop_timer_thread); atexit_done = 1; } return start_timer_thread(); } int sigaction(int sig, struct sigaction *in, struct sigaction *out) { if (sig != SIGALRM) return errno = EINVAL, error("sigaction only implemented for SIGALRM"); if (out != NULL) return errno = EINVAL, error("sigaction: param 3 != NULL not implemented"); timer_fn = in->sa_handler; return 0; } #undef signal sig_handler_t mingw_signal(int sig, sig_handler_t handler) { if (sig != SIGALRM) return signal(sig, handler); sig_handler_t old = timer_fn; timer_fn = handler; return old; }