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