diff options
| author | Peter Wemm <peter@FreeBSD.org> | 2016-12-01 07:45:05 +0000 | 
|---|---|---|
| committer | Peter Wemm <peter@FreeBSD.org> | 2016-12-01 07:45:05 +0000 | 
| commit | 608944fa5a78d7f517c9c73a7ded6c130cc97b83 (patch) | |
| tree | 9dce7c56ce4cbd36bb5457661d50b23d30c3533c /subversion/libsvn_subr | |
| parent | c94cceea9c2262c5b2ad5f215bb9a8ae48b02764 (diff) | |
Notes
Diffstat (limited to 'subversion/libsvn_subr')
| -rw-r--r-- | subversion/libsvn_subr/config_file.c | 22 | ||||
| -rw-r--r-- | subversion/libsvn_subr/deprecated.c | 10 | ||||
| -rw-r--r-- | subversion/libsvn_subr/gpg_agent.c | 20 | ||||
| -rw-r--r-- | subversion/libsvn_subr/internal_statements.h | 2 | ||||
| -rw-r--r-- | subversion/libsvn_subr/sqlite.c | 142 | ||||
| -rw-r--r-- | subversion/libsvn_subr/sysinfo.c | 2 | ||||
| -rw-r--r-- | subversion/libsvn_subr/win32_crashrpt.c | 82 | ||||
| -rw-r--r-- | subversion/libsvn_subr/xml.c | 39 | 
8 files changed, 214 insertions, 105 deletions
diff --git a/subversion/libsvn_subr/config_file.c b/subversion/libsvn_subr/config_file.c index eede717575b6..8b4d7a35220c 100644 --- a/subversion/libsvn_subr/config_file.c +++ b/subversion/libsvn_subr/config_file.c @@ -74,6 +74,9 @@ typedef struct parse_context_t    char parser_buffer[SVN__STREAM_CHUNK_SIZE]; /* Larger than most config files */    size_t buffer_pos; /* Current position within parser_buffer */    size_t buffer_size; /* parser_buffer contains this many bytes */ + +  /* Non-zero if we hit EOF on the stream. */ +  svn_boolean_t hit_stream_eof;  } parse_context_t; @@ -101,11 +104,15 @@ parser_getc(parse_context_t *ctx, int *c)          }        else          { -          ctx->buffer_pos = 0; -          ctx->buffer_size = sizeof(ctx->parser_buffer); +          if (!ctx->hit_stream_eof) +            { +              ctx->buffer_pos = 0; +              ctx->buffer_size = sizeof(ctx->parser_buffer); -          SVN_ERR(svn_stream_read_full(ctx->stream, ctx->parser_buffer, -                                       &(ctx->buffer_size))); +              SVN_ERR(svn_stream_read_full(ctx->stream, ctx->parser_buffer, +                                           &(ctx->buffer_size))); +              ctx->hit_stream_eof = (ctx->buffer_size != sizeof(ctx->parser_buffer)); +            }            if (ctx->buffer_pos < ctx->buffer_size)              { @@ -224,8 +231,10 @@ skip_bom(parse_context_t *ctx)         * of the BOM characters into the parse_context_t buffer.  This can         * safely be assumed as long as we only try to use skip_bom() at the         * start of the stream and the buffer is longer than 3 characters. */ -      SVN_ERR_ASSERT(ctx->buffer_size > ctx->buffer_pos + 1); -      if (buf[ctx->buffer_pos] == 0xBB && buf[ctx->buffer_pos + 1] == 0xBF) +      SVN_ERR_ASSERT(ctx->buffer_size > ctx->buffer_pos + 1 || +                     ctx->hit_stream_eof); +      if (ctx->buffer_size > ctx->buffer_pos + 1 && +          buf[ctx->buffer_pos] == 0xBB && buf[ctx->buffer_pos + 1] == 0xBF)          ctx->buffer_pos += 2;        else          SVN_ERR(parser_ungetc(ctx, ch)); @@ -579,6 +588,7 @@ svn_config__parse_stream(svn_config_t *cfg, svn_stream_t *stream,    ctx->value = svn_stringbuf_create_empty(scratch_pool);    ctx->buffer_pos = 0;    ctx->buffer_size = 0; +  ctx->hit_stream_eof = FALSE;    SVN_ERR(skip_bom(ctx)); diff --git a/subversion/libsvn_subr/deprecated.c b/subversion/libsvn_subr/deprecated.c index a0bf813eada7..68e3bd2cb3f9 100644 --- a/subversion/libsvn_subr/deprecated.c +++ b/subversion/libsvn_subr/deprecated.c @@ -1484,7 +1484,11 @@ void  svn_auth_get_keychain_simple_provider(svn_auth_provider_object_t **provider,                                        apr_pool_t *pool)  { +#ifdef SVN_HAVE_KEYCHAIN_SERVICES    svn_auth__get_keychain_simple_provider(provider, pool); +#else +  svn_auth__get_dummmy_simple_provider(provider, pool); +#endif  }  void @@ -1492,7 +1496,13 @@ svn_auth_get_keychain_ssl_client_cert_pw_provider    (svn_auth_provider_object_t **provider,     apr_pool_t *pool)  { +#ifdef SVN_HAVE_KEYCHAIN_SERVICES    svn_auth__get_keychain_ssl_client_cert_pw_provider(provider, pool); +#else +  /* Not really the right type of dummy provider, but doesn't throw NULL +     errors as just returning NULL would */ +  svn_auth__get_dummmy_simple_provider(provider, pool); +#endif  }  #endif /* DARWIN */ diff --git a/subversion/libsvn_subr/gpg_agent.c b/subversion/libsvn_subr/gpg_agent.c index d53eec44c28f..36fe30ddb8fe 100644 --- a/subversion/libsvn_subr/gpg_agent.c +++ b/subversion/libsvn_subr/gpg_agent.c @@ -233,6 +233,7 @@ find_running_gpg_agent(int *new_sd, apr_pool_t *pool)  {    char *buffer;    char *gpg_agent_info = NULL; +  char *gnupghome = NULL;    const char *socket_name = NULL;    const char *request = NULL;    const char *p = NULL; @@ -243,10 +244,9 @@ find_running_gpg_agent(int *new_sd, apr_pool_t *pool)    /* This implements the method of finding the socket as described in     * the gpg-agent man page under the --use-standard-socket option. -   * The manage page misleadingly says the standard socket is -   * "named 'S.gpg-agent' located in the home directory."  The standard -   * socket path is actually in the .gnupg directory in the home directory, -   * i.e. ~/.gnupg/S.gpg-agent */ +   * The manage page says the standard socket is "named 'S.gpg-agent' located +   * in the home directory."  GPG's home directory is either the directory +   * specified by $GNUPGHOME or ~/.gnupg. */    gpg_agent_info = getenv("GPG_AGENT_INFO");    if (gpg_agent_info != NULL)      { @@ -259,6 +259,11 @@ find_running_gpg_agent(int *new_sd, apr_pool_t *pool)                                           pool);        socket_name = APR_ARRAY_IDX(socket_details, 0, const char *);      } +  else if ((gnupghome = getenv("GNUPGHOME")) != NULL) +    { +      const char *homedir = svn_dirent_canonicalize(gnupghome, pool); +      socket_name = svn_dirent_join(homedir, "S.gpg-agent", pool); +    }    else      {        const char *homedir = svn_user_get_homedir(pool); @@ -611,11 +616,10 @@ simple_gpg_agent_next_creds(void **credentials,        return SVN_NO_ERROR;      } +  bye_gpg_agent(sd); +    if (strncmp(buffer, "OK\n", 3) != 0) -    { -      bye_gpg_agent(sd); -      return SVN_NO_ERROR; -    } +    return SVN_NO_ERROR;    /* TODO: This attempt limit hard codes it at 3 attempts (or 2 retries)     * which matches svn command line client's retry_limit as set in diff --git a/subversion/libsvn_subr/internal_statements.h b/subversion/libsvn_subr/internal_statements.h index 93251a47e997..39b671964787 100644 --- a/subversion/libsvn_subr/internal_statements.h +++ b/subversion/libsvn_subr/internal_statements.h @@ -1,4 +1,4 @@ -/* This file is automatically generated from internal_statements.sql and .dist_sandbox/subversion-1.9.4/subversion/libsvn_subr/token-map.h. +/* This file is automatically generated from internal_statements.sql and .dist_sandbox/subversion-1.9.5/subversion/libsvn_subr/token-map.h.   * Do not edit this file -- edit the source and rerun gen-make.py */  #define STMT_INTERNAL_SAVEPOINT_SVN 0 diff --git a/subversion/libsvn_subr/sqlite.c b/subversion/libsvn_subr/sqlite.c index 18d1c4928558..18124a3508e6 100644 --- a/subversion/libsvn_subr/sqlite.c +++ b/subversion/libsvn_subr/sqlite.c @@ -1261,6 +1261,55 @@ reset_all_statements(svn_sqlite__db_t *db,    return err;  } +static svn_error_t * +rollback_transaction(svn_sqlite__db_t *db, +                     svn_error_t *error_to_wrap) +{ +  svn_sqlite__stmt_t *stmt; +  svn_error_t *err; + +  err = get_internal_statement(&stmt, db, STMT_INTERNAL_ROLLBACK_TRANSACTION); +  if (!err) +    { +      err = svn_error_trace(svn_sqlite__step_done(stmt)); + +      if (err && err->apr_err == SVN_ERR_SQLITE_BUSY) +        { +          /* ### Houston, we have a problem! + +             We are trying to rollback but we can't because some +             statements are still busy. This leaves the database +             unusable for future transactions as the current transaction +             is still open. + +             As we are returning the actual error as the most relevant +             error in the chain, our caller might assume that it can +             retry/compensate on this error (e.g. SVN_WC_LOCKED), while +             in fact the SQLite database is unusable until the statements +             started within this transaction are reset and the transaction +             aborted. + +             We try to compensate by resetting all prepared but unreset +             statements; but we leave the busy error in the chain anyway to +             help diagnosing the original error and help in finding where +             a reset statement is missing. */ +          err = svn_error_trace(reset_all_statements(db, err)); +          err = svn_error_compose_create( +                      svn_error_trace(svn_sqlite__step_done(stmt)), +                      err); +        } +    } + +  if (err) +    { +      /* Rollback failed, use a specific error code. */ +      err = svn_error_create(SVN_SQLITE__ERR_ROLLBACK_FAILED, err, +                             _("SQLite transaction rollback failed")); +    } + +  return svn_error_compose_create(error_to_wrap, err); +} +  svn_error_t *  svn_sqlite__begin_transaction(svn_sqlite__db_t *db)  { @@ -1303,46 +1352,37 @@ svn_sqlite__finish_transaction(svn_sqlite__db_t *db,    /* Commit or rollback the sqlite transaction. */    if (err)      { -      svn_error_t *err2; - -      err2 = get_internal_statement(&stmt, db, -                                    STMT_INTERNAL_ROLLBACK_TRANSACTION); -      if (!err2) -        err2 = svn_sqlite__step_done(stmt); - -      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY) -        { -          /* ### Houston, we have a problem! - -             We are trying to rollback but we can't because some -             statements are still busy. This leaves the database -             unusable for future transactions as the current transaction -             is still open. - -             As we are returning the actual error as the most relevant -             error in the chain, our caller might assume that it can -             retry/compensate on this error (e.g. SVN_WC_LOCKED), while -             in fact the SQLite database is unusable until the statements -             started within this transaction are reset and the transaction -             aborted. - -             We try to compensate by resetting all prepared but unreset -             statements; but we leave the busy error in the chain anyway to -             help diagnosing the original error and help in finding where -             a reset statement is missing. */ - -          err2 = reset_all_statements(db, err2); -          err2 = svn_error_compose_create( -                      svn_sqlite__step_done(stmt), -                      err2); -        } - -      return svn_error_compose_create(err, -                                      err2); +      return svn_error_trace(rollback_transaction(db, err)); +    } +  else +    { +      err = get_internal_statement(&stmt, db, +                                   STMT_INTERNAL_COMMIT_TRANSACTION); +      if (!err) +        err = svn_error_trace(svn_sqlite__step_done(stmt)); + +      /* Need to rollback if the commit fails as well, because otherwise the +         db connection will be left in an unusable state. + +         One important case to keep in mind is trying to COMMIT with concurrent +         readers. In case the commit fails, because someone else is holding a +         shared lock, sqlite keeps the transaction, and *also* keeps the file +         locks on the database. While the first part only prevents from using +         this connection, the second part prevents everyone else from accessing +         the database while the connection is open. + +         See https://www.sqlite.org/lang_transaction.html + +         COMMIT might also result in an SQLITE_BUSY return code if an another +         thread or process has a shared lock on the database that prevented +         the database from being updated. When COMMIT fails in this way, the +         transaction remains active and the COMMIT can be retried later after +         the reader has had a chance to clear. */ +      if (err) +        return svn_error_trace(rollback_transaction(db, err));      } -  SVN_ERR(get_internal_statement(&stmt, db, STMT_INTERNAL_COMMIT_TRANSACTION)); -  return svn_error_trace(svn_sqlite__step_done(stmt)); +  return SVN_NO_ERROR;  }  svn_error_t * @@ -1359,18 +1399,22 @@ svn_sqlite__finish_savepoint(svn_sqlite__db_t *db,                                      STMT_INTERNAL_ROLLBACK_TO_SAVEPOINT_SVN);        if (!err2) -        err2 = svn_sqlite__step_done(stmt); - -      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)          { -          /* Ok, we have a major problem. Some statement is still open, which -             makes it impossible to release this savepoint. +          err2 = svn_error_trace(svn_sqlite__step_done(stmt)); + +          if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY) +            { +              /* Ok, we have a major problem. Some statement is still open, +                 which makes it impossible to release this savepoint. -             ### See huge comment in svn_sqlite__finish_transaction for -                 further details */ +                 ### See huge comment in svn_sqlite__finish_transaction for +                     further details */ -          err2 = reset_all_statements(db, err2); -          err2 = svn_error_compose_create(svn_sqlite__step_done(stmt), err2); +              err2 = svn_error_trace(reset_all_statements(db, err2)); +              err2 = svn_error_compose_create( +                          svn_error_trace(svn_sqlite__step_done(stmt)), +                          err2); +            }          }        err = svn_error_compose_create(err, err2); @@ -1378,9 +1422,9 @@ svn_sqlite__finish_savepoint(svn_sqlite__db_t *db,                                      STMT_INTERNAL_RELEASE_SAVEPOINT_SVN);        if (!err2) -        err2 = svn_sqlite__step_done(stmt); +        err2 = svn_error_trace(svn_sqlite__step_done(stmt)); -      return svn_error_trace(svn_error_compose_create(err, err2)); +      return svn_error_compose_create(err, err2);      }    SVN_ERR(get_internal_statement(&stmt, db, diff --git a/subversion/libsvn_subr/sysinfo.c b/subversion/libsvn_subr/sysinfo.c index 067867224153..4ac923c0551b 100644 --- a/subversion/libsvn_subr/sysinfo.c +++ b/subversion/libsvn_subr/sysinfo.c @@ -1143,6 +1143,8 @@ release_name_from_version(const char *osver)      case  8: return "Mountain Lion";      case  9: return "Mavericks";      case 10: return "Yosemite"; +    case 11: return "El Capitan"; +    case 12: return "Sierra";      }    return NULL; diff --git a/subversion/libsvn_subr/win32_crashrpt.c b/subversion/libsvn_subr/win32_crashrpt.c index 680b944b9022..1349d84c9fe2 100644 --- a/subversion/libsvn_subr/win32_crashrpt.c +++ b/subversion/libsvn_subr/win32_crashrpt.c @@ -53,9 +53,9 @@ HANDLE dbghelp_dll = INVALID_HANDLE_VALUE;  #define LOGFILE_PREFIX "svn-crash-log"  #if defined(_M_IX86) -#define FORMAT_PTR "0x%08x" +#define FORMAT_PTR "0x%08Ix"  #elif defined(_M_X64) -#define FORMAT_PTR "0x%016I64x" +#define FORMAT_PTR "0x%016Ix"  #endif  /*** Code. ***/ @@ -171,7 +171,7 @@ write_module_info_callback(void *data,        MINIDUMP_MODULE_CALLBACK module = callback_input->Module;        char *buf = convert_wbcs_to_ansi(module.FullPath); -      fprintf(log_file, FORMAT_PTR, module.BaseOfImage); +      fprintf(log_file, FORMAT_PTR, (UINT_PTR)module.BaseOfImage);        fprintf(log_file, "  %s", buf);        free(buf); @@ -260,18 +260,19 @@ write_process_info(EXCEPTION_RECORD *exception, CONTEXT *context,  #endif  } -/* Formats the value at address based on the specified basic type - * (char, int, long ...). */ +/* Writes the value at address based on the specified basic type + * (char, int, long ...) to LOG_FILE. */  static void -format_basic_type(char *buf, DWORD basic_type, DWORD64 length, void *address) +write_basic_type(FILE *log_file, DWORD basic_type, DWORD64 length, +                 void *address)  {    switch(length)      {        case 1: -        sprintf(buf, "0x%02x", (int)*(unsigned char *)address); +        fprintf(log_file, "0x%02x", (int)*(unsigned char *)address);          break;        case 2: -        sprintf(buf, "0x%04x", (int)*(unsigned short *)address); +        fprintf(log_file, "0x%04x", (int)*(unsigned short *)address);          break;        case 4:          switch(basic_type) @@ -279,38 +280,38 @@ format_basic_type(char *buf, DWORD basic_type, DWORD64 length, void *address)              case 2:  /* btChar */                {                  if (!IsBadStringPtr(*(PSTR*)address, 32)) -                  sprintf(buf, "\"%.31s\"", *(const char **)address); +                  fprintf(log_file, "\"%.31s\"", *(const char **)address);                  else -                  sprintf(buf, FORMAT_PTR, *(DWORD_PTR *)address); +                  fprintf(log_file, FORMAT_PTR, *(DWORD_PTR *)address);                }              case 6:  /* btInt */ -              sprintf(buf, "%d", *(int *)address); +              fprintf(log_file, "%d", *(int *)address);                break;              case 8:  /* btFloat */ -              sprintf(buf, "%f", *(float *)address); +              fprintf(log_file, "%f", *(float *)address);                break;              default: -              sprintf(buf, FORMAT_PTR, *(DWORD_PTR *)address); +              fprintf(log_file, FORMAT_PTR, *(DWORD_PTR *)address);                break;            }          break;        case 8:          if (basic_type == 8) /* btFloat */ -          sprintf(buf, "%lf", *(double *)address); +          fprintf(log_file, "%lf", *(double *)address);          else -          sprintf(buf, "0x%016I64X", *(unsigned __int64 *)address); +          fprintf(log_file, "0x%016I64X", *(unsigned __int64 *)address);          break;        default: -        sprintf(buf, "[unhandled type 0x%08x of length " FORMAT_PTR "]", -                     basic_type, length); +        fprintf(log_file, "[unhandled type 0x%08x of length " FORMAT_PTR "]", +                basic_type, (UINT_PTR)length);          break;      }  } -/* Formats the value at address based on the type (pointer, user defined, - * basic type). */ +/* Writes the value at address based on the type (pointer, user defined, + * basic type) to LOG_FILE. */  static void -format_value(char *value_str, DWORD64 mod_base, DWORD type, void *value_addr) +write_value(FILE *log_file, DWORD64 mod_base, DWORD type, void *value_addr)  {    DWORD tag = 0;    int ptr = 0; @@ -340,19 +341,19 @@ format_value(char *value_str, DWORD64 mod_base, DWORD type, void *value_addr)                LocalFree(type_name_wbcs);                if (ptr == 0) -                sprintf(value_str, "(%s) " FORMAT_PTR, -                        type_name, (DWORD_PTR *)value_addr); +                fprintf(log_file, "(%s) " FORMAT_PTR, +                        type_name, (UINT_PTR)(DWORD_PTR *)value_addr);                else if (ptr == 1) -                sprintf(value_str, "(%s *) " FORMAT_PTR, +                fprintf(log_file, "(%s *) " FORMAT_PTR,                          type_name, *(DWORD_PTR *)value_addr);                else -                sprintf(value_str, "(%s **) " FORMAT_PTR, +                fprintf(log_file, "(%s **) " FORMAT_PTR,                          type_name, *(DWORD_PTR *)value_addr);                free(type_name);              }            else -            sprintf(value_str, "[no symbol tag]"); +            fprintf(log_file, "[no symbol tag]");          }          break;        case 16: /* SymTagBaseType */ @@ -364,27 +365,27 @@ format_value(char *value_str, DWORD64 mod_base, DWORD type, void *value_addr)            /* print a char * as a string */            if (ptr == 1 && length == 1)              { -              sprintf(value_str, FORMAT_PTR " \"%s\"", +              fprintf(log_file, FORMAT_PTR " \"%s\"",                        *(DWORD_PTR *)value_addr, *(const char **)value_addr);              }            else if (ptr >= 1)              { -              sprintf(value_str, FORMAT_PTR, *(DWORD_PTR *)value_addr); +              fprintf(log_file, FORMAT_PTR, *(DWORD_PTR *)value_addr);              }            else if (SymGetTypeInfo_(proc, mod_base, type, TI_GET_BASETYPE, &bt))              { -              format_basic_type(value_str, bt, length, value_addr); +              write_basic_type(log_file, bt, length, value_addr);              }          }          break;        case 12: /* SymTagEnum */ -          sprintf(value_str, "%d", *(DWORD_PTR *)value_addr); +          fprintf(log_file, "%d", *(DWORD_PTR *)value_addr);            break;        case 13: /* SymTagFunctionType */ -          sprintf(value_str, FORMAT_PTR, *(DWORD_PTR *)value_addr); +          fprintf(log_file, FORMAT_PTR, *(DWORD_PTR *)value_addr);            break;        default: -          sprintf(value_str, "[unhandled tag: %d]", tag); +          fprintf(log_file, "[unhandled tag: %d]", tag);            break;      }  } @@ -408,7 +409,6 @@ write_var_values(PSYMBOL_INFO sym_info, ULONG sym_size, void *baton)    FILE *log_file   = ((symbols_baton_t*)baton)->log_file;    int nr_of_frame = ((symbols_baton_t*)baton)->nr_of_frame;    BOOL log_params = ((symbols_baton_t*)baton)->log_params; -  char value_str[256] = "";    /* get the variable's data */    if (sym_info->Flags & SYMFLAG_REGREL) @@ -422,21 +422,21 @@ write_var_values(PSYMBOL_INFO sym_info, ULONG sym_size, void *baton)    if (log_params && sym_info->Flags & SYMFLAG_PARAMETER)      {        if (last_nr_of_frame == nr_of_frame) -        fprintf(log_file, ", ", 2); +        fprintf(log_file, ", ");        else          last_nr_of_frame = nr_of_frame; -      format_value(value_str, sym_info->ModBase, sym_info->TypeIndex, -                   (void *)var_data); -      fprintf(log_file, "%.*s=%s", (int)sym_info->NameLen, sym_info->Name, -              value_str); +      fprintf(log_file, "%.*s=", (int)sym_info->NameLen, sym_info->Name); +      write_value(log_file, sym_info->ModBase, sym_info->TypeIndex, +                  (void *)var_data);      }    if (!log_params && sym_info->Flags & SYMFLAG_LOCAL)      { -      format_value(value_str, sym_info->ModBase, sym_info->TypeIndex, -                   (void *)var_data); -      fprintf(log_file, "        %.*s = %s\n", (int)sym_info->NameLen, -              sym_info->Name, value_str); +      fprintf(log_file, "        %.*s = ", (int)sym_info->NameLen, +              sym_info->Name); +      write_value(log_file, sym_info->ModBase, sym_info->TypeIndex, +                  (void *)var_data); +      fprintf(log_file, "\n");      }    return TRUE; diff --git a/subversion/libsvn_subr/xml.c b/subversion/libsvn_subr/xml.c index 7f66b4531a54..edf21aae6d30 100644 --- a/subversion/libsvn_subr/xml.c +++ b/subversion/libsvn_subr/xml.c @@ -46,6 +46,14 @@  #error Expat is unusable -- it has been compiled for wide characters  #endif +#ifndef XML_VERSION_AT_LEAST +#define XML_VERSION_AT_LEAST(major,minor,patch)                  \ +(((major) < XML_MAJOR_VERSION)                                       \ + || ((major) == XML_MAJOR_VERSION && (minor) < XML_MINOR_VERSION)    \ + || ((major) == XML_MAJOR_VERSION && (minor) == XML_MINOR_VERSION && \ +     (patch) <= XML_MICRO_VERSION)) +#endif /* XML_VERSION_AT_LEAST */ +  const char *  svn_xml__compiled_version(void)  { @@ -361,6 +369,28 @@ static void expat_data_handler(void *userData, const XML_Char *s, int len)    (*svn_parser->data_handler)(svn_parser->baton, s, (apr_size_t)len);  } +#if XML_VERSION_AT_LEAST(1, 95, 8) +static void expat_entity_declaration(void *userData, +                                     const XML_Char *entityName, +                                     int is_parameter_entity, +                                     const XML_Char *value, +                                     int value_length, +                                     const XML_Char *base, +                                     const XML_Char *systemId, +                                     const XML_Char *publicId, +                                     const XML_Char *notationName) +{ +  svn_xml_parser_t *svn_parser = userData; + +  /* Stop the parser if an entity declaration is hit. */ +  XML_StopParser(svn_parser->parser, 0 /* resumable */); +} +#else +/* A noop default_handler. */ +static void expat_default_handler(void *userData, const XML_Char *s, int len) +{ +} +#endif  /*** Making a parser. ***/ @@ -382,6 +412,12 @@ svn_xml_make_parser(void *baton,    XML_SetCharacterDataHandler(parser,                                data_handler ? expat_data_handler : NULL); +#if XML_VERSION_AT_LEAST(1, 95, 8) +  XML_SetEntityDeclHandler(parser, expat_entity_declaration); +#else +  XML_SetDefaultHandler(parser, expat_default_handler); +#endif +    /* ### we probably don't want this pool; or at least we should pass it       ### to the callbacks and clear it periodically.  */    subpool = svn_pool_create(pool); @@ -463,6 +499,9 @@ void svn_xml_signal_bailout(svn_error_t *error,    /* This will cause the current XML_Parse() call to finish quickly! */    XML_SetElementHandler(svn_parser->parser, NULL, NULL);    XML_SetCharacterDataHandler(svn_parser->parser, NULL); +#if XML_VERSION_AT_LEAST(1, 95, 8) +  XML_SetEntityDeclHandler(svn_parser->parser, NULL); +#endif    /* Once outside of XML_Parse(), the existence of this field will       cause svn_delta_parse()'s main read-loop to return error. */  | 
