]> git.proxmox.com Git - libgit2.git/blob - src/errors.c
Merge remote-tracking branch 'carlosmn/revwalk-merge-base' into new-error-handling
[libgit2.git] / src / errors.c
1 /*
2 * Copyright (C) 2009-2012 the libgit2 contributors
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 #include "common.h"
8 #include "global.h"
9 #include "posix.h"
10 #include <stdarg.h>
11
12 static struct {
13 int num;
14 const char *str;
15 } error_codes[] = {
16 {GIT_ERROR, "Unspecified error"},
17 {GIT_ENOTOID, "Input was not a properly formatted Git object id."},
18 {GIT_ENOTFOUND, "Object does not exist in the scope searched."},
19 {GIT_ENOMEM, "Not enough space available."},
20 {GIT_EOSERR, "Consult the OS error information."},
21 {GIT_EOBJTYPE, "The specified object is of invalid type"},
22 {GIT_EOBJCORRUPTED, "The specified object has its data corrupted"},
23 {GIT_ENOTAREPO, "The specified repository is invalid"},
24 {GIT_EINVALIDTYPE, "The object or config variable type is invalid or doesn't match"},
25 {GIT_EMISSINGOBJDATA, "The object cannot be written that because it's missing internal data"},
26 {GIT_EPACKCORRUPTED, "The packfile for the ODB is corrupted"},
27 {GIT_EFLOCKFAIL, "Failed to adquire or release a file lock"},
28 {GIT_EZLIB, "The Z library failed to inflate/deflate an object's data"},
29 {GIT_EBUSY, "The queried object is currently busy"},
30 {GIT_EINVALIDPATH, "The path is invalid"},
31 {GIT_EBAREINDEX, "The index file is not backed up by an existing repository"},
32 {GIT_EINVALIDREFNAME, "The name of the reference is not valid"},
33 {GIT_EREFCORRUPTED, "The specified reference has its data corrupted"},
34 {GIT_ETOONESTEDSYMREF, "The specified symbolic reference is too deeply nested"},
35 {GIT_EPACKEDREFSCORRUPTED, "The pack-refs file is either corrupted of its format is not currently supported"},
36 {GIT_EINVALIDPATH, "The path is invalid" },
37 {GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"},
38 {GIT_EINVALIDREFSTATE, "The state of the reference is not valid"},
39 {GIT_ENOTIMPLEMENTED, "This feature has not been implemented yet"},
40 {GIT_EEXISTS, "A reference with this name already exists"},
41 {GIT_EOVERFLOW, "The given integer literal is too large to be parsed"},
42 {GIT_ENOTNUM, "The given literal is not a valid number"},
43 {GIT_EAMBIGUOUS, "The given oid prefix is ambiguous"},
44 };
45
46 const char *git_strerror(int num)
47 {
48 size_t i;
49
50 if (num == GIT_EOSERR)
51 return strerror(errno);
52 for (i = 0; i < ARRAY_SIZE(error_codes); i++)
53 if (num == error_codes[i].num)
54 return error_codes[i].str;
55
56 return "Unknown error";
57 }
58
59 #define ERROR_MAX_LEN 1024
60
61 void git___rethrow(const char *msg, ...)
62 {
63 char new_error[ERROR_MAX_LEN];
64 char *last_error;
65 char *old_error = NULL;
66
67 va_list va;
68
69 last_error = GIT_GLOBAL->error.last;
70
71 va_start(va, msg);
72 vsnprintf(new_error, ERROR_MAX_LEN, msg, va);
73 va_end(va);
74
75 old_error = git__strdup(last_error);
76
77 snprintf(last_error, ERROR_MAX_LEN, "%s \n - %s", new_error, old_error);
78
79 git__free(old_error);
80 }
81
82 void git___throw(const char *msg, ...)
83 {
84 va_list va;
85
86 va_start(va, msg);
87 vsnprintf(GIT_GLOBAL->error.last, ERROR_MAX_LEN, msg, va);
88 va_end(va);
89 }
90
91 const char *git_lasterror(void)
92 {
93 char *last_error = GIT_GLOBAL->error.last;
94
95 if (!last_error[0]) {
96 const git_error *err = git_error_last();
97 if (err != NULL)
98 return err->message;
99 return NULL;
100 }
101
102 return last_error;
103 }
104
105 void git_clearerror(void)
106 {
107 char *last_error = GIT_GLOBAL->error.last;
108 last_error[0] = '\0';
109 }
110
111 /********************************************
112 * New error handling
113 ********************************************/
114
115 static git_error g_git_oom_error = {
116 "Out of memory",
117 GITERR_NOMEMORY
118 };
119
120 void giterr_set_oom(void)
121 {
122 GIT_GLOBAL->last_error = &g_git_oom_error;
123 }
124
125 void giterr_set(int error_class, const char *string, ...)
126 {
127 char error_str[1024];
128 va_list arglist;
129
130 /* Grab errno before calling vsnprintf() so it won't be overwritten */
131 const char *os_error_msg =
132 (error_class == GITERR_OS && errno != 0) ? strerror(errno) : NULL;
133 #ifdef GIT_WIN32
134 DWORD dwLastError = GetLastError();
135 #endif
136
137 va_start(arglist, string);
138 p_vsnprintf(error_str, sizeof(error_str), string, arglist);
139 va_end(arglist);
140
141 /* automatically suffix strerror(errno) for GITERR_OS errors */
142 if (error_class == GITERR_OS) {
143 if (os_error_msg != NULL) {
144 strncat(error_str, ": ", sizeof(error_str));
145 strncat(error_str, os_error_msg, sizeof(error_str));
146 errno = 0; /* reset so same error won't be reported twice */
147 }
148 #ifdef GIT_WIN32
149 else if (dwLastError != 0) {
150 LPVOID lpMsgBuf = NULL;
151
152 FormatMessage(
153 FORMAT_MESSAGE_ALLOCATE_BUFFER |
154 FORMAT_MESSAGE_FROM_SYSTEM |
155 FORMAT_MESSAGE_IGNORE_INSERTS,
156 NULL, dwLastError, 0, (LPTSTR) &lpMsgBuf, 0, NULL);
157
158 if (lpMsgBuf) {
159 strncat(error_str, ": ", sizeof(error_str));
160 strncat(error_str, (const char *)lpMsgBuf, sizeof(error_str));
161 LocalFree(lpMsgBuf);
162 }
163
164 SetLastError(0);
165 }
166 #endif
167 }
168
169 giterr_set_str(error_class, error_str);
170 }
171
172 void giterr_set_str(int error_class, const char *string)
173 {
174 git_error *error = &GIT_GLOBAL->error_t;
175
176 free(error->message);
177
178 error->message = git__strdup(string);
179 error->klass = error_class;
180
181 if (error->message == NULL) {
182 giterr_set_oom();
183 return;
184 }
185
186 GIT_GLOBAL->last_error = error;
187 }
188
189 void giterr_set_regex(const regex_t *regex, int error_code)
190 {
191 char error_buf[1024];
192 regerror(error_code, regex, error_buf, sizeof(error_buf));
193 giterr_set_str(GITERR_REGEX, error_buf);
194 }
195
196 void giterr_clear(void)
197 {
198 GIT_GLOBAL->last_error = NULL;
199 }
200
201 const git_error *git_error_last(void)
202 {
203 return GIT_GLOBAL->last_error;
204 }
205
206 void git_error_clear(void)
207 {
208 giterr_clear();
209 }
210