RebaseDlg: Correctly remember commits for rewriting on Squash after (Edit|Squash...
[TortoiseGit.git] / src / TortoiseMerge / libsvn_diff / error.c
blobad81a9827263b6ad94da44ce0afeea2ddda5cb54
1 /* error.c: common exception handling for Subversion
3 * ====================================================================
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 * ====================================================================
25 #include <stdarg.h>
27 #include <apr_general.h>
28 #include <apr_pools.h>
29 #include <apr_strings.h>
31 #include <zlib.h>
33 #ifndef SVN_ERR__TRACING
34 #define SVN_ERR__TRACING
35 #endif
36 #include "svn_cmdline.h"
37 #include "svn_error.h"
38 #include "svn_pools.h"
39 #include "svn_utf.h"
41 #ifdef SVN_DEBUG
42 /* XXX FIXME: These should be protected by a thread mutex.
43 svn_error__locate and make_error_internal should cooperate
44 in locking and unlocking it. */
46 /* XXX TODO: Define mutex here #if APR_HAS_THREADS */
47 static const char * volatile error_file = NULL;
48 static long volatile error_line = -1;
50 /* file_line for the non-debug case. */
51 static const char SVN_FILE_LINE_UNDEFINED[] = "svn:<undefined>";
52 #endif /* SVN_DEBUG */
54 #include "svn_private_config.h"
55 #include "private/svn_error_private.h"
59 * Undefine the helpers for creating errors.
61 * *NOTE*: Any use of these functions in any other function may need
62 * to call svn_error__locate() because the macro that would otherwise
63 * do this is being undefined and the filename and line number will
64 * not be properly set in the static error_file and error_line
65 * variables.
67 #undef svn_error_create
68 #undef svn_error_createf
69 #undef svn_error_quick_wrap
70 #undef svn_error_wrap_apr
72 /* Note: Although this is a "__" function, it was historically in the
73 * public ABI, so we can never change it or remove its signature, even
74 * though it is now only used in SVN_DEBUG mode. */
75 void
76 svn_error__locate(const char *file, long line)
78 #if defined(SVN_DEBUG)
79 /* XXX TODO: Lock mutex here */
80 error_file = file;
81 error_line = line;
82 #endif
86 /* Cleanup function for errors. svn_error_clear () removes this so
87 errors that are properly handled *don't* hit this code. */
88 #if defined(SVN_DEBUG)
89 static apr_status_t err_abort(void *data)
91 svn_error_t *err = data; /* For easy viewing in a debugger */
92 err = err; /* Fake a use for the variable to avoid compiler warnings */
94 if (!getenv("SVN_DBG_NO_ABORT_ON_ERROR_LEAK"))
95 abort();
96 return APR_SUCCESS;
98 #endif
101 static svn_error_t *
102 make_error_internal(apr_status_t apr_err,
103 svn_error_t *child)
105 apr_pool_t *pool;
106 svn_error_t *new_error;
108 /* Reuse the child's pool, or create our own. */
109 if (child)
110 pool = child->pool;
111 else
113 if (apr_pool_create(&pool, NULL))
114 abort();
117 /* Create the new error structure */
118 new_error = apr_pcalloc(pool, sizeof(*new_error));
120 /* Fill 'er up. */
121 new_error->apr_err = apr_err;
122 new_error->child = child;
123 new_error->pool = pool;
124 #if defined(SVN_DEBUG)
125 new_error->file = error_file;
126 new_error->line = error_line;
127 /* XXX TODO: Unlock mutex here */
129 if (! child)
130 apr_pool_cleanup_register(pool, new_error,
131 err_abort,
132 apr_pool_cleanup_null);
133 #endif
135 return new_error;
140 /*** Creating and destroying errors. ***/
142 svn_error_t *
143 svn_error_create(apr_status_t apr_err,
144 svn_error_t *child,
145 const char *message)
147 svn_error_t *err;
149 err = make_error_internal(apr_err, child);
151 if (message)
152 err->message = apr_pstrdup(err->pool, message);
154 return err;
158 svn_error_t *
159 svn_error_createf(apr_status_t apr_err,
160 svn_error_t *child,
161 const char *fmt,
162 ...)
164 svn_error_t *err;
165 va_list ap;
167 err = make_error_internal(apr_err, child);
169 va_start(ap, fmt);
170 err->message = apr_pvsprintf(err->pool, fmt, ap);
171 va_end(ap);
173 return err;
177 svn_error_t *
178 svn_error_wrap_apr(apr_status_t status,
179 const char *fmt,
180 ...)
182 svn_error_t *err, *utf8_err;
183 va_list ap;
184 char errbuf[255];
185 const char *msg_apr, *msg;
187 err = make_error_internal(status, NULL);
189 if (fmt)
191 /* Grab the APR error message. */
192 apr_strerror(status, errbuf, sizeof(errbuf));
193 utf8_err = svn_utf_cstring_to_utf8(&msg_apr, errbuf, err->pool);
194 if (utf8_err)
195 msg_apr = NULL;
196 svn_error_clear(utf8_err);
198 /* Append it to the formatted message. */
199 va_start(ap, fmt);
200 msg = apr_pvsprintf(err->pool, fmt, ap);
201 va_end(ap);
202 if (msg_apr)
204 err->message = apr_pstrcat(err->pool, msg, ": ", msg_apr, NULL);
206 else
208 err->message = msg;
212 return err;
216 svn_error_t *
217 svn_error_quick_wrap(svn_error_t *child, const char *new_msg)
219 if (child == SVN_NO_ERROR)
220 return SVN_NO_ERROR;
222 return svn_error_create(child->apr_err,
223 child,
224 new_msg);
227 /* Messages in tracing errors all point to this static string. */
228 static const char error_tracing_link[] = "traced call";
230 svn_error_t *
231 svn_error__trace(const char *file, long line, svn_error_t *err)
233 #ifndef SVN_DEBUG
235 /* We shouldn't even be here, but whatever. Just return the error as-is. */
236 return err;
238 #else
240 /* Only do the work when an error occurs. */
241 if (err)
243 svn_error_t *trace;
244 svn_error__locate(file, line);
245 trace = make_error_internal(err->apr_err, err);
246 trace->message = error_tracing_link;
247 return trace;
249 return SVN_NO_ERROR;
251 #endif
255 svn_error_t *
256 svn_error_compose_create(svn_error_t *err1,
257 svn_error_t *err2)
259 if (err1 && err2)
261 svn_error_compose(err1,
262 svn_error_quick_wrap(err2,
263 _("Additional errors:")));
264 return err1;
266 return err1 ? err1 : err2;
270 void
271 svn_error_compose(svn_error_t *chain, svn_error_t *new_err)
273 apr_pool_t *pool = chain->pool;
274 apr_pool_t *oldpool = new_err->pool;
276 while (chain->child)
277 chain = chain->child;
279 #if defined(SVN_DEBUG)
280 /* Kill existing handler since the end of the chain is going to change */
281 apr_pool_cleanup_kill(pool, chain, err_abort);
282 #endif
284 /* Copy the new error chain into the old chain's pool. */
285 while (new_err)
287 chain->child = apr_palloc(pool, sizeof(*chain->child));
288 chain = chain->child;
289 *chain = *new_err;
290 if (chain->message)
291 chain->message = apr_pstrdup(pool, new_err->message);
292 chain->pool = pool;
293 #if defined(SVN_DEBUG)
294 if (! new_err->child)
295 apr_pool_cleanup_kill(oldpool, new_err, err_abort);
296 #endif
297 new_err = new_err->child;
300 #if defined(SVN_DEBUG)
301 apr_pool_cleanup_register(pool, chain,
302 err_abort,
303 apr_pool_cleanup_null);
304 #endif
306 /* Destroy the new error chain. */
307 svn_pool_destroy(oldpool);
310 svn_error_t *
311 svn_error_root_cause(svn_error_t *err)
313 while (err)
315 if (err->child)
316 err = err->child;
317 else
318 break;
321 return err;
324 svn_error_t *
325 svn_error_find_cause(svn_error_t *err, apr_status_t apr_err)
327 svn_error_t *child;
329 for (child = err; child; child = child->child)
330 if (child->apr_err == apr_err)
331 return child;
333 return SVN_NO_ERROR;
336 svn_error_t *
337 svn_error_dup(svn_error_t *err)
339 apr_pool_t *pool;
340 svn_error_t *new_err = NULL, *tmp_err = NULL;
342 if (apr_pool_create(&pool, NULL))
343 abort();
345 for (; err; err = err->child)
347 if (! new_err)
349 new_err = apr_palloc(pool, sizeof(*new_err));
350 tmp_err = new_err;
352 else
354 tmp_err->child = apr_palloc(pool, sizeof(*tmp_err->child));
355 tmp_err = tmp_err->child;
357 *tmp_err = *err;
358 tmp_err->pool = pool;
359 if (tmp_err->message)
360 tmp_err->message = apr_pstrdup(pool, tmp_err->message);
363 #if defined(SVN_DEBUG)
364 apr_pool_cleanup_register(pool, tmp_err,
365 err_abort,
366 apr_pool_cleanup_null);
367 #endif
369 return new_err;
372 void
373 svn_error_clear(svn_error_t *err)
375 if (err)
377 #if defined(SVN_DEBUG)
378 while (err->child)
379 err = err->child;
380 apr_pool_cleanup_kill(err->pool, err, err_abort);
381 #endif
382 svn_pool_destroy(err->pool);
386 svn_boolean_t
387 svn_error__is_tracing_link(svn_error_t *err)
389 #ifdef SVN_ERR__TRACING
390 /* ### A strcmp()? Really? I think it's the best we can do unless
391 ### we add a boolean field to svn_error_t that's set only for
392 ### these "placeholder error chain" items. Not such a bad idea,
393 ### really... */
394 return (err && err->message && !strcmp(err->message, error_tracing_link));
395 #else
396 return FALSE;
397 #endif
400 svn_error_t *
401 svn_error_purge_tracing(svn_error_t *err)
403 #ifdef SVN_ERR__TRACING
404 svn_error_t *new_err = NULL, *new_err_leaf = NULL;
406 if (! err)
407 return SVN_NO_ERROR;
411 svn_error_t *tmp_err;
413 /* Skip over any trace-only links. */
414 while (err && svn_error__is_tracing_link(err))
415 err = err->child;
417 /* The link must be a real link in the error chain, otherwise an
418 error chain with trace only links would map into SVN_NO_ERROR. */
419 if (! err)
420 return svn_error_create(
421 SVN_ERR_ASSERTION_ONLY_TRACING_LINKS,
422 svn_error_compose_create(
423 svn_error__malfunction(TRUE, __FILE__, __LINE__,
424 NULL /* ### say something? */),
425 err),
426 NULL);
428 /* Copy the current error except for its child error pointer
429 into the new error. Share any message and source filename
430 strings from the error. */
431 tmp_err = apr_palloc(err->pool, sizeof(*tmp_err));
432 *tmp_err = *err;
433 tmp_err->child = NULL;
435 /* Add a new link to the new chain (creating the chain if necessary). */
436 if (! new_err)
438 new_err = tmp_err;
439 new_err_leaf = tmp_err;
441 else
443 new_err_leaf->child = tmp_err;
444 new_err_leaf = tmp_err;
447 /* Advance to the next link in the original chain. */
448 err = err->child;
449 } while (err);
451 return new_err;
452 #else /* SVN_ERR__TRACING */
453 return err;
454 #endif /* SVN_ERR__TRACING */
457 /* ### The logic around omitting (sic) apr_err= in maintainer mode is tightly
458 ### coupled to the current sole caller.*/
459 static void
460 print_error(svn_error_t *err, FILE *stream, const char *prefix)
462 char errbuf[256];
463 const char *err_string;
464 svn_error_t *temp_err = NULL; /* ensure initialized even if
465 err->file == NULL */
466 /* Pretty-print the error */
467 /* Note: we can also log errors here someday. */
469 #ifdef SVN_DEBUG
470 /* Note: err->file is _not_ in UTF-8, because it's expanded from
471 the __FILE__ preprocessor macro. */
472 const char *file_utf8;
474 if (err->file
475 && !(temp_err = svn_utf_cstring_to_utf8(&file_utf8, err->file,
476 err->pool)))
477 svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
478 "%s:%ld", err->file, err->line));
479 else
481 svn_error_clear(svn_cmdline_fputs(SVN_FILE_LINE_UNDEFINED,
482 stream, err->pool));
483 svn_error_clear(temp_err);
487 const char *symbolic_name;
488 if (svn_error__is_tracing_link(err))
489 /* Skip it; the error code will be printed by the real link. */
490 svn_error_clear(svn_cmdline_fprintf(stream, err->pool, ",\n"));
491 else if ((symbolic_name = svn_error_symbolic_name(err->apr_err)))
492 svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
493 ": (apr_err=%s)\n", symbolic_name));
494 else
495 svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
496 ": (apr_err=%d)\n", err->apr_err));
498 #endif /* SVN_DEBUG */
500 /* "traced call" */
501 if (svn_error__is_tracing_link(err))
503 /* Skip it. We already printed the file-line coordinates. */
505 /* Only print the same APR error string once. */
506 else if (err->message)
508 svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
509 "%sE%06d: %s\n",
510 prefix, err->apr_err, err->message));
512 else
514 /* Is this a Subversion-specific error code? */
515 if ((err->apr_err > APR_OS_START_USEERR)
516 && (err->apr_err <= APR_OS_START_CANONERR))
517 err_string = svn_strerror(err->apr_err, errbuf, sizeof(errbuf));
518 /* Otherwise, this must be an APR error code. */
519 else if ((temp_err = svn_utf_cstring_to_utf8
520 (&err_string, apr_strerror(err->apr_err, errbuf,
521 sizeof(errbuf)), err->pool)))
523 svn_error_clear(temp_err);
524 err_string = _("Can't recode error string from APR");
527 svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
528 "%sE%06d: %s\n",
529 prefix, err->apr_err, err_string));
533 void
534 svn_handle_error(svn_error_t *err, FILE *stream, svn_boolean_t fatal)
536 svn_handle_error2(err, stream, fatal, "svn: ");
539 void
540 svn_handle_error2(svn_error_t *err,
541 FILE *stream,
542 svn_boolean_t fatal,
543 const char *prefix)
545 /* In a long error chain, there may be multiple errors with the same
546 error code and no custom message. We only want to print the
547 default message for that code once; printing it multiple times
548 would add no useful information. The 'empties' array below
549 remembers the codes of empty errors already seen in the chain.
551 We could allocate it in err->pool, but there's no telling how
552 long err will live or how many times it will get handled. So we
553 use a subpool. */
554 apr_pool_t *subpool;
555 apr_array_header_t *empties;
556 svn_error_t *tmp_err;
558 /* ### The rest of this file carefully avoids using svn_pool_*(),
559 preferring apr_pool_*() instead. I can't remember why -- it may
560 be an artifact of r843793, or it may be for some deeper reason --
561 but I'm playing it safe and using apr_pool_*() here too. */
562 apr_pool_create(&subpool, err->pool);
563 empties = apr_array_make(subpool, 0, sizeof(apr_status_t));
565 tmp_err = err;
566 while (tmp_err)
568 svn_boolean_t printed_already = FALSE;
570 if (! tmp_err->message)
572 int i;
574 for (i = 0; i < empties->nelts; i++)
576 if (tmp_err->apr_err == APR_ARRAY_IDX(empties, i, apr_status_t) )
578 printed_already = TRUE;
579 break;
584 if (! printed_already)
586 print_error(tmp_err, stream, prefix);
587 if (! tmp_err->message)
589 APR_ARRAY_PUSH(empties, apr_status_t) = tmp_err->apr_err;
593 tmp_err = tmp_err->child;
596 svn_pool_destroy(subpool);
598 fflush(stream);
599 if (fatal)
601 /* Avoid abort()s in maintainer mode. */
602 svn_error_clear(err);
604 /* We exit(1) here instead of abort()ing so that atexit handlers
605 get called. */
606 exit(EXIT_FAILURE);
611 void
612 svn_handle_warning(FILE *stream, svn_error_t *err)
614 svn_handle_warning2(stream, err, "svn: ");
617 void
618 svn_handle_warning2(FILE *stream, svn_error_t *err, const char *prefix)
620 char buf[256];
622 svn_error_clear(svn_cmdline_fprintf
623 (stream, err->pool,
624 _("%swarning: W%06d: %s\n"),
625 prefix, err->apr_err,
626 svn_err_best_message(err, buf, sizeof(buf))));
627 fflush(stream);
630 const char *
631 svn_err_best_message(svn_error_t *err, char *buf, apr_size_t bufsize)
633 /* Skip over any trace records. */
634 while (svn_error__is_tracing_link(err))
635 err = err->child;
636 if (err->message)
637 return err->message;
638 else
639 return svn_strerror(err->apr_err, buf, bufsize);
643 /* svn_strerror() and helpers */
645 /* Duplicate of the same typedef in tests/libsvn_subr/error-code-test.c */
646 typedef struct err_defn {
647 svn_errno_t errcode; /* 160004 */
648 const char *errname; /* SVN_ERR_FS_CORRUPT */
649 const char *errdesc; /* default message */
650 } err_defn;
652 /* To understand what is going on here, read svn_error_codes.h. */
653 #define SVN_ERROR_BUILD_ARRAY
654 #include "svn_error_codes.h"
656 char *
657 svn_strerror(apr_status_t statcode, char *buf, apr_size_t bufsize)
659 const err_defn *defn;
661 for (defn = error_table; defn->errdesc != NULL; ++defn)
662 if (defn->errcode == (svn_errno_t)statcode)
664 apr_cpystrn(buf, _(defn->errdesc), bufsize);
665 return buf;
668 return apr_strerror(statcode, buf, bufsize);
671 const char *
672 svn_error_symbolic_name(apr_status_t statcode)
674 const err_defn *defn;
676 for (defn = error_table; defn->errdesc != NULL; ++defn)
677 if (defn->errcode == (svn_errno_t)statcode)
678 return defn->errname;
680 /* "No error" is not in error_table. */
681 if (statcode == SVN_NO_ERROR)
682 return "SVN_NO_ERROR";
684 return NULL;
689 /* Malfunctions. */
691 svn_error_t *
692 svn_error_raise_on_malfunction(svn_boolean_t can_return,
693 const char *file, int line,
694 const char *expr)
696 if (!can_return)
697 abort(); /* Nothing else we can do as a library */
699 /* The filename and line number of the error source needs to be set
700 here because svn_error_createf() is not the macro defined in
701 svn_error.h but the real function. */
702 svn_error__locate(file, line);
704 if (expr)
705 return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL,
706 _("In file '%s' line %d: assertion failed (%s)"),
707 file, line, expr);
708 else
709 return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL,
710 _("In file '%s' line %d: internal malfunction"),
711 file, line);
714 svn_error_t *
715 svn_error_abort_on_malfunction(svn_boolean_t can_return,
716 const char *file, int line,
717 const char *expr)
719 svn_error_t *err = svn_error_raise_on_malfunction(TRUE, file, line, expr);
721 svn_handle_error2(err, stderr, FALSE, "svn: ");
722 abort();
723 return err; /* Not reached. */
726 /* The current handler for reporting malfunctions, and its default setting. */
727 static svn_error_malfunction_handler_t malfunction_handler
728 = svn_error_abort_on_malfunction;
730 svn_error_malfunction_handler_t
731 svn_error_set_malfunction_handler(svn_error_malfunction_handler_t func)
733 svn_error_malfunction_handler_t old_malfunction_handler
734 = malfunction_handler;
736 malfunction_handler = func;
737 return old_malfunction_handler;
740 /* Note: Although this is a "__" function, it is in the public ABI, so
741 * we can never remove it or change its signature. */
742 svn_error_t *
743 svn_error__malfunction(svn_boolean_t can_return,
744 const char *file, int line,
745 const char *expr)
747 return malfunction_handler(can_return, file, line, expr);
751 /* Misc. */
753 svn_error_t *
754 svn_error__wrap_zlib(int zerr, const char *function, const char *message)
756 apr_status_t status;
757 const char *zmsg;
759 if (zerr == Z_OK)
760 return SVN_NO_ERROR;
762 switch (zerr)
764 case Z_STREAM_ERROR:
765 status = SVN_ERR_STREAM_MALFORMED_DATA;
766 zmsg = _("stream error");
767 break;
769 case Z_MEM_ERROR:
770 status = APR_ENOMEM;
771 zmsg = _("out of memory");
772 break;
774 case Z_BUF_ERROR:
775 status = APR_ENOMEM;
776 zmsg = _("buffer error");
777 break;
779 case Z_VERSION_ERROR:
780 status = SVN_ERR_STREAM_UNRECOGNIZED_DATA;
781 zmsg = _("version error");
782 break;
784 case Z_DATA_ERROR:
785 status = SVN_ERR_STREAM_MALFORMED_DATA;
786 zmsg = _("corrupt data");
787 break;
789 default:
790 status = SVN_ERR_STREAM_UNRECOGNIZED_DATA;
791 zmsg = _("unknown error");
792 break;
795 if (message != NULL)
796 return svn_error_createf(status, NULL, "zlib (%s): %s: %s", function,
797 zmsg, message);
798 else
799 return svn_error_createf(status, NULL, "zlib (%s): %s", function, zmsg);