PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/Subversion/subversion/libsvn_subr/error.c

http://commitmonitor.googlecode.com/
C | 800 lines | 562 code | 130 blank | 108 comment | 75 complexity | b8f2de72e32f34a3273f0df3fe190aa1 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, GPL-2.0, BSD-3-Clause, AGPL-1.0
  1. /* error.c: common exception handling for Subversion
  2. *
  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
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  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. * ====================================================================
  21. */
  22. #include <stdarg.h>
  23. #include <apr_general.h>
  24. #include <apr_pools.h>
  25. #include <apr_strings.h>
  26. #include <zlib.h>
  27. #ifndef SVN_ERR__TRACING
  28. #define SVN_ERR__TRACING
  29. #endif
  30. #include "svn_cmdline.h"
  31. #include "svn_error.h"
  32. #include "svn_pools.h"
  33. #include "svn_utf.h"
  34. #ifdef SVN_DEBUG
  35. /* XXX FIXME: These should be protected by a thread mutex.
  36. svn_error__locate and make_error_internal should cooperate
  37. in locking and unlocking it. */
  38. /* XXX TODO: Define mutex here #if APR_HAS_THREADS */
  39. static const char * volatile error_file = NULL;
  40. static long volatile error_line = -1;
  41. /* file_line for the non-debug case. */
  42. static const char SVN_FILE_LINE_UNDEFINED[] = "svn:<undefined>";
  43. #endif /* SVN_DEBUG */
  44. #include "svn_private_config.h"
  45. #include "private/svn_error_private.h"
  46. /*
  47. * Undefine the helpers for creating errors.
  48. *
  49. * *NOTE*: Any use of these functions in any other function may need
  50. * to call svn_error__locate() because the macro that would otherwise
  51. * do this is being undefined and the filename and line number will
  52. * not be properly set in the static error_file and error_line
  53. * variables.
  54. */
  55. #undef svn_error_create
  56. #undef svn_error_createf
  57. #undef svn_error_quick_wrap
  58. #undef svn_error_wrap_apr
  59. /* Note: Although this is a "__" function, it was historically in the
  60. * public ABI, so we can never change it or remove its signature, even
  61. * though it is now only used in SVN_DEBUG mode. */
  62. void
  63. svn_error__locate(const char *file, long line)
  64. {
  65. #if defined(SVN_DEBUG)
  66. /* XXX TODO: Lock mutex here */
  67. error_file = file;
  68. error_line = line;
  69. #endif
  70. }
  71. /* Cleanup function for errors. svn_error_clear () removes this so
  72. errors that are properly handled *don't* hit this code. */
  73. #if defined(SVN_DEBUG)
  74. static apr_status_t err_abort(void *data)
  75. {
  76. svn_error_t *err = data; /* For easy viewing in a debugger */
  77. err = err; /* Fake a use for the variable to avoid compiler warnings */
  78. if (!getenv("SVN_DBG_NO_ABORT_ON_ERROR_LEAK"))
  79. abort();
  80. return APR_SUCCESS;
  81. }
  82. #endif
  83. static svn_error_t *
  84. make_error_internal(apr_status_t apr_err,
  85. svn_error_t *child)
  86. {
  87. apr_pool_t *pool;
  88. svn_error_t *new_error;
  89. /* Reuse the child's pool, or create our own. */
  90. if (child)
  91. pool = child->pool;
  92. else
  93. {
  94. if (apr_pool_create(&pool, NULL))
  95. abort();
  96. }
  97. /* Create the new error structure */
  98. new_error = apr_pcalloc(pool, sizeof(*new_error));
  99. /* Fill 'er up. */
  100. new_error->apr_err = apr_err;
  101. new_error->child = child;
  102. new_error->pool = pool;
  103. #if defined(SVN_DEBUG)
  104. new_error->file = error_file;
  105. new_error->line = error_line;
  106. /* XXX TODO: Unlock mutex here */
  107. if (! child)
  108. apr_pool_cleanup_register(pool, new_error,
  109. err_abort,
  110. apr_pool_cleanup_null);
  111. #endif
  112. return new_error;
  113. }
  114. /*** Creating and destroying errors. ***/
  115. svn_error_t *
  116. svn_error_create(apr_status_t apr_err,
  117. svn_error_t *child,
  118. const char *message)
  119. {
  120. svn_error_t *err;
  121. err = make_error_internal(apr_err, child);
  122. if (message)
  123. err->message = apr_pstrdup(err->pool, message);
  124. return err;
  125. }
  126. svn_error_t *
  127. svn_error_createf(apr_status_t apr_err,
  128. svn_error_t *child,
  129. const char *fmt,
  130. ...)
  131. {
  132. svn_error_t *err;
  133. va_list ap;
  134. err = make_error_internal(apr_err, child);
  135. va_start(ap, fmt);
  136. err->message = apr_pvsprintf(err->pool, fmt, ap);
  137. va_end(ap);
  138. return err;
  139. }
  140. svn_error_t *
  141. svn_error_wrap_apr(apr_status_t status,
  142. const char *fmt,
  143. ...)
  144. {
  145. svn_error_t *err, *utf8_err;
  146. va_list ap;
  147. char errbuf[255];
  148. const char *msg_apr, *msg;
  149. err = make_error_internal(status, NULL);
  150. if (fmt)
  151. {
  152. /* Grab the APR error message. */
  153. apr_strerror(status, errbuf, sizeof(errbuf));
  154. utf8_err = svn_utf_cstring_to_utf8(&msg_apr, errbuf, err->pool);
  155. if (utf8_err)
  156. msg_apr = NULL;
  157. svn_error_clear(utf8_err);
  158. /* Append it to the formatted message. */
  159. va_start(ap, fmt);
  160. msg = apr_pvsprintf(err->pool, fmt, ap);
  161. va_end(ap);
  162. if (msg_apr)
  163. {
  164. err->message = apr_pstrcat(err->pool, msg, ": ", msg_apr, NULL);
  165. }
  166. else
  167. {
  168. err->message = msg;
  169. }
  170. }
  171. return err;
  172. }
  173. svn_error_t *
  174. svn_error_quick_wrap(svn_error_t *child, const char *new_msg)
  175. {
  176. if (child == SVN_NO_ERROR)
  177. return SVN_NO_ERROR;
  178. return svn_error_create(child->apr_err,
  179. child,
  180. new_msg);
  181. }
  182. /* Messages in tracing errors all point to this static string. */
  183. static const char error_tracing_link[] = "traced call";
  184. svn_error_t *
  185. svn_error__trace(const char *file, long line, svn_error_t *err)
  186. {
  187. #ifndef SVN_DEBUG
  188. /* We shouldn't even be here, but whatever. Just return the error as-is. */
  189. return err;
  190. #else
  191. /* Only do the work when an error occurs. */
  192. if (err)
  193. {
  194. svn_error_t *trace;
  195. svn_error__locate(file, line);
  196. trace = make_error_internal(err->apr_err, err);
  197. trace->message = error_tracing_link;
  198. return trace;
  199. }
  200. return SVN_NO_ERROR;
  201. #endif
  202. }
  203. svn_error_t *
  204. svn_error_compose_create(svn_error_t *err1,
  205. svn_error_t *err2)
  206. {
  207. if (err1 && err2)
  208. {
  209. svn_error_compose(err1,
  210. svn_error_quick_wrap(err2,
  211. _("Additional errors:")));
  212. return err1;
  213. }
  214. return err1 ? err1 : err2;
  215. }
  216. void
  217. svn_error_compose(svn_error_t *chain, svn_error_t *new_err)
  218. {
  219. apr_pool_t *pool = chain->pool;
  220. apr_pool_t *oldpool = new_err->pool;
  221. while (chain->child)
  222. chain = chain->child;
  223. #if defined(SVN_DEBUG)
  224. /* Kill existing handler since the end of the chain is going to change */
  225. apr_pool_cleanup_kill(pool, chain, err_abort);
  226. #endif
  227. /* Copy the new error chain into the old chain's pool. */
  228. while (new_err)
  229. {
  230. chain->child = apr_palloc(pool, sizeof(*chain->child));
  231. chain = chain->child;
  232. *chain = *new_err;
  233. if (chain->message)
  234. chain->message = apr_pstrdup(pool, new_err->message);
  235. chain->pool = pool;
  236. #if defined(SVN_DEBUG)
  237. if (! new_err->child)
  238. apr_pool_cleanup_kill(oldpool, new_err, err_abort);
  239. #endif
  240. new_err = new_err->child;
  241. }
  242. #if defined(SVN_DEBUG)
  243. apr_pool_cleanup_register(pool, chain,
  244. err_abort,
  245. apr_pool_cleanup_null);
  246. #endif
  247. /* Destroy the new error chain. */
  248. svn_pool_destroy(oldpool);
  249. }
  250. svn_error_t *
  251. svn_error_root_cause(svn_error_t *err)
  252. {
  253. while (err)
  254. {
  255. if (err->child)
  256. err = err->child;
  257. else
  258. break;
  259. }
  260. return err;
  261. }
  262. svn_error_t *
  263. svn_error_find_cause(svn_error_t *err, apr_status_t apr_err)
  264. {
  265. svn_error_t *child;
  266. for (child = err; child; child = child->child)
  267. if (child->apr_err == apr_err)
  268. return child;
  269. return SVN_NO_ERROR;
  270. }
  271. svn_error_t *
  272. svn_error_dup(svn_error_t *err)
  273. {
  274. apr_pool_t *pool;
  275. svn_error_t *new_err = NULL, *tmp_err = NULL;
  276. if (apr_pool_create(&pool, NULL))
  277. abort();
  278. for (; err; err = err->child)
  279. {
  280. if (! new_err)
  281. {
  282. new_err = apr_palloc(pool, sizeof(*new_err));
  283. tmp_err = new_err;
  284. }
  285. else
  286. {
  287. tmp_err->child = apr_palloc(pool, sizeof(*tmp_err->child));
  288. tmp_err = tmp_err->child;
  289. }
  290. *tmp_err = *err;
  291. tmp_err->pool = pool;
  292. if (tmp_err->message)
  293. tmp_err->message = apr_pstrdup(pool, tmp_err->message);
  294. }
  295. #if defined(SVN_DEBUG)
  296. apr_pool_cleanup_register(pool, tmp_err,
  297. err_abort,
  298. apr_pool_cleanup_null);
  299. #endif
  300. return new_err;
  301. }
  302. void
  303. svn_error_clear(svn_error_t *err)
  304. {
  305. if (err)
  306. {
  307. #if defined(SVN_DEBUG)
  308. while (err->child)
  309. err = err->child;
  310. apr_pool_cleanup_kill(err->pool, err, err_abort);
  311. #endif
  312. svn_pool_destroy(err->pool);
  313. }
  314. }
  315. svn_boolean_t
  316. svn_error__is_tracing_link(svn_error_t *err)
  317. {
  318. #ifdef SVN_ERR__TRACING
  319. /* ### A strcmp()? Really? I think it's the best we can do unless
  320. ### we add a boolean field to svn_error_t that's set only for
  321. ### these "placeholder error chain" items. Not such a bad idea,
  322. ### really... */
  323. return (err && err->message && !strcmp(err->message, error_tracing_link));
  324. #else
  325. return FALSE;
  326. #endif
  327. }
  328. svn_error_t *
  329. svn_error_purge_tracing(svn_error_t *err)
  330. {
  331. #ifdef SVN_ERR__TRACING
  332. svn_error_t *new_err = NULL, *new_err_leaf = NULL;
  333. if (! err)
  334. return SVN_NO_ERROR;
  335. do
  336. {
  337. svn_error_t *tmp_err;
  338. /* Skip over any trace-only links. */
  339. while (err && svn_error__is_tracing_link(err))
  340. err = err->child;
  341. /* The link must be a real link in the error chain, otherwise an
  342. error chain with trace only links would map into SVN_NO_ERROR. */
  343. if (! err)
  344. return svn_error_create(
  345. SVN_ERR_ASSERTION_ONLY_TRACING_LINKS,
  346. svn_error_compose_create(
  347. svn_error__malfunction(TRUE, __FILE__, __LINE__,
  348. NULL /* ### say something? */),
  349. err),
  350. NULL);
  351. /* Copy the current error except for its child error pointer
  352. into the new error. Share any message and source filename
  353. strings from the error. */
  354. tmp_err = apr_palloc(err->pool, sizeof(*tmp_err));
  355. *tmp_err = *err;
  356. tmp_err->child = NULL;
  357. /* Add a new link to the new chain (creating the chain if necessary). */
  358. if (! new_err)
  359. {
  360. new_err = tmp_err;
  361. new_err_leaf = tmp_err;
  362. }
  363. else
  364. {
  365. new_err_leaf->child = tmp_err;
  366. new_err_leaf = tmp_err;
  367. }
  368. /* Advance to the next link in the original chain. */
  369. err = err->child;
  370. } while (err);
  371. return new_err;
  372. #else /* SVN_ERR__TRACING */
  373. return err;
  374. #endif /* SVN_ERR__TRACING */
  375. }
  376. /* ### The logic around omitting (sic) apr_err= in maintainer mode is tightly
  377. ### coupled to the current sole caller.*/
  378. static void
  379. print_error(svn_error_t *err, FILE *stream, const char *prefix)
  380. {
  381. char errbuf[256];
  382. const char *err_string;
  383. svn_error_t *temp_err = NULL; /* ensure initialized even if
  384. err->file == NULL */
  385. /* Pretty-print the error */
  386. /* Note: we can also log errors here someday. */
  387. #ifdef SVN_DEBUG
  388. /* Note: err->file is _not_ in UTF-8, because it's expanded from
  389. the __FILE__ preprocessor macro. */
  390. const char *file_utf8;
  391. if (err->file
  392. && !(temp_err = svn_utf_cstring_to_utf8(&file_utf8, err->file,
  393. err->pool)))
  394. svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
  395. "%s:%ld", err->file, err->line));
  396. else
  397. {
  398. svn_error_clear(svn_cmdline_fputs(SVN_FILE_LINE_UNDEFINED,
  399. stream, err->pool));
  400. svn_error_clear(temp_err);
  401. }
  402. {
  403. const char *symbolic_name;
  404. if (svn_error__is_tracing_link(err))
  405. /* Skip it; the error code will be printed by the real link. */
  406. svn_error_clear(svn_cmdline_fprintf(stream, err->pool, ",\n"));
  407. else if ((symbolic_name = svn_error_symbolic_name(err->apr_err)))
  408. svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
  409. ": (apr_err=%s)\n", symbolic_name));
  410. else
  411. svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
  412. ": (apr_err=%d)\n", err->apr_err));
  413. }
  414. #endif /* SVN_DEBUG */
  415. /* "traced call" */
  416. if (svn_error__is_tracing_link(err))
  417. {
  418. /* Skip it. We already printed the file-line coordinates. */
  419. }
  420. /* Only print the same APR error string once. */
  421. else if (err->message)
  422. {
  423. svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
  424. "%sE%06d: %s\n",
  425. prefix, err->apr_err, err->message));
  426. }
  427. else
  428. {
  429. /* Is this a Subversion-specific error code? */
  430. if ((err->apr_err > APR_OS_START_USEERR)
  431. && (err->apr_err <= APR_OS_START_CANONERR))
  432. err_string = svn_strerror(err->apr_err, errbuf, sizeof(errbuf));
  433. /* Otherwise, this must be an APR error code. */
  434. else if ((temp_err = svn_utf_cstring_to_utf8
  435. (&err_string, apr_strerror(err->apr_err, errbuf,
  436. sizeof(errbuf)), err->pool)))
  437. {
  438. svn_error_clear(temp_err);
  439. err_string = _("Can't recode error string from APR");
  440. }
  441. svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
  442. "%sE%06d: %s\n",
  443. prefix, err->apr_err, err_string));
  444. }
  445. }
  446. void
  447. svn_handle_error(svn_error_t *err, FILE *stream, svn_boolean_t fatal)
  448. {
  449. svn_handle_error2(err, stream, fatal, "svn: ");
  450. }
  451. void
  452. svn_handle_error2(svn_error_t *err,
  453. FILE *stream,
  454. svn_boolean_t fatal,
  455. const char *prefix)
  456. {
  457. /* In a long error chain, there may be multiple errors with the same
  458. error code and no custom message. We only want to print the
  459. default message for that code once; printing it multiple times
  460. would add no useful information. The 'empties' array below
  461. remembers the codes of empty errors already seen in the chain.
  462. We could allocate it in err->pool, but there's no telling how
  463. long err will live or how many times it will get handled. So we
  464. use a subpool. */
  465. apr_pool_t *subpool;
  466. apr_array_header_t *empties;
  467. svn_error_t *tmp_err;
  468. /* ### The rest of this file carefully avoids using svn_pool_*(),
  469. preferring apr_pool_*() instead. I can't remember why -- it may
  470. be an artifact of r843793, or it may be for some deeper reason --
  471. but I'm playing it safe and using apr_pool_*() here too. */
  472. apr_pool_create(&subpool, err->pool);
  473. empties = apr_array_make(subpool, 0, sizeof(apr_status_t));
  474. tmp_err = err;
  475. while (tmp_err)
  476. {
  477. svn_boolean_t printed_already = FALSE;
  478. if (! tmp_err->message)
  479. {
  480. int i;
  481. for (i = 0; i < empties->nelts; i++)
  482. {
  483. if (tmp_err->apr_err == APR_ARRAY_IDX(empties, i, apr_status_t) )
  484. {
  485. printed_already = TRUE;
  486. break;
  487. }
  488. }
  489. }
  490. if (! printed_already)
  491. {
  492. print_error(tmp_err, stream, prefix);
  493. if (! tmp_err->message)
  494. {
  495. APR_ARRAY_PUSH(empties, apr_status_t) = tmp_err->apr_err;
  496. }
  497. }
  498. tmp_err = tmp_err->child;
  499. }
  500. svn_pool_destroy(subpool);
  501. fflush(stream);
  502. if (fatal)
  503. {
  504. /* Avoid abort()s in maintainer mode. */
  505. svn_error_clear(err);
  506. /* We exit(1) here instead of abort()ing so that atexit handlers
  507. get called. */
  508. exit(EXIT_FAILURE);
  509. }
  510. }
  511. void
  512. svn_handle_warning(FILE *stream, svn_error_t *err)
  513. {
  514. svn_handle_warning2(stream, err, "svn: ");
  515. }
  516. void
  517. svn_handle_warning2(FILE *stream, svn_error_t *err, const char *prefix)
  518. {
  519. char buf[256];
  520. svn_error_clear(svn_cmdline_fprintf
  521. (stream, err->pool,
  522. _("%swarning: W%06d: %s\n"),
  523. prefix, err->apr_err,
  524. svn_err_best_message(err, buf, sizeof(buf))));
  525. fflush(stream);
  526. }
  527. const char *
  528. svn_err_best_message(svn_error_t *err, char *buf, apr_size_t bufsize)
  529. {
  530. /* Skip over any trace records. */
  531. while (svn_error__is_tracing_link(err))
  532. err = err->child;
  533. if (err->message)
  534. return err->message;
  535. else
  536. return svn_strerror(err->apr_err, buf, bufsize);
  537. }
  538. /* svn_strerror() and helpers */
  539. /* Duplicate of the same typedef in tests/libsvn_subr/error-code-test.c */
  540. typedef struct err_defn {
  541. svn_errno_t errcode; /* 160004 */
  542. const char *errname; /* SVN_ERR_FS_CORRUPT */
  543. const char *errdesc; /* default message */
  544. } err_defn;
  545. /* To understand what is going on here, read svn_error_codes.h. */
  546. #define SVN_ERROR_BUILD_ARRAY
  547. #include "svn_error_codes.h"
  548. char *
  549. svn_strerror(apr_status_t statcode, char *buf, apr_size_t bufsize)
  550. {
  551. const err_defn *defn;
  552. for (defn = error_table; defn->errdesc != NULL; ++defn)
  553. if (defn->errcode == (svn_errno_t)statcode)
  554. {
  555. apr_cpystrn(buf, _(defn->errdesc), bufsize);
  556. return buf;
  557. }
  558. return apr_strerror(statcode, buf, bufsize);
  559. }
  560. const char *
  561. svn_error_symbolic_name(apr_status_t statcode)
  562. {
  563. const err_defn *defn;
  564. for (defn = error_table; defn->errdesc != NULL; ++defn)
  565. if (defn->errcode == (svn_errno_t)statcode)
  566. return defn->errname;
  567. /* "No error" is not in error_table. */
  568. if (statcode == SVN_NO_ERROR)
  569. return "SVN_NO_ERROR";
  570. return NULL;
  571. }
  572. /* Malfunctions. */
  573. svn_error_t *
  574. svn_error_raise_on_malfunction(svn_boolean_t can_return,
  575. const char *file, int line,
  576. const char *expr)
  577. {
  578. if (!can_return)
  579. abort(); /* Nothing else we can do as a library */
  580. /* The filename and line number of the error source needs to be set
  581. here because svn_error_createf() is not the macro defined in
  582. svn_error.h but the real function. */
  583. svn_error__locate(file, line);
  584. if (expr)
  585. return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL,
  586. _("In file '%s' line %d: assertion failed (%s)"),
  587. file, line, expr);
  588. else
  589. return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL,
  590. _("In file '%s' line %d: internal malfunction"),
  591. file, line);
  592. }
  593. svn_error_t *
  594. svn_error_abort_on_malfunction(svn_boolean_t can_return,
  595. const char *file, int line,
  596. const char *expr)
  597. {
  598. svn_error_t *err = svn_error_raise_on_malfunction(TRUE, file, line, expr);
  599. svn_handle_error2(err, stderr, FALSE, "svn: ");
  600. abort();
  601. return err; /* Not reached. */
  602. }
  603. /* The current handler for reporting malfunctions, and its default setting. */
  604. static svn_error_malfunction_handler_t malfunction_handler
  605. = svn_error_abort_on_malfunction;
  606. svn_error_malfunction_handler_t
  607. svn_error_set_malfunction_handler(svn_error_malfunction_handler_t func)
  608. {
  609. svn_error_malfunction_handler_t old_malfunction_handler
  610. = malfunction_handler;
  611. malfunction_handler = func;
  612. return old_malfunction_handler;
  613. }
  614. /* Note: Although this is a "__" function, it is in the public ABI, so
  615. * we can never remove it or change its signature. */
  616. svn_error_t *
  617. svn_error__malfunction(svn_boolean_t can_return,
  618. const char *file, int line,
  619. const char *expr)
  620. {
  621. return malfunction_handler(can_return, file, line, expr);
  622. }
  623. /* Misc. */
  624. svn_error_t *
  625. svn_error__wrap_zlib(int zerr, const char *function, const char *message)
  626. {
  627. apr_status_t status;
  628. const char *zmsg;
  629. if (zerr == Z_OK)
  630. return SVN_NO_ERROR;
  631. switch (zerr)
  632. {
  633. case Z_STREAM_ERROR:
  634. status = SVN_ERR_STREAM_MALFORMED_DATA;
  635. zmsg = _("stream error");
  636. break;
  637. case Z_MEM_ERROR:
  638. status = APR_ENOMEM;
  639. zmsg = _("out of memory");
  640. break;
  641. case Z_BUF_ERROR:
  642. status = APR_ENOMEM;
  643. zmsg = _("buffer error");
  644. break;
  645. case Z_VERSION_ERROR:
  646. status = SVN_ERR_STREAM_UNRECOGNIZED_DATA;
  647. zmsg = _("version error");
  648. break;
  649. case Z_DATA_ERROR:
  650. status = SVN_ERR_STREAM_MALFORMED_DATA;
  651. zmsg = _("corrupt data");
  652. break;
  653. default:
  654. status = SVN_ERR_STREAM_UNRECOGNIZED_DATA;
  655. zmsg = _("unknown error");
  656. break;
  657. }
  658. if (message != NULL)
  659. return svn_error_createf(status, NULL, "zlib (%s): %s: %s", function,
  660. zmsg, message);
  661. else
  662. return svn_error_createf(status, NULL, "zlib (%s): %s", function, zmsg);
  663. }