1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 
8 #include "posix.h"
9 
10 #include "path.h"
11 #include <stdio.h>
12 #include <ctype.h>
13 
14 size_t p_fsync__cnt = 0;
15 
16 #ifndef GIT_WIN32
17 
18 #ifdef NO_ADDRINFO
19 
p_getaddrinfo(const char * host,const char * port,struct addrinfo * hints,struct addrinfo ** info)20 int p_getaddrinfo(
21 	const char *host,
22 	const char *port,
23 	struct addrinfo *hints,
24 	struct addrinfo **info)
25 {
26 	struct addrinfo *ainfo, *ai;
27 	int p = 0;
28 
29 	GIT_UNUSED(hints);
30 
31 	if ((ainfo = git__malloc(sizeof(struct addrinfo))) == NULL)
32 		return -1;
33 
34 	if ((ainfo->ai_hostent = gethostbyname(host)) == NULL) {
35 		git__free(ainfo);
36 		return -2;
37 	}
38 
39 	ainfo->ai_servent = getservbyname(port, 0);
40 
41 	if (ainfo->ai_servent)
42 		ainfo->ai_port = ainfo->ai_servent->s_port;
43 	else
44 		ainfo->ai_port = htons(atol(port));
45 
46 	memcpy(&ainfo->ai_addr_in.sin_addr,
47 			ainfo->ai_hostent->h_addr_list[0],
48 			ainfo->ai_hostent->h_length);
49 
50 	ainfo->ai_protocol = 0;
51 	ainfo->ai_socktype = hints->ai_socktype;
52 	ainfo->ai_family = ainfo->ai_hostent->h_addrtype;
53 	ainfo->ai_addr_in.sin_family = ainfo->ai_family;
54 	ainfo->ai_addr_in.sin_port = ainfo->ai_port;
55 	ainfo->ai_addr = (struct addrinfo *)&ainfo->ai_addr_in;
56 	ainfo->ai_addrlen = sizeof(struct sockaddr_in);
57 
58 	*info = ainfo;
59 
60 	if (ainfo->ai_hostent->h_addr_list[1] == NULL) {
61 		ainfo->ai_next = NULL;
62 		return 0;
63 	}
64 
65 	ai = ainfo;
66 
67 	for (p = 1; ainfo->ai_hostent->h_addr_list[p] != NULL; p++) {
68 		if (!(ai->ai_next = git__malloc(sizeof(struct addrinfo)))) {
69 			p_freeaddrinfo(ainfo);
70 			return -1;
71 		}
72 		memcpy(ai->ai_next, ainfo, sizeof(struct addrinfo));
73 		memcpy(&ai->ai_next->ai_addr_in.sin_addr,
74 			ainfo->ai_hostent->h_addr_list[p],
75 			ainfo->ai_hostent->h_length);
76 		ai->ai_next->ai_addr = (struct addrinfo *)&ai->ai_next->ai_addr_in;
77 		ai = ai->ai_next;
78 	}
79 
80 	ai->ai_next = NULL;
81 	return 0;
82 }
83 
p_freeaddrinfo(struct addrinfo * info)84 void p_freeaddrinfo(struct addrinfo *info)
85 {
86 	struct addrinfo *p, *next;
87 
88 	p = info;
89 
90 	while(p != NULL) {
91 		next = p->ai_next;
92 		git__free(p);
93 		p = next;
94 	}
95 }
96 
p_gai_strerror(int ret)97 const char *p_gai_strerror(int ret)
98 {
99 	switch(ret) {
100 	case -1: return "Out of memory"; break;
101 	case -2: return "Address lookup failed"; break;
102 	default: return "Unknown error"; break;
103 	}
104 }
105 
106 #endif /* NO_ADDRINFO */
107 
p_open(const char * path,volatile int flags,...)108 int p_open(const char *path, volatile int flags, ...)
109 {
110 	mode_t mode = 0;
111 
112 	if (flags & O_CREAT) {
113 		va_list arg_list;
114 
115 		va_start(arg_list, flags);
116 		mode = (mode_t)va_arg(arg_list, int);
117 		va_end(arg_list);
118 	}
119 
120 	return open(path, flags | O_BINARY | O_CLOEXEC, mode);
121 }
122 
p_creat(const char * path,mode_t mode)123 int p_creat(const char *path, mode_t mode)
124 {
125 	return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC, mode);
126 }
127 
p_getcwd(char * buffer_out,size_t size)128 int p_getcwd(char *buffer_out, size_t size)
129 {
130 	char *cwd_buffer;
131 
132 	assert(buffer_out && size > 0);
133 
134 	cwd_buffer = getcwd(buffer_out, size);
135 
136 	if (cwd_buffer == NULL)
137 		return -1;
138 
139 	git_path_mkposix(buffer_out);
140 	git_path_string_to_dir(buffer_out, size); /* append trailing slash */
141 
142 	return 0;
143 }
144 
p_rename(const char * from,const char * to)145 int p_rename(const char *from, const char *to)
146 {
147 	if (!link(from, to)) {
148 		p_unlink(from);
149 		return 0;
150 	}
151 
152 	if (!rename(from, to))
153 		return 0;
154 
155 	return -1;
156 }
157 
158 #endif /* GIT_WIN32 */
159 
p_read(git_file fd,void * buf,size_t cnt)160 ssize_t p_read(git_file fd, void *buf, size_t cnt)
161 {
162 	char *b = buf;
163 
164 	if (!git__is_ssizet(cnt)) {
165 #ifdef GIT_WIN32
166 		SetLastError(ERROR_INVALID_PARAMETER);
167 #endif
168 		errno = EINVAL;
169 		return -1;
170 	}
171 
172 	while (cnt) {
173 		ssize_t r;
174 #ifdef GIT_WIN32
175 		r = read(fd, b, cnt > INT_MAX ? INT_MAX : (unsigned int)cnt);
176 #else
177 		r = read(fd, b, cnt);
178 #endif
179 		if (r < 0) {
180 			if (errno == EINTR || errno == EAGAIN)
181 				continue;
182 			return -1;
183 		}
184 		if (!r)
185 			break;
186 		cnt -= r;
187 		b += r;
188 	}
189 	return (b - (char *)buf);
190 }
191 
p_write(git_file fd,const void * buf,size_t cnt)192 int p_write(git_file fd, const void *buf, size_t cnt)
193 {
194 	const char *b = buf;
195 
196 	while (cnt) {
197 		ssize_t r;
198 #ifdef GIT_WIN32
199 		assert((size_t)((unsigned int)cnt) == cnt);
200 		r = write(fd, b, (unsigned int)cnt);
201 #else
202 		r = write(fd, b, cnt);
203 #endif
204 		if (r < 0) {
205 			if (errno == EINTR || GIT_ISBLOCKED(errno))
206 				continue;
207 			return -1;
208 		}
209 		if (!r) {
210 			errno = EPIPE;
211 			return -1;
212 		}
213 		cnt -= r;
214 		b += r;
215 	}
216 	return 0;
217 }
218 
219 #ifdef NO_MMAP
220 
221 #include "map.h"
222 
git__page_size(size_t * page_size)223 int git__page_size(size_t *page_size)
224 {
225 	/* dummy; here we don't need any alignment anyway */
226 	*page_size = 4096;
227 	return 0;
228 }
229 
git__mmap_alignment(size_t * alignment)230 int git__mmap_alignment(size_t *alignment)
231 {
232 	/* dummy; here we don't need any alignment anyway */
233 	*alignment = 4096;
234 	return 0;
235 }
236 
237 
p_mmap(git_map * out,size_t len,int prot,int flags,int fd,off64_t offset)238 int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset)
239 {
240 	GIT_MMAP_VALIDATE(out, len, prot, flags);
241 
242 	out->data = NULL;
243 	out->len = 0;
244 
245 	if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) {
246 		git_error_set(GIT_ERROR_OS, "trying to map shared-writeable");
247 		return -1;
248 	}
249 
250 	out->data = git__malloc(len);
251 	GIT_ERROR_CHECK_ALLOC(out->data);
252 
253 	if (!git__is_ssizet(len) ||
254 		(p_lseek(fd, offset, SEEK_SET) < 0) ||
255 		(p_read(fd, out->data, len) != (ssize_t)len)) {
256 		git_error_set(GIT_ERROR_OS, "mmap emulation failed");
257 		return -1;
258 	}
259 
260 	out->len = len;
261 	return 0;
262 }
263 
p_munmap(git_map * map)264 int p_munmap(git_map *map)
265 {
266 	assert(map != NULL);
267 	git__free(map->data);
268 
269 	return 0;
270 }
271 
272 #endif
273