errors.c 4.11 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 53 54 55 56 57 58 59 60 61
void git_error_set(int error_class, const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	git_error_vset(error_class, fmt, ap);
	va_end(ap);
}

void git_error_vset(int error_class, const char *fmt, va_list ap)
62
{
63
#ifdef GIT_WIN32
64
	DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0;
65
#endif
66
	int error_code = (error_class == GIT_ERROR_OS) ? errno : 0;
67
	git_buf *buf = &GIT_GLOBAL->error_buf;
68

69
	git_buf_clear(buf);
70 71
	if (fmt) {
		git_buf_vprintf(buf, fmt, ap);
72
		if (error_class == GIT_ERROR_OS)
73
			git_buf_PUTS(buf, ": ");
74
	}
75

76
	if (error_class == GIT_ERROR_OS) {
77
#ifdef GIT_WIN32
78 79
		char * win32_error = git_win32_get_error_message(win32_error_code);
		if (win32_error) {
80
			git_buf_puts(buf, win32_error);
81
			git__free(win32_error);
82 83

			SetLastError(0);
84
		}
85
		else
86
#endif
87
		if (error_code)
88
			git_buf_puts(buf, strerror(error_code));
89 90 91

		if (error_code)
			errno = 0;
92 93
	}

94 95
	if (!git_buf_oom(buf))
		set_error_from_buffer(error_class);
96 97
}

98
int git_error_set_str(int error_class, const char *string)
99
{
100
	git_buf *buf = &GIT_GLOBAL->error_buf;
101 102 103

	assert(string);

104 105 106 107
	if (!string) {
		git_error_set(GIT_ERROR_INVALID, "unspecified caller error");
		return -1;
	}
108

109 110
	git_buf_clear(buf);
	git_buf_puts(buf, string);
111 112 113 114 115 116

	if (git_buf_oom(buf))
		return -1;

	set_error_from_buffer(error_class);
	return 0;
117 118
}

119
void git_error_clear(void)
120
{
121 122 123 124
	if (GIT_GLOBAL->last_error != NULL) {
		set_error(0, NULL);
		GIT_GLOBAL->last_error = NULL;
	}
125 126 127 128 129

	errno = 0;
#ifdef GIT_WIN32
	SetLastError(0);
#endif
130
}
131

132
const git_error *git_error_last(void)
133 134 135 136
{
	return GIT_GLOBAL->last_error;
}

137
int git_error_state_capture(git_error_state *state, int error_code)
138 139
{
	git_error *error = GIT_GLOBAL->last_error;
140
	git_buf *error_buf = &GIT_GLOBAL->error_buf;
141

142
	memset(state, 0, sizeof(git_error_state));
143

144 145 146 147 148
	if (!error_code)
		return 0;

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

150 151
	if (error) {
		state->error_msg.klass = error->klass;
152

153 154 155 156
		if (state->oom)
			state->error_msg.message = g_git_oom_error.message;
		else
			state->error_msg.message = git_buf_detach(error_buf);
157
	}
158

159
	git_error_clear();
160
	return error_code;
161 162
}

163
int git_error_state_restore(git_error_state *state)
164
{
165
	int ret = 0;
166

167
	git_error_clear();
168

169 170
	if (state && state->error_msg.message) {
		if (state->oom)
171
			git_error_set_oom();
172
		else
173
			set_error(state->error_msg.klass, state->error_msg.message);
174 175 176

		ret = state->error_code;
		memset(state, 0, sizeof(git_error_state));
177
	}
178

179 180 181
	return ret;
}

182
void git_error_state_free(git_error_state *state)
183 184 185 186 187 188 189 190
{
	if (!state)
		return;

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

	memset(state, 0, sizeof(git_error_state));
191 192
}

193
int git_error_system_last(void)
194 195 196 197 198 199 200 201
{
#ifdef GIT_WIN32
	return GetLastError();
#else
	return errno;
#endif
}

202
void git_error_system_set(int code)
203 204 205 206 207 208 209
{
#ifdef GIT_WIN32
	SetLastError(code);
#else
	errno = code;
#endif
}
210

211
/* Deprecated error values and functions */
212 213 214 215 216 217 218 219 220 221 222 223 224

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)
{
225
	git_error_set_str(error_class, string);
226 227 228 229 230 231
}

void giterr_set_oom(void)
{
	git_error_set_oom();
}