| /* | 
 |  * Copyright (C) the libgit2 contributors. All rights reserved. | 
 |  * | 
 |  * This file is part of libgit2, distributed under the GNU GPL v2 with | 
 |  * a Linking Exception. For full terms see the included COPYING file. | 
 |  */ | 
 | #include "common.h" | 
 | #include "posix.h" | 
 | #include "path.h" | 
 | #include <stdio.h> | 
 | #include <ctype.h> | 
 |  | 
 | #ifndef GIT_WIN32 | 
 |  | 
 | #ifdef NO_ADDRINFO | 
 |  | 
 | int p_getaddrinfo( | 
 | 	const char *host, | 
 | 	const char *port, | 
 | 	struct addrinfo *hints, | 
 | 	struct addrinfo **info) | 
 | { | 
 | 	struct addrinfo *ainfo, *ai; | 
 | 	int p = 0; | 
 |  | 
 | 	GIT_UNUSED(hints); | 
 |  | 
 | 	if ((ainfo = malloc(sizeof(struct addrinfo))) == NULL) | 
 | 		return -1; | 
 |  | 
 | 	if ((ainfo->ai_hostent = gethostbyname(host)) == NULL) { | 
 | 		free(ainfo); | 
 | 		return -2; | 
 | 	} | 
 |  | 
 | 	ainfo->ai_servent = getservbyname(port, 0); | 
 |  | 
 | 	if (ainfo->ai_servent) | 
 | 		ainfo->ai_port = ainfo->ai_servent->s_port; | 
 | 	else | 
 | 		ainfo->ai_port = atol(port); | 
 |  | 
 | 	memcpy(&ainfo->ai_addr_in.sin_addr, | 
 | 			ainfo->ai_hostent->h_addr_list[0], | 
 | 			ainfo->ai_hostent->h_length); | 
 |  | 
 | 	ainfo->ai_protocol = 0; | 
 | 	ainfo->ai_socktype = hints->ai_socktype; | 
 | 	ainfo->ai_family = ainfo->ai_hostent->h_addrtype; | 
 | 	ainfo->ai_addr_in.sin_family = ainfo->ai_family; | 
 | 	ainfo->ai_addr_in.sin_port = ainfo->ai_port; | 
 | 	ainfo->ai_addr = (struct addrinfo *)&ainfo->ai_addr_in; | 
 | 	ainfo->ai_addrlen = sizeof(struct sockaddr_in); | 
 |  | 
 | 	*info = ainfo; | 
 |  | 
 | 	if (ainfo->ai_hostent->h_addr_list[1] == NULL) { | 
 | 		ainfo->ai_next = NULL; | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	ai = ainfo; | 
 |  | 
 | 	for (p = 1; ainfo->ai_hostent->h_addr_list[p] != NULL; p++) { | 
 | 		ai->ai_next = malloc(sizeof(struct addrinfo)); | 
 | 		memcpy(&ai->ai_next, ainfo, sizeof(struct addrinfo)); | 
 | 		memcpy(&ai->ai_next->ai_addr_in.sin_addr, | 
 | 			ainfo->ai_hostent->h_addr_list[p], | 
 | 			ainfo->ai_hostent->h_length); | 
 | 		ai->ai_next->ai_addr = (struct addrinfo *)&ai->ai_next->ai_addr_in; | 
 | 		ai = ai->ai_next; | 
 | 	} | 
 |  | 
 | 	ai->ai_next = NULL; | 
 | 	return 0; | 
 | } | 
 |  | 
 | void p_freeaddrinfo(struct addrinfo *info) | 
 | { | 
 | 	struct addrinfo *p, *next; | 
 |  | 
 | 	p = info; | 
 |  | 
 | 	while(p != NULL) { | 
 | 		next = p->ai_next; | 
 | 		free(p); | 
 | 		p = next; | 
 | 	} | 
 | } | 
 |  | 
 | const char *p_gai_strerror(int ret) | 
 | { | 
 | 	switch(ret) { | 
 | 	case -1: return "Out of memory"; break; | 
 | 	case -2: return "Address lookup failed"; break; | 
 | 	default: return "Unknown error"; break; | 
 | 	} | 
 | } | 
 |  | 
 | #endif /* NO_ADDRINFO */ | 
 |  | 
 | int p_open(const char *path, volatile int flags, ...) | 
 | { | 
 | 	mode_t mode = 0; | 
 |  | 
 | 	if (flags & O_CREAT) { | 
 | 		va_list arg_list; | 
 |  | 
 | 		va_start(arg_list, flags); | 
 | 		mode = (mode_t)va_arg(arg_list, int); | 
 | 		va_end(arg_list); | 
 | 	} | 
 |  | 
 | 	return open(path, flags | O_BINARY | O_CLOEXEC, mode); | 
 | } | 
 |  | 
 | int p_creat(const char *path, mode_t mode) | 
 | { | 
 | 	return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC, mode); | 
 | } | 
 |  | 
 | int p_getcwd(char *buffer_out, size_t size) | 
 | { | 
 | 	char *cwd_buffer; | 
 |  | 
 | 	assert(buffer_out && size > 0); | 
 |  | 
 | 	cwd_buffer = getcwd(buffer_out, size); | 
 |  | 
 | 	if (cwd_buffer == NULL) | 
 | 		return -1; | 
 |  | 
 | 	git_path_mkposix(buffer_out); | 
 | 	git_path_string_to_dir(buffer_out, size); /* append trailing slash */ | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int p_rename(const char *from, const char *to) | 
 | { | 
 | 	if (!link(from, to)) { | 
 | 		p_unlink(from); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	if (!rename(from, to)) | 
 | 		return 0; | 
 |  | 
 | 	return -1; | 
 | } | 
 |  | 
 | #endif /* GIT_WIN32 */ | 
 |  | 
 | ssize_t p_read(git_file fd, void *buf, size_t cnt) | 
 | { | 
 | 	char *b = buf; | 
 |  | 
 | 	if (!git__is_ssizet(cnt)) { | 
 | #ifdef GIT_WIN32 | 
 | 		SetLastError(ERROR_INVALID_PARAMETER); | 
 | #endif | 
 | 		errno = EINVAL; | 
 | 		return -1; | 
 | 	} | 
 |  | 
 | 	while (cnt) { | 
 | 		ssize_t r; | 
 | #ifdef GIT_WIN32 | 
 | 		r = read(fd, b, cnt > INT_MAX ? INT_MAX : (unsigned int)cnt); | 
 | #else | 
 | 		r = read(fd, b, cnt); | 
 | #endif | 
 | 		if (r < 0) { | 
 | 			if (errno == EINTR || errno == EAGAIN) | 
 | 				continue; | 
 | 			return -1; | 
 | 		} | 
 | 		if (!r) | 
 | 			break; | 
 | 		cnt -= r; | 
 | 		b += r; | 
 | 	} | 
 | 	return (b - (char *)buf); | 
 | } | 
 |  | 
 | int p_write(git_file fd, const void *buf, size_t cnt) | 
 | { | 
 | 	const char *b = buf; | 
 |  | 
 | 	while (cnt) { | 
 | 		ssize_t r; | 
 | #ifdef GIT_WIN32 | 
 | 		assert((size_t)((unsigned int)cnt) == cnt); | 
 | 		r = write(fd, b, (unsigned int)cnt); | 
 | #else | 
 | 		r = write(fd, b, cnt); | 
 | #endif | 
 | 		if (r < 0) { | 
 | 			if (errno == EINTR || GIT_ISBLOCKED(errno)) | 
 | 				continue; | 
 | 			return -1; | 
 | 		} | 
 | 		if (!r) { | 
 | 			errno = EPIPE; | 
 | 			return -1; | 
 | 		} | 
 | 		cnt -= r; | 
 | 		b += r; | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | #ifdef NO_MMAP | 
 |  | 
 | #include "map.h" | 
 |  | 
 | int git__page_size(size_t *page_size) | 
 | { | 
 | 	/* dummy; here we don't need any alignment anyway */ | 
 | 	*page_size = 4096; | 
 | 	return 0; | 
 | } | 
 |  | 
 |  | 
 | int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) | 
 | { | 
 | 	GIT_MMAP_VALIDATE(out, len, prot, flags); | 
 |  | 
 | 	out->data = NULL; | 
 | 	out->len = 0; | 
 |  | 
 | 	if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) { | 
 | 		giterr_set(GITERR_OS, "Trying to map shared-writeable"); | 
 | 		return -1; | 
 | 	} | 
 |  | 
 | 	out->data = malloc(len); | 
 | 	GITERR_CHECK_ALLOC(out->data); | 
 |  | 
 | 	if (!git__is_ssizet(len) || | 
 | 		(p_lseek(fd, offset, SEEK_SET) < 0) || | 
 | 		(p_read(fd, out->data, len) != (ssize_t)len)) { | 
 | 		giterr_set(GITERR_OS, "mmap emulation failed"); | 
 | 		return -1; | 
 | 	} | 
 |  | 
 | 	out->len = len; | 
 | 	return 0; | 
 | } | 
 |  | 
 | int p_munmap(git_map *map) | 
 | { | 
 | 	assert(map != NULL); | 
 | 	free(map->data); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | #endif |