#include "../git-compat-util.h"
#include "win32.h"
+#include <conio.h>
#include "../strbuf.h"
-unsigned int _CRT_fmode = _O_BINARY;
+#include <shellapi.h>
static int err_win_to_posix(DWORD winerr)
{
{
va_list args;
unsigned mode;
+ int fd;
+
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);
+
+ 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))
static void free_path_split(char **path)
{
+ char **p = path;
+
if (!path)
return;
- char **p = path;
while (*p)
free(*p++);
free(path);
free_path_split(path);
}
-char **copy_environ()
+static char **copy_environ(void)
{
char **env;
int i = 0;
/*
* If name contains '=', then sets the variable, otherwise it unsets it
*/
-char **env_setenv(char **env, const char *name)
+static char **env_setenv(char **env, const char *name)
{
char *eq = strchrnul(name, '=');
int i = lookup_env(env, name, eq-name);
return env;
}
-/* this is the first function to call into WS_32; initialize it */
-#undef gethostbyname
-struct hostent *mingw_gethostbyname(const char *host)
+/*
+ * Copies global environ and adjusts variables as specified by vars.
+ */
+char **make_augmented_environ(const char *const *vars)
+{
+ char **env = copy_environ();
+
+ while (*vars)
+ env = env_setenv(env, *vars++);
+ return env;
+}
+
+/*
+ * Note, this isn't a complete replacement for getaddrinfo. It assumes
+ * that service contains a numerical port, or that it it is null. It
+ * does a simple search using gethostbyname, and returns one IPv4 host
+ * if one was found.
+ */
+static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
+{
+ struct hostent *h = gethostbyname(node);
+ struct addrinfo *ai;
+ struct sockaddr_in *sin;
+
+ if (!h)
+ return WSAGetLastError();
+
+ ai = xmalloc(sizeof(struct addrinfo));
+ *res = ai;
+ ai->ai_flags = 0;
+ ai->ai_family = AF_INET;
+ ai->ai_socktype = hints->ai_socktype;
+ switch (hints->ai_socktype) {
+ case SOCK_STREAM:
+ ai->ai_protocol = IPPROTO_TCP;
+ break;
+ case SOCK_DGRAM:
+ ai->ai_protocol = IPPROTO_UDP;
+ break;
+ default:
+ ai->ai_protocol = 0;
+ break;
+ }
+ ai->ai_addrlen = sizeof(struct sockaddr_in);
+ ai->ai_canonname = strdup(h->h_name);
+
+ sin = xmalloc(ai->ai_addrlen);
+ memset(sin, 0, ai->ai_addrlen);
+ sin->sin_family = AF_INET;
+ if (service)
+ sin->sin_port = htons(atoi(service));
+ sin->sin_addr = *(struct in_addr *)h->h_addr;
+ ai->ai_addr = (struct sockaddr *)sin;
+ ai->ai_next = 0;
+ return 0;
+}
+
+static void WSAAPI freeaddrinfo_stub(struct addrinfo *res)
+{
+ free(res->ai_canonname);
+ free(res->ai_addr);
+ free(res);
+}
+
+static int WSAAPI getnameinfo_stub(const struct sockaddr *sa, socklen_t salen,
+ char *host, DWORD hostlen,
+ char *serv, DWORD servlen, int flags)
+{
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
+ if (sa->sa_family != AF_INET)
+ return EAI_FAMILY;
+ if (!host && !serv)
+ return EAI_NONAME;
+
+ if (host && hostlen > 0) {
+ struct hostent *ent = NULL;
+ if (!(flags & NI_NUMERICHOST))
+ ent = gethostbyaddr((const char *)&sin->sin_addr,
+ sizeof(sin->sin_addr), AF_INET);
+
+ if (ent)
+ snprintf(host, hostlen, "%s", ent->h_name);
+ else if (flags & NI_NAMEREQD)
+ return EAI_NONAME;
+ else
+ snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
+ }
+
+ if (serv && servlen > 0) {
+ struct servent *ent = NULL;
+ if (!(flags & NI_NUMERICSERV))
+ ent = getservbyport(sin->sin_port,
+ flags & NI_DGRAM ? "udp" : "tcp");
+
+ if (ent)
+ snprintf(serv, servlen, "%s", ent->s_name);
+ else
+ snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
+ }
+
+ return 0;
+}
+
+static HMODULE ipv6_dll = NULL;
+static void (WSAAPI *ipv6_freeaddrinfo)(struct addrinfo *res);
+static int (WSAAPI *ipv6_getaddrinfo)(const char *node, const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **res);
+static int (WSAAPI *ipv6_getnameinfo)(const struct sockaddr *sa, socklen_t salen,
+ char *host, DWORD hostlen,
+ char *serv, DWORD servlen, int flags);
+/*
+ * gai_strerror is an inline function in the ws2tcpip.h header, so we
+ * don't need to try to load that one dynamically.
+ */
+
+static void socket_cleanup(void)
+{
+ WSACleanup();
+ if (ipv6_dll)
+ FreeLibrary(ipv6_dll);
+ ipv6_dll = NULL;
+ ipv6_freeaddrinfo = freeaddrinfo_stub;
+ ipv6_getaddrinfo = getaddrinfo_stub;
+ ipv6_getnameinfo = getnameinfo_stub;
+}
+
+static void ensure_socket_initialization(void)
{
WSADATA wsa;
+ static int initialized = 0;
+ const char *libraries[] = { "ws2_32.dll", "wship6.dll", NULL };
+ const char **name;
+
+ if (initialized)
+ return;
if (WSAStartup(MAKEWORD(2,2), &wsa))
die("unable to initialize winsock subsystem, error %d",
WSAGetLastError());
- atexit((void(*)(void)) WSACleanup);
+
+ for (name = libraries; *name; name++) {
+ ipv6_dll = LoadLibrary(*name);
+ if (!ipv6_dll)
+ continue;
+
+ ipv6_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *))
+ GetProcAddress(ipv6_dll, "freeaddrinfo");
+ ipv6_getaddrinfo = (int (WSAAPI *)(const char *, const char *,
+ const struct addrinfo *,
+ struct addrinfo **))
+ GetProcAddress(ipv6_dll, "getaddrinfo");
+ ipv6_getnameinfo = (int (WSAAPI *)(const struct sockaddr *,
+ socklen_t, char *, DWORD,
+ char *, DWORD, int))
+ GetProcAddress(ipv6_dll, "getnameinfo");
+ if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
+ FreeLibrary(ipv6_dll);
+ ipv6_dll = NULL;
+ } else
+ break;
+ }
+ if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
+ ipv6_freeaddrinfo = freeaddrinfo_stub;
+ ipv6_getaddrinfo = getaddrinfo_stub;
+ ipv6_getnameinfo = getnameinfo_stub;
+ }
+
+ atexit(socket_cleanup);
+ initialized = 1;
+}
+
+#undef gethostbyname
+struct hostent *mingw_gethostbyname(const char *host)
+{
+ ensure_socket_initialization();
return gethostbyname(host);
}
+void mingw_freeaddrinfo(struct addrinfo *res)
+{
+ ipv6_freeaddrinfo(res);
+}
+
+int mingw_getaddrinfo(const char *node, const char *service,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ ensure_socket_initialization();
+ return ipv6_getaddrinfo(node, service, hints, res);
+}
+
+int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *host, DWORD hostlen, char *serv, DWORD servlen,
+ int flags)
+{
+ ensure_socket_initialization();
+ return ipv6_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+}
+
int mingw_socket(int domain, int type, int protocol)
{
int sockfd;
return -1;
}
+/*
+ * Note that this doesn't return the actual pagesize, but
+ * the allocation granularity. If future Windows specific git code
+ * needs the real getpagesize function, we need to find another solution.
+ */
+int mingw_getpagesize(void)
+{
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return si.dwAllocationGranularity;
+}
+
struct passwd *getpwuid(int uid)
{
static char user_name[100];
* length to call the signal handler.
*/
-static __stdcall unsigned ticktack(void *dummy)
+static unsigned __stdcall ticktack(void *dummy)
{
while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
if (timer_fn == SIG_DFL)
#undef signal
sig_handler_t mingw_signal(int sig, sig_handler_t handler)
{
+ sig_handler_t old = timer_fn;
if (sig != SIGALRM)
return signal(sig, handler);
- sig_handler_t old = timer_fn;
timer_fn = handler;
return old;
}
int link(const char *oldpath, const char *newpath)
{
- typedef BOOL WINAPI (*T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
+ typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
static T create_hard_link = NULL;
if (!create_hard_link) {
create_hard_link = (T) GetProcAddress(
fputs("\n", stderr);
return strbuf_detach(&buf, NULL);
}
+
+#ifndef NO_MINGW_REPLACE_READDIR
+/* MinGW readdir implementation to avoid extra lstats for Git */
+struct mingw_DIR
+{
+ struct _finddata_t dd_dta; /* disk transfer area for this dir */
+ struct mingw_dirent dd_dir; /* Our own implementation, including d_type */
+ long dd_handle; /* _findnext handle */
+ int dd_stat; /* 0 = next entry to read is first entry, -1 = off the end, positive = 0 based index of next entry */
+ char dd_name[1]; /* given path for dir with search pattern (struct is extended) */
+};
+
+struct dirent *mingw_readdir(DIR *dir)
+{
+ WIN32_FIND_DATAA buf;
+ HANDLE handle;
+ struct mingw_DIR *mdir = (struct mingw_DIR*)dir;
+
+ if (!dir->dd_handle) {
+ errno = EBADF; /* No set_errno for mingw */
+ return NULL;
+ }
+
+ if (dir->dd_handle == (long)INVALID_HANDLE_VALUE && dir->dd_stat == 0)
+ {
+ DWORD lasterr;
+ handle = FindFirstFileA(dir->dd_name, &buf);
+ lasterr = GetLastError();
+ dir->dd_handle = (long)handle;
+ if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
+ errno = err_win_to_posix(lasterr);
+ return NULL;
+ }
+ } else if (dir->dd_handle == (long)INVALID_HANDLE_VALUE) {
+ return NULL;
+ } else if (!FindNextFileA((HANDLE)dir->dd_handle, &buf)) {
+ DWORD lasterr = GetLastError();
+ FindClose((HANDLE)dir->dd_handle);
+ dir->dd_handle = (long)INVALID_HANDLE_VALUE;
+ /* POSIX says you shouldn't set errno when readdir can't
+ find any more files; so, if another error we leave it set. */
+ if (lasterr != ERROR_NO_MORE_FILES)
+ errno = err_win_to_posix(lasterr);
+ return NULL;
+ }
+
+ /* We get here if `buf' contains valid data. */
+ strcpy(dir->dd_dir.d_name, buf.cFileName);
+ ++dir->dd_stat;
+
+ /* Set file type, based on WIN32_FIND_DATA */
+ mdir->dd_dir.d_type = 0;
+ if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ mdir->dd_dir.d_type |= DT_DIR;
+ else
+ mdir->dd_dir.d_type |= DT_REG;
+
+ return (struct dirent*)&dir->dd_dir;
+}
+#endif // !NO_MINGW_REPLACE_READDIR