posix.c 5.56 KB
Newer Older
Vicent Marti committed
1
/*
Edward Thomson committed
2
 * Copyright (C) the libgit2 contributors. All rights reserved.
Vicent Marti committed
3 4 5 6
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */
7

Vicent Marti committed
8
#include "posix.h"
9

10
#include "fs_path.h"
Vicent Marti committed
11 12 13
#include <stdio.h>
#include <ctype.h>

14 15
size_t p_fsync__cnt = 0;

16 17
#ifndef GIT_WIN32

Vicent Marti committed
18
#ifdef NO_ADDRINFO
19

Vicent Marti committed
20 21 22 23 24 25 26 27
int p_getaddrinfo(
	const char *host,
	const char *port,
	struct addrinfo *hints,
	struct addrinfo **info)
{
	struct addrinfo *ainfo, *ai;
	int p = 0;
28 29 30

	GIT_UNUSED(hints);

31
	if ((ainfo = git__malloc(sizeof(struct addrinfo))) == NULL)
Vicent Marti committed
32
		return -1;
33 34

	if ((ainfo->ai_hostent = gethostbyname(host)) == NULL) {
35
		git__free(ainfo);
Vicent Marti committed
36
		return -2;
37 38
	}

Vicent Marti committed
39
	ainfo->ai_servent = getservbyname(port, 0);
40

Vicent Marti committed
41 42 43
	if (ainfo->ai_servent)
		ainfo->ai_port = ainfo->ai_servent->s_port;
	else
44
		ainfo->ai_port = htons(atol(port));
Vicent Marti committed
45 46 47 48 49 50 51 52 53 54 55 56 57 58

	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;
59

Vicent Marti committed
60 61 62 63
	if (ainfo->ai_hostent->h_addr_list[1] == NULL) {
		ainfo->ai_next = NULL;
		return 0;
	}
64

Vicent Marti committed
65
	ai = ainfo;
66

Vicent Marti committed
67
	for (p = 1; ainfo->ai_hostent->h_addr_list[p] != NULL; p++) {
68
		if (!(ai->ai_next = git__malloc(sizeof(struct addrinfo)))) {
69 70 71
			p_freeaddrinfo(ainfo);
			return -1;
		}
72
		memcpy(ai->ai_next, ainfo, sizeof(struct addrinfo));
Vicent Marti committed
73 74 75 76 77 78
		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;
	}
79

Vicent Marti committed
80 81 82 83 84 85 86
	ai->ai_next = NULL;
	return 0;
}

void p_freeaddrinfo(struct addrinfo *info)
{
	struct addrinfo *p, *next;
87

Vicent Marti committed
88
	p = info;
89

Vicent Marti committed
90 91
	while(p != NULL) {
		next = p->ai_next;
92
		git__free(p);
Vicent Marti committed
93 94 95 96 97 98 99
		p = next;
	}
}

const char *p_gai_strerror(int ret)
{
	switch(ret) {
100 101 102
	case -1: return "Out of memory"; break;
	case -2: return "Address lookup failed"; break;
	default: return "Unknown error"; break;
Vicent Marti committed
103 104
	}
}
105

Vicent Marti committed
106 107
#endif /* NO_ADDRINFO */

108
int p_open(const char *path, volatile int flags, ...)
Vicent Marti committed
109
{
110 111
	mode_t mode = 0;

112 113 114 115 116 117 118
	#ifdef GIT_DEBUG_STRICT_OPEN
	if (strstr(path, "//") != NULL) {
		errno = EACCES;
		return -1;
	}
	#endif

119
	if (flags & O_CREAT) {
120 121 122
		va_list arg_list;

		va_start(arg_list, flags);
123
		mode = (mode_t)va_arg(arg_list, int);
124 125 126
		va_end(arg_list);
	}

127
	return open(path, flags | O_BINARY | O_CLOEXEC, mode);
Vicent Marti committed
128 129
}

130
int p_creat(const char *path, mode_t mode)
Vicent Marti committed
131
{
132
	return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC, mode);
Vicent Marti committed
133 134
}

135 136 137 138
int p_getcwd(char *buffer_out, size_t size)
{
	char *cwd_buffer;

Edward Thomson committed
139 140
	GIT_ASSERT_ARG(buffer_out);
	GIT_ASSERT_ARG(size > 0);
141 142 143 144

	cwd_buffer = getcwd(buffer_out, size);

	if (cwd_buffer == NULL)
145
		return -1;
146

147 148
	git_fs_path_mkposix(buffer_out);
	git_fs_path_string_to_dir(buffer_out, size); /* append trailing slash */
149

150
	return 0;
151 152
}

153 154 155 156
int p_rename(const char *from, const char *to)
{
	if (!link(from, to)) {
		p_unlink(from);
157
		return 0;
158 159 160
	}

	if (!rename(from, to))
161
		return 0;
162

163
	return -1;
164 165
}

Vicent Marti committed
166
#endif /* GIT_WIN32 */
167

168
ssize_t p_read(git_file fd, void *buf, size_t cnt)
Vicent Marti committed
169 170
{
	char *b = buf;
171

172 173 174 175 176 177 178 179
	if (!git__is_ssizet(cnt)) {
#ifdef GIT_WIN32
		SetLastError(ERROR_INVALID_PARAMETER);
#endif
		errno = EINVAL;
		return -1;
	}

Vicent Marti committed
180
	while (cnt) {
181 182
		ssize_t r;
#ifdef GIT_WIN32
183
		r = read(fd, b, cnt > INT_MAX ? INT_MAX : (unsigned int)cnt);
184 185 186
#else
		r = read(fd, b, cnt);
#endif
Vicent Marti committed
187 188 189
		if (r < 0) {
			if (errno == EINTR || errno == EAGAIN)
				continue;
190
			return -1;
Vicent Marti committed
191 192 193 194 195 196
		}
		if (!r)
			break;
		cnt -= r;
		b += r;
	}
197
	return (b - (char *)buf);
Vicent Marti committed
198 199
}

200
int p_write(git_file fd, const void *buf, size_t cnt)
Vicent Marti committed
201
{
202
	const char *b = buf;
203

Vicent Marti committed
204
	while (cnt) {
205 206
		ssize_t r;
#ifdef GIT_WIN32
Edward Thomson committed
207
		GIT_ASSERT((size_t)((unsigned int)cnt) == cnt);
208 209 210 211
		r = write(fd, b, (unsigned int)cnt);
#else
		r = write(fd, b, cnt);
#endif
Vicent Marti committed
212
		if (r < 0) {
213
			if (errno == EINTR || GIT_ISBLOCKED(errno))
Vicent Marti committed
214
				continue;
215
			return -1;
Vicent Marti committed
216 217 218
		}
		if (!r) {
			errno = EPIPE;
219
			return -1;
Vicent Marti committed
220 221 222 223
		}
		cnt -= r;
		b += r;
	}
224
	return 0;
Vicent Marti committed
225
}
226

227
#ifdef NO_MMAP
228

229 230
#include "map.h"

231
int git__page_size(size_t *page_size)
232 233
{
	/* dummy; here we don't need any alignment anyway */
234 235
	*page_size = 4096;
	return 0;
236 237
}

238 239 240 241 242 243 244
int git__mmap_alignment(size_t *alignment)
{
	/* dummy; here we don't need any alignment anyway */
	*alignment = 4096;
	return 0;
}

245

246
int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset)
247
{
248 249 250
	const char *ptr;
	size_t remaining_len;

251 252
	GIT_MMAP_VALIDATE(out, len, prot, flags);

253 254 255 256 257
	/* writes cannot be emulated without handling pagefaults since write happens by
	 * writing to mapped memory */
	if (prot & GIT_PROT_WRITE) {
		git_error_set(GIT_ERROR_OS, "trying to map %s-writeable",
				((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) ? "shared": "private");
258 259 260
		return -1;
	}

261 262 263 264 265
	if (!git__is_ssizet(len)) {
		errno = EINVAL;
		return -1;
	}

266
	out->len = 0;
267
	out->data = git__malloc(len);
268
	GIT_ERROR_CHECK_ALLOC(out->data);
269

270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
	remaining_len = len;
	ptr = (const char *)out->data;
	while (remaining_len > 0) {
		ssize_t nb;
		HANDLE_EINTR(nb, p_pread(fd, (void *)ptr, remaining_len, offset));
		if (nb <= 0) {
			git_error_set(GIT_ERROR_OS, "mmap emulation failed");
			git__free(out->data);
			out->data = NULL;
			return -1;
		}

		ptr += nb;
		offset += nb;
		remaining_len -= nb;
285 286 287 288 289 290 291 292
	}

	out->len = len;
	return 0;
}

int p_munmap(git_map *map)
{
Edward Thomson committed
293
	GIT_ASSERT_ARG(map);
294
	git__free(map->data);
295

296 297 298 299
	/* Initializing will help debug use-after-free */
	map->len = 0;
	map->data = NULL;

300 301 302 303
	return 0;
}

#endif