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 "common.h"
9
10 #include "threadstate.h"
11 #include "posix.h"
12 #include "buffer.h"
13 #include "libgit2.h"
14
15 /********************************************
16 * New error handling
17 ********************************************/
18
19 static git_error g_git_oom_error = {
20 "Out of memory",
21 GIT_ERROR_NOMEMORY
22 };
23
24 static git_error g_git_uninitialized_error = {
25 "libgit2 has not been initialized; you must call git_libgit2_init",
26 GIT_ERROR_INVALID
27 };
28
set_error_from_buffer(int error_class)29 static void set_error_from_buffer(int error_class)
30 {
31 git_error *error = &GIT_THREADSTATE->error_t;
32 git_buf *buf = &GIT_THREADSTATE->error_buf;
33
34 error->message = buf->ptr;
35 error->klass = error_class;
36
37 GIT_THREADSTATE->last_error = error;
38 }
39
set_error(int error_class,char * string)40 static void set_error(int error_class, char *string)
41 {
42 git_buf *buf = &GIT_THREADSTATE->error_buf;
43
44 git_buf_clear(buf);
45 if (string) {
46 git_buf_puts(buf, string);
47 git__free(string);
48 }
49
50 set_error_from_buffer(error_class);
51 }
52
git_error_set_oom(void)53 void git_error_set_oom(void)
54 {
55 GIT_THREADSTATE->last_error = &g_git_oom_error;
56 }
57
git_error_set(int error_class,const char * fmt,...)58 void git_error_set(int error_class, const char *fmt, ...)
59 {
60 va_list ap;
61
62 va_start(ap, fmt);
63 git_error_vset(error_class, fmt, ap);
64 va_end(ap);
65 }
66
git_error_vset(int error_class,const char * fmt,va_list ap)67 void git_error_vset(int error_class, const char *fmt, va_list ap)
68 {
69 #ifdef GIT_WIN32
70 DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0;
71 #endif
72 int error_code = (error_class == GIT_ERROR_OS) ? errno : 0;
73 git_buf *buf = &GIT_THREADSTATE->error_buf;
74
75 git_buf_clear(buf);
76 if (fmt) {
77 git_buf_vprintf(buf, fmt, ap);
78 if (error_class == GIT_ERROR_OS)
79 git_buf_PUTS(buf, ": ");
80 }
81
82 if (error_class == GIT_ERROR_OS) {
83 #ifdef GIT_WIN32
84 char * win32_error = git_win32_get_error_message(win32_error_code);
85 if (win32_error) {
86 git_buf_puts(buf, win32_error);
87 git__free(win32_error);
88
89 SetLastError(0);
90 }
91 else
92 #endif
93 if (error_code)
94 git_buf_puts(buf, strerror(error_code));
95
96 if (error_code)
97 errno = 0;
98 }
99
100 if (!git_buf_oom(buf))
101 set_error_from_buffer(error_class);
102 }
103
git_error_set_str(int error_class,const char * string)104 int git_error_set_str(int error_class, const char *string)
105 {
106 git_buf *buf = &GIT_THREADSTATE->error_buf;
107
108 GIT_ASSERT_ARG(string);
109
110 if (!string) {
111 git_error_set(GIT_ERROR_INVALID, "unspecified caller error");
112 return -1;
113 }
114
115 git_buf_clear(buf);
116 git_buf_puts(buf, string);
117
118 if (git_buf_oom(buf))
119 return -1;
120
121 set_error_from_buffer(error_class);
122 return 0;
123 }
124
git_error_clear(void)125 void git_error_clear(void)
126 {
127 if (GIT_THREADSTATE->last_error != NULL) {
128 set_error(0, NULL);
129 GIT_THREADSTATE->last_error = NULL;
130 }
131
132 errno = 0;
133 #ifdef GIT_WIN32
134 SetLastError(0);
135 #endif
136 }
137
git_error_last(void)138 const git_error *git_error_last(void)
139 {
140 /* If the library is not initialized, return a static error. */
141 if (!git_libgit2_init_count())
142 return &g_git_uninitialized_error;
143
144 return GIT_THREADSTATE->last_error;
145 }
146
git_error_state_capture(git_error_state * state,int error_code)147 int git_error_state_capture(git_error_state *state, int error_code)
148 {
149 git_error *error = GIT_THREADSTATE->last_error;
150 git_buf *error_buf = &GIT_THREADSTATE->error_buf;
151
152 memset(state, 0, sizeof(git_error_state));
153
154 if (!error_code)
155 return 0;
156
157 state->error_code = error_code;
158 state->oom = (error == &g_git_oom_error);
159
160 if (error) {
161 state->error_msg.klass = error->klass;
162
163 if (state->oom)
164 state->error_msg.message = g_git_oom_error.message;
165 else
166 state->error_msg.message = git_buf_detach(error_buf);
167 }
168
169 git_error_clear();
170 return error_code;
171 }
172
git_error_state_restore(git_error_state * state)173 int git_error_state_restore(git_error_state *state)
174 {
175 int ret = 0;
176
177 git_error_clear();
178
179 if (state && state->error_msg.message) {
180 if (state->oom)
181 git_error_set_oom();
182 else
183 set_error(state->error_msg.klass, state->error_msg.message);
184
185 ret = state->error_code;
186 memset(state, 0, sizeof(git_error_state));
187 }
188
189 return ret;
190 }
191
git_error_state_free(git_error_state * state)192 void git_error_state_free(git_error_state *state)
193 {
194 if (!state)
195 return;
196
197 if (!state->oom)
198 git__free(state->error_msg.message);
199
200 memset(state, 0, sizeof(git_error_state));
201 }
202
git_error_system_last(void)203 int git_error_system_last(void)
204 {
205 #ifdef GIT_WIN32
206 return GetLastError();
207 #else
208 return errno;
209 #endif
210 }
211
git_error_system_set(int code)212 void git_error_system_set(int code)
213 {
214 #ifdef GIT_WIN32
215 SetLastError(code);
216 #else
217 errno = code;
218 #endif
219 }
220
221 /* Deprecated error values and functions */
222
223 #ifndef GIT_DEPRECATE_HARD
giterr_last(void)224 const git_error *giterr_last(void)
225 {
226 return git_error_last();
227 }
228
giterr_clear(void)229 void giterr_clear(void)
230 {
231 git_error_clear();
232 }
233
giterr_set_str(int error_class,const char * string)234 void giterr_set_str(int error_class, const char *string)
235 {
236 git_error_set_str(error_class, string);
237 }
238
giterr_set_oom(void)239 void giterr_set_oom(void)
240 {
241 git_error_set_oom();
242 }
243 #endif
244