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

8
#include "common.h"
9

10
#include "global.h"
11
#include "posix.h"
12
#include "buffer.h"
13

14 15 16 17
/********************************************
 * New error handling
 ********************************************/

18 19
static git_error g_git_oom_error = {
	"Out of memory",
20
	GIT_ERROR_NOMEMORY
21 22
};

23
static void set_error_from_buffer(int error_class)
24 25
{
	git_error *error = &GIT_GLOBAL->error_t;
26
	git_buf *buf = &GIT_GLOBAL->error_buf;
27

28
	error->message = buf->ptr;
29 30 31 32 33
	error->klass = error_class;

	GIT_GLOBAL->last_error = error;
}

34 35 36 37 38 39 40 41 42 43 44 45 46
static void set_error(int error_class, char *string)
{
	git_buf *buf = &GIT_GLOBAL->error_buf;

	git_buf_clear(buf);
	if (string) {
		git_buf_puts(buf, string);
		git__free(string);
	}

	set_error_from_buffer(error_class);
}

47
void git_error_set_oom(void)
48 49 50 51
{
	GIT_GLOBAL->last_error = &g_git_oom_error;
}

52
void git_error_set(int error_class, const char *string, ...)
53 54
{
	va_list arglist;
55
#ifdef GIT_WIN32
56
	DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0;
57
#endif
58
	int error_code = (error_class == GIT_ERROR_OS) ? errno : 0;
59
	git_buf *buf = &GIT_GLOBAL->error_buf;
60

61
	git_buf_clear(buf);
62 63
	if (string) {
		va_start(arglist, string);
64
		git_buf_vprintf(buf, string, arglist);
65 66
		va_end(arglist);

67
		if (error_class == GIT_ERROR_OS)
68
			git_buf_PUTS(buf, ": ");
69
	}
70

71
	if (error_class == GIT_ERROR_OS) {
72
#ifdef GIT_WIN32
73 74
		char * win32_error = git_win32_get_error_message(win32_error_code);
		if (win32_error) {
75
			git_buf_puts(buf, win32_error);
76
			git__free(win32_error);
77 78

			SetLastError(0);
79
		}
80
		else
81
#endif
82
		if (error_code)
83
			git_buf_puts(buf, strerror(error_code));
84 85 86

		if (error_code)
			errno = 0;
87 88
	}

89 90
	if (!git_buf_oom(buf))
		set_error_from_buffer(error_class);
91 92
}

93
void git_error_set_str(int error_class, const char *string)
94
{
95
	git_buf *buf = &GIT_GLOBAL->error_buf;
96 97 98

	assert(string);

99 100
	if (!string)
		return;
101

102 103 104 105
	git_buf_clear(buf);
	git_buf_puts(buf, string);
	if (!git_buf_oom(buf))
		set_error_from_buffer(error_class);
106 107
}

108
int git_error_set_regex(const regex_t *regex, int error_code)
109 110
{
	char error_buf[1024];
111 112 113

	assert(error_code);

114
	regerror(error_code, regex, error_buf, sizeof(error_buf));
115
	git_error_set_str(GIT_ERROR_REGEX, error_buf);
116 117 118

	if (error_code == REG_NOMATCH)
		return GIT_ENOTFOUND;
119 120

	return GIT_EINVALIDSPEC;
121 122
}

123
void git_error_clear(void)
124
{
125 126 127 128
	if (GIT_GLOBAL->last_error != NULL) {
		set_error(0, NULL);
		GIT_GLOBAL->last_error = NULL;
	}
129 130 131 132 133

	errno = 0;
#ifdef GIT_WIN32
	SetLastError(0);
#endif
134
}
135

136
const git_error *git_error_last(void)
137 138 139 140
{
	return GIT_GLOBAL->last_error;
}

141
int git_error_state_capture(git_error_state *state, int error_code)
142 143
{
	git_error *error = GIT_GLOBAL->last_error;
144
	git_buf *error_buf = &GIT_GLOBAL->error_buf;
145

146
	memset(state, 0, sizeof(git_error_state));
147

148 149 150 151 152
	if (!error_code)
		return 0;

	state->error_code = error_code;
	state->oom = (error == &g_git_oom_error);
153

154 155
	if (error) {
		state->error_msg.klass = error->klass;
156

157 158 159 160
		if (state->oom)
			state->error_msg.message = g_git_oom_error.message;
		else
			state->error_msg.message = git_buf_detach(error_buf);
161
	}
162

163
	git_error_clear();
164
	return error_code;
165 166
}

167
int git_error_state_restore(git_error_state *state)
168
{
169
	int ret = 0;
170

171
	git_error_clear();
172

173 174
	if (state && state->error_msg.message) {
		if (state->oom)
175
			git_error_set_oom();
176
		else
177
			set_error(state->error_msg.klass, state->error_msg.message);
178 179 180

		ret = state->error_code;
		memset(state, 0, sizeof(git_error_state));
181
	}
182

183 184 185
	return ret;
}

186
void git_error_state_free(git_error_state *state)
187 188 189 190 191 192 193 194
{
	if (!state)
		return;

	if (!state->oom)
		git__free(state->error_msg.message);

	memset(state, 0, sizeof(git_error_state));
195 196
}

197
int git_error_system_last(void)
198 199 200 201 202 203 204 205
{
#ifdef GIT_WIN32
	return GetLastError();
#else
	return errno;
#endif
}

206
void git_error_system_set(int code)
207 208 209 210 211 212 213
{
#ifdef GIT_WIN32
	SetLastError(code);
#else
	errno = code;
#endif
}
214

215
/* Deprecated error values and functions */
216 217 218 219 220 221 222 223 224 225 226 227 228

const git_error *giterr_last(void)
{
	return git_error_last();
}

void giterr_clear(void)
{
	git_error_clear();
}

void giterr_set_str(int error_class, const char *string)
{
229
	git_error_set_str(error_class, string);
230 231 232 233 234 235
}

void giterr_set_oom(void)
{
	git_error_set_oom();
}