]> git.proxmox.com Git - libgit2.git/blob - src/libgit2/errors.c
Merge https://salsa.debian.org/debian/libgit2 into proxmox/bullseye
[libgit2.git] / src / libgit2 / errors.c
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 "str.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
29 static void set_error_from_buffer(int error_class)
30 {
31 git_error *error = &GIT_THREADSTATE->error_t;
32 git_str *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
40 static void set_error(int error_class, char *string)
41 {
42 git_str *buf = &GIT_THREADSTATE->error_buf;
43
44 git_str_clear(buf);
45 if (string) {
46 git_str_puts(buf, string);
47 git__free(string);
48 }
49
50 set_error_from_buffer(error_class);
51 }
52
53 void git_error_set_oom(void)
54 {
55 GIT_THREADSTATE->last_error = &g_git_oom_error;
56 }
57
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
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_str *buf = &GIT_THREADSTATE->error_buf;
74
75 git_str_clear(buf);
76 if (fmt) {
77 git_str_vprintf(buf, fmt, ap);
78 if (error_class == GIT_ERROR_OS)
79 git_str_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_str_puts(buf, win32_error);
87 git__free(win32_error);
88
89 SetLastError(0);
90 }
91 else
92 #endif
93 if (error_code)
94 git_str_puts(buf, strerror(error_code));
95
96 if (error_code)
97 errno = 0;
98 }
99
100 if (!git_str_oom(buf))
101 set_error_from_buffer(error_class);
102 }
103
104 int git_error_set_str(int error_class, const char *string)
105 {
106 git_str *buf = &GIT_THREADSTATE->error_buf;
107
108 GIT_ASSERT_ARG(string);
109
110 git_str_clear(buf);
111 git_str_puts(buf, string);
112
113 if (git_str_oom(buf))
114 return -1;
115
116 set_error_from_buffer(error_class);
117 return 0;
118 }
119
120 void git_error_clear(void)
121 {
122 if (GIT_THREADSTATE->last_error != NULL) {
123 set_error(0, NULL);
124 GIT_THREADSTATE->last_error = NULL;
125 }
126
127 errno = 0;
128 #ifdef GIT_WIN32
129 SetLastError(0);
130 #endif
131 }
132
133 const git_error *git_error_last(void)
134 {
135 /* If the library is not initialized, return a static error. */
136 if (!git_libgit2_init_count())
137 return &g_git_uninitialized_error;
138
139 return GIT_THREADSTATE->last_error;
140 }
141
142 int git_error_state_capture(git_error_state *state, int error_code)
143 {
144 git_error *error = GIT_THREADSTATE->last_error;
145 git_str *error_buf = &GIT_THREADSTATE->error_buf;
146
147 memset(state, 0, sizeof(git_error_state));
148
149 if (!error_code)
150 return 0;
151
152 state->error_code = error_code;
153 state->oom = (error == &g_git_oom_error);
154
155 if (error) {
156 state->error_msg.klass = error->klass;
157
158 if (state->oom)
159 state->error_msg.message = g_git_oom_error.message;
160 else
161 state->error_msg.message = git_str_detach(error_buf);
162 }
163
164 git_error_clear();
165 return error_code;
166 }
167
168 int git_error_state_restore(git_error_state *state)
169 {
170 int ret = 0;
171
172 git_error_clear();
173
174 if (state && state->error_msg.message) {
175 if (state->oom)
176 git_error_set_oom();
177 else
178 set_error(state->error_msg.klass, state->error_msg.message);
179
180 ret = state->error_code;
181 memset(state, 0, sizeof(git_error_state));
182 }
183
184 return ret;
185 }
186
187 void git_error_state_free(git_error_state *state)
188 {
189 if (!state)
190 return;
191
192 if (!state->oom)
193 git__free(state->error_msg.message);
194
195 memset(state, 0, sizeof(git_error_state));
196 }
197
198 int git_error_system_last(void)
199 {
200 #ifdef GIT_WIN32
201 return GetLastError();
202 #else
203 return errno;
204 #endif
205 }
206
207 void git_error_system_set(int code)
208 {
209 #ifdef GIT_WIN32
210 SetLastError(code);
211 #else
212 errno = code;
213 #endif
214 }
215
216 /* Deprecated error values and functions */
217
218 #ifndef GIT_DEPRECATE_HARD
219 const git_error *giterr_last(void)
220 {
221 return git_error_last();
222 }
223
224 void giterr_clear(void)
225 {
226 git_error_clear();
227 }
228
229 void giterr_set_str(int error_class, const char *string)
230 {
231 git_error_set_str(error_class, string);
232 }
233
234 void giterr_set_oom(void)
235 {
236 git_error_set_oom();
237 }
238 #endif