/src/sleuthkit/tsk/base/tsk_error.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * The Sleuth Kit |
3 | | * |
4 | | * Brian Carrier [carrier <at> sleuthkit [dot] org] |
5 | | * Copyright (c) 2006-2011 Brian Carrier. All Rights reserved |
6 | | * |
7 | | * This software is distributed under the Common Public License 1.0 |
8 | | */ |
9 | | |
10 | | #include "tsk_base_i.h" |
11 | | #include "tsk_base.h" |
12 | | |
13 | | /** |
14 | | * \file tsk_error.c |
15 | | * Contains the error handling code and variables. |
16 | | */ |
17 | | |
18 | | |
19 | | /* Global variables that fit here as well as anywhere */ |
20 | | char *progname = "unknown"; |
21 | | int tsk_verbose = 0; |
22 | | |
23 | | /* Optional error listener */ |
24 | | TSK_ERROR_LISTENER_CB error_listener = NULL; |
25 | | |
26 | | /* Error messages */ |
27 | | static const char *tsk_err_aux_str[TSK_ERR_IMG_MAX] = { |
28 | | "Insufficient memory", |
29 | | "TSK Error" |
30 | | }; |
31 | | |
32 | | /* imagetools specific error strings */ |
33 | | static const char *tsk_err_img_str[TSK_ERR_IMG_MAX] = { |
34 | | "Missing image file names", // 0 |
35 | | "Invalid image offset", |
36 | | "Cannot determine image type", |
37 | | "Unsupported image type", |
38 | | "Error opening image file", |
39 | | "Error stat(ing) image file", // 5 |
40 | | "Error seeking in image file", |
41 | | "Error reading image file", |
42 | | "Read offset too large for image file", |
43 | | "Invalid API argument", |
44 | | "Invalid magic value", // 10 |
45 | | "Error writing data", |
46 | | "Error converting file name", |
47 | | "Incorrect or missing password" |
48 | | }; |
49 | | |
50 | | |
51 | | static const char *tsk_err_mm_str[TSK_ERR_VS_MAX] = { |
52 | | "Cannot determine partition type", // 0 |
53 | | "Unsupported partition type", |
54 | | "Error reading image file", |
55 | | "Invalid magic value", |
56 | | "Invalid walk range", |
57 | | "Invalid buffer size", // 5 |
58 | | "Invalid sector address", |
59 | | "Invalid API argument", |
60 | | "Encryption detected", |
61 | | "Multiple volume system types detected", |
62 | | }; |
63 | | |
64 | | static const char *tsk_err_fs_str[TSK_ERR_FS_MAX] = { |
65 | | "Cannot determine file system type", // 0 |
66 | | "Unsupported file system type", |
67 | | "Function/Feature not supported", |
68 | | "Invalid walk range", |
69 | | "Error reading image file", |
70 | | "Invalid file offset", // 5 |
71 | | "Invalid API argument", |
72 | | "Invalid block address", |
73 | | "Invalid metadata address", |
74 | | "Error in metadata structure", |
75 | | "Invalid magic value", // 10 |
76 | | "Error extracting file from image", |
77 | | "Error writing data", |
78 | | "Error converting Unicode", |
79 | | "Error recovering deleted file", |
80 | | "General file system error", // 15 |
81 | | "File system is corrupt", |
82 | | "Attribute not found in file", |
83 | | "Encryption detected", |
84 | | "Possible encryption detected", |
85 | | "Multiple file system types detected", // 20 |
86 | | "BitLocker initialization failed", |
87 | | "Error loading large directory", |
88 | | }; |
89 | | |
90 | | static const char *tsk_err_hdb_str[TSK_ERR_HDB_MAX] = { |
91 | | "Cannot determine hash database type", // 0 |
92 | | "Unsupported hash database type", |
93 | | "Error reading hash database file", |
94 | | "Error reading hash database index", |
95 | | "Invalid argument", |
96 | | "Error writing data", // 5 |
97 | | "Error creating file", |
98 | | "Error deleting file", |
99 | | "Missing file", |
100 | | "Error creating process", |
101 | | "Error opening file", // 10 |
102 | | "Corrupt hash database" |
103 | | }; |
104 | | |
105 | | static const char *tsk_err_auto_str[TSK_ERR_AUTO_MAX] = { |
106 | | "Database Error", |
107 | | "Corrupt file data", |
108 | | "Error converting Unicode", |
109 | | "Image not opened yet" |
110 | | }; |
111 | | |
112 | | static const char *tsk_err_pool_str[TSK_ERR_POOL_MAX] = { |
113 | | "Cannot determine pool container type", |
114 | | "Unsupported pool container type", |
115 | | "Invalid API argument", |
116 | | "General pool error" |
117 | | }; |
118 | | |
119 | | |
120 | | #ifdef TSK_MULTITHREAD_LIB |
121 | | |
122 | | #ifdef TSK_WIN32 |
123 | | TSK_ERROR_INFO * |
124 | | tsk_error_get_info() |
125 | | { |
126 | | return (TSK_ERROR_INFO *) |
127 | | tsk_error_win32_get_per_thread_(sizeof(TSK_ERROR_INFO)); |
128 | | } |
129 | | |
130 | | // non-windows |
131 | | #else |
132 | | static pthread_key_t pt_tls_key; |
133 | | static pthread_once_t pt_tls_key_once = PTHREAD_ONCE_INIT; |
134 | | |
135 | | static void |
136 | | free_error_info(void *per_thread_error_info) |
137 | 0 | { |
138 | 0 | if (per_thread_error_info != 0) { |
139 | 0 | free(per_thread_error_info); |
140 | 0 | pthread_setspecific(pt_tls_key, 0); |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | | static void |
145 | | make_pt_tls_key() |
146 | 11 | { |
147 | 11 | (void) pthread_key_create(&pt_tls_key, free_error_info); |
148 | 11 | } |
149 | | |
150 | | TSK_ERROR_INFO * |
151 | | tsk_error_get_info() |
152 | 18.0M | { |
153 | 18.0M | TSK_ERROR_INFO *ptr = NULL; |
154 | 18.0M | (void) pthread_once(&pt_tls_key_once, make_pt_tls_key); |
155 | 18.0M | if ((ptr = (TSK_ERROR_INFO *) pthread_getspecific(pt_tls_key)) == 0) { |
156 | | // Under high memory pressure malloc will return NULL. |
157 | 11 | ptr = (TSK_ERROR_INFO *) malloc(sizeof(TSK_ERROR_INFO)); |
158 | | |
159 | 11 | if( ptr != NULL ) { |
160 | 11 | ptr->t_errno = 0; |
161 | 11 | ptr->errstr[0] = 0; |
162 | 11 | ptr->errstr2[0] = 0; |
163 | 11 | } |
164 | 11 | (void) pthread_setspecific(pt_tls_key, ptr); |
165 | 11 | } |
166 | 18.0M | return ptr; |
167 | 18.0M | } |
168 | | #endif |
169 | | |
170 | | // single-threaded |
171 | | #else |
172 | | |
173 | | static TSK_ERROR_INFO error_info = { 0, {0}, {0} }; |
174 | | |
175 | | TSK_ERROR_INFO * |
176 | | tsk_error_get_info() |
177 | | { |
178 | | return &error_info; |
179 | | } |
180 | | |
181 | | #endif |
182 | | |
183 | | /** |
184 | | * \ingroup baselib |
185 | | * Return the string with the current error message. The string does not end with a |
186 | | * newline. |
187 | | * |
188 | | * @returns String with error message or NULL if there is no error |
189 | | */ |
190 | | const char * |
191 | | tsk_error_get() |
192 | 0 | { |
193 | 0 | size_t pidx = 0; |
194 | 0 | TSK_ERROR_INFO *error_info = tsk_error_get_info(); |
195 | 0 | int t_errno = error_info->t_errno; |
196 | 0 | char *errstr_print = error_info->errstr_print; |
197 | |
|
198 | 0 | if (t_errno == 0) { |
199 | 0 | return NULL; |
200 | 0 | } |
201 | | |
202 | 0 | memset(errstr_print, 0, TSK_ERROR_STRING_MAX_LENGTH); |
203 | 0 | if (t_errno & TSK_ERR_AUX) { |
204 | 0 | if ((TSK_ERR_MASK & t_errno) < TSK_ERR_AUX_MAX) |
205 | 0 | snprintf(&errstr_print[pidx], |
206 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s", |
207 | 0 | tsk_err_aux_str[t_errno & TSK_ERR_MASK]); |
208 | 0 | else |
209 | 0 | snprintf(&errstr_print[pidx], |
210 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, |
211 | 0 | "auxtools error: %" PRIu32, TSK_ERR_MASK & t_errno); |
212 | 0 | } |
213 | 0 | else if (t_errno & TSK_ERR_IMG) { |
214 | 0 | if ((TSK_ERR_MASK & t_errno) < TSK_ERR_IMG_MAX) |
215 | 0 | snprintf(&errstr_print[pidx], |
216 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s", |
217 | 0 | tsk_err_img_str[t_errno & TSK_ERR_MASK]); |
218 | 0 | else |
219 | 0 | snprintf(&errstr_print[pidx], |
220 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, |
221 | 0 | "imgtools error: %" PRIu32, TSK_ERR_MASK & t_errno); |
222 | 0 | } |
223 | 0 | else if (t_errno & TSK_ERR_VS) { |
224 | 0 | if ((TSK_ERR_MASK & t_errno) < TSK_ERR_VS_MAX) |
225 | 0 | snprintf(&errstr_print[pidx], |
226 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s", |
227 | 0 | tsk_err_mm_str[t_errno & TSK_ERR_MASK]); |
228 | 0 | else |
229 | 0 | snprintf(&errstr_print[pidx], |
230 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, |
231 | 0 | "mmtools error: %" PRIu32, TSK_ERR_MASK & t_errno); |
232 | 0 | } |
233 | 0 | else if (t_errno & TSK_ERR_FS) { |
234 | 0 | if ((TSK_ERR_MASK & t_errno) < TSK_ERR_FS_MAX) |
235 | 0 | snprintf(&errstr_print[pidx], |
236 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s", |
237 | 0 | tsk_err_fs_str[t_errno & TSK_ERR_MASK]); |
238 | 0 | else |
239 | 0 | snprintf(&errstr_print[pidx], |
240 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, |
241 | 0 | "fstools error: %" PRIu32, TSK_ERR_MASK & t_errno); |
242 | 0 | } |
243 | 0 | else if (t_errno & TSK_ERR_HDB) { |
244 | 0 | if ((TSK_ERR_MASK & t_errno) < TSK_ERR_HDB_MAX) |
245 | 0 | snprintf(&errstr_print[pidx], |
246 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s", |
247 | 0 | tsk_err_hdb_str[t_errno & TSK_ERR_MASK]); |
248 | 0 | else |
249 | 0 | snprintf(&errstr_print[pidx], |
250 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, |
251 | 0 | "hashtools error: %" PRIu32, TSK_ERR_MASK & t_errno); |
252 | 0 | } |
253 | 0 | else if (t_errno & TSK_ERR_AUTO) { |
254 | 0 | if ((TSK_ERR_MASK & t_errno) < TSK_ERR_AUTO_MAX) |
255 | 0 | snprintf(&errstr_print[pidx], |
256 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s", |
257 | 0 | tsk_err_auto_str[t_errno & TSK_ERR_MASK]); |
258 | 0 | else |
259 | 0 | snprintf(&errstr_print[pidx], |
260 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, "auto error: %" PRIu32, |
261 | 0 | TSK_ERR_MASK & t_errno); |
262 | 0 | } |
263 | 0 | else if (t_errno & TSK_ERR_POOL) { |
264 | 0 | if ((TSK_ERR_MASK & t_errno) < TSK_ERR_POOL_MAX) |
265 | 0 | snprintf(&errstr_print[pidx], |
266 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s", |
267 | 0 | tsk_err_pool_str[t_errno & TSK_ERR_MASK]); |
268 | 0 | else |
269 | 0 | snprintf(&errstr_print[pidx], |
270 | 0 | TSK_ERROR_STRING_MAX_LENGTH - pidx, "pool error: %" PRIu32, |
271 | 0 | TSK_ERR_MASK & t_errno); |
272 | 0 | } |
273 | 0 | else { |
274 | 0 | snprintf(&errstr_print[pidx], TSK_ERROR_STRING_MAX_LENGTH - pidx, |
275 | 0 | "Unknown Error: %" PRIu32, t_errno); |
276 | 0 | } |
277 | 0 | pidx = strlen(errstr_print); |
278 | | |
279 | | /* Print the unique string, if it exists */ |
280 | 0 | if (error_info->errstr[0] != '\0') { |
281 | 0 | snprintf(&errstr_print[pidx], TSK_ERROR_STRING_MAX_LENGTH - pidx, |
282 | 0 | " (%s)", error_info->errstr); |
283 | 0 | pidx = strlen(errstr_print); |
284 | 0 | } |
285 | |
|
286 | 0 | if (error_info->errstr2[0] != '\0') { |
287 | 0 | snprintf(&errstr_print[pidx], TSK_ERROR_STRING_MAX_LENGTH - pidx, |
288 | 0 | " (%s)", error_info->errstr2); |
289 | 0 | pidx = strlen(errstr_print); |
290 | 0 | } |
291 | 0 | return (char *) error_info->errstr_print; |
292 | 0 | } |
293 | | |
294 | | /** |
295 | | * \ingroup baselib |
296 | | * Return the current error number. |
297 | | * @returns the current error number. |
298 | | */ |
299 | | uint32_t |
300 | | tsk_error_get_errno() |
301 | 158k | { |
302 | 158k | return tsk_error_get_info()->t_errno; |
303 | 158k | } |
304 | | |
305 | | /** |
306 | | * \ingroup baselib |
307 | | * Set the current TSK error number. |
308 | | * @param t_errno the error number. |
309 | | */ |
310 | | void |
311 | | tsk_error_set_errno(uint32_t t_errno) |
312 | 4.32M | { |
313 | 4.32M | tsk_error_get_info()->t_errno = t_errno; |
314 | 4.32M | } |
315 | | |
316 | | /** |
317 | | * \ingroup baselib |
318 | | * Retrieve the current, basic error string. |
319 | | * Additional information is in errstr2. |
320 | | * Use tsk_error_get() to get a fully formatted string. |
321 | | * @returns the string. This is only valid until the next call to a tsk function. |
322 | | */ |
323 | | char * |
324 | | tsk_error_get_errstr() |
325 | 0 | { |
326 | 0 | return tsk_error_get_info()->errstr; |
327 | 0 | } |
328 | | |
329 | | /** |
330 | | * \ingroup baselib |
331 | | * Set the error string #1. This should contain the basic message. |
332 | | * @param format the printf-style format string |
333 | | */ |
334 | | void |
335 | | tsk_error_set_errstr(const char *format, ...) |
336 | 4.12M | { |
337 | 4.12M | va_list args; |
338 | 4.12M | va_start(args, format); |
339 | 4.12M | vsnprintf(tsk_error_get_info()->errstr, TSK_ERROR_STRING_MAX_LENGTH, |
340 | 4.12M | format, args); |
341 | 4.12M | va_end(args); |
342 | 4.12M | if (error_listener != NULL) { |
343 | 0 | error_listener((uint32_t)tsk_error_get_info()->t_errno, tsk_error_get_info()->errstr); |
344 | 0 | } |
345 | 4.12M | } |
346 | | |
347 | | /** |
348 | | * \ingroup baselib |
349 | | * Set the error string |
350 | | * @param format the printf-style format string |
351 | | * @param args the printf-style args |
352 | | */ |
353 | | void |
354 | | tsk_error_vset_errstr(const char *format, va_list args) |
355 | 349 | { |
356 | 349 | vsnprintf(tsk_error_get_info()->errstr, TSK_ERROR_STRING_MAX_LENGTH, |
357 | 349 | format, args); |
358 | 349 | if (error_listener != NULL) { |
359 | 0 | error_listener((uint32_t)tsk_error_get_info()->t_errno, tsk_error_get_info()->errstr); |
360 | 0 | } |
361 | 349 | } |
362 | | |
363 | | /** |
364 | | * \ingroup baselib |
365 | | * Retrieve the current error string #2. |
366 | | * This has additional information than string #1. |
367 | | * @returns the string. This is only valid until the next call to a tsk function. |
368 | | */ |
369 | | char * |
370 | | tsk_error_get_errstr2() |
371 | 0 | { |
372 | 0 | return tsk_error_get_info()->errstr2; |
373 | 0 | } |
374 | | |
375 | | /** |
376 | | * \ingroup baselib |
377 | | * Set the error string #2. This is called by methods who encounter the error, |
378 | | * but did not set errno. |
379 | | * @param format the printf-style format string |
380 | | */ |
381 | | void |
382 | | tsk_error_set_errstr2(const char *format, ...) |
383 | 714k | { |
384 | 714k | va_list args; |
385 | 714k | va_start(args, format); |
386 | 714k | vsnprintf(tsk_error_get_info()->errstr2, TSK_ERROR_STRING_MAX_LENGTH, |
387 | 714k | format, args); |
388 | 714k | va_end(args); |
389 | 714k | } |
390 | | |
391 | | /** |
392 | | * \ingroup baselib |
393 | | * Set the error string |
394 | | * @param format the printf-style format string |
395 | | * @param args the printf-style format args |
396 | | */ |
397 | | void |
398 | | tsk_error_vset_errstr2(const char *format, va_list args) |
399 | 0 | { |
400 | 0 | vsnprintf(tsk_error_get_info()->errstr2, TSK_ERROR_STRING_MAX_LENGTH, |
401 | 0 | format, args); |
402 | 0 | } |
403 | | |
404 | | /** |
405 | | * \ingroup baselib |
406 | | * Concatenate a message onto the end of the errstr2. |
407 | | * @param format |
408 | | */ |
409 | | void |
410 | | tsk_error_errstr2_concat(const char *format, ...) |
411 | 20.6k | { |
412 | 20.6k | char *errstr2 = tsk_error_get_info()->errstr2; |
413 | 20.6k | int current_length = (int) (strlen(errstr2) + 1); // +1 for a space |
414 | 20.6k | if (current_length > 0) { |
415 | 20.6k | va_list args; |
416 | 20.6k | int remaining = TSK_ERROR_STRING_MAX_LENGTH - current_length; |
417 | 20.6k | errstr2[current_length - 1] = ' '; |
418 | 20.6k | va_start(args, format); |
419 | 20.6k | vsnprintf(&errstr2[current_length], remaining, format, args); |
420 | 20.6k | va_end(args); |
421 | 20.6k | } |
422 | 20.6k | } |
423 | | |
424 | | /** |
425 | | * Add a method that will be sent most errors (in additional to the processing TSK already does). |
426 | | * |
427 | | * This is a bit limited since adding an error is a multistep process. The listener is invoked when |
428 | | * tsk_error_set_errstr() is called. Our convention is that tsk_error_set_errno() is called first so |
429 | | * the errno should be accurate. We would miss anything set to errstr2 but this is not very common. |
430 | | * |
431 | | * @param listener Method that should take arguments (uint32_t, const char*) |
432 | | */ |
433 | | void |
434 | 0 | tsk_error_set_error_listener(TSK_ERROR_LISTENER_CB listener) { |
435 | 0 | error_listener = listener; |
436 | 0 | } |
437 | | |
438 | | /** |
439 | | * \ingroup baselib |
440 | | * Print the current fully formed error message to a file. |
441 | | * |
442 | | * @param hFile File to print message to |
443 | | */ |
444 | | void |
445 | | tsk_error_print(FILE * hFile) |
446 | 0 | { |
447 | 0 | const char *str; |
448 | 0 | if (tsk_error_get_errno() == 0) |
449 | 0 | return; |
450 | | |
451 | 0 | str = tsk_error_get(); |
452 | 0 | if (str != NULL) { |
453 | 0 | tsk_fprintf(hFile, "%s\n", str); |
454 | 0 | } |
455 | 0 | else { |
456 | 0 | tsk_fprintf(hFile, |
457 | 0 | "Error creating Sleuth Kit error string (Errno: %d)\n", |
458 | 0 | tsk_error_get_errno()); |
459 | 0 | } |
460 | 0 | } |
461 | | |
462 | | /** |
463 | | * \ingroup baselib |
464 | | * Clear the error number and error message. |
465 | | */ |
466 | | void |
467 | | tsk_error_reset() |
468 | 8.70M | { |
469 | 8.70M | TSK_ERROR_INFO *info = tsk_error_get_info(); |
470 | | |
471 | 8.70M | if( info != NULL ) { |
472 | 8.70M | info->t_errno = 0; |
473 | 8.70M | info->errstr[0] = 0; |
474 | 8.70M | info->errstr2[0] = 0; |
475 | 8.70M | info->errstr_print[0] = 0; |
476 | 8.70M | } |
477 | 8.70M | } |