<commit_before>/*
 * deadprops.c: mod_dav_svn dead property provider functions for Subversion
 *
 * ====================================================================
 * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */




#include <httpd.h>
#include <mod_dav.h>

#include <apr_hash.h>

#include "dav_svn.h"
#include "svn_xml.h"


struct dav_db {
  const dav_resource *resource;
  apr_pool_t *p;

  /* the resource's properties that we are sequencing over */
  apr_hash_t *props;
  apr_hash_index_t *hi;

  /* used for constructing repos-local names for properties */
  svn_stringbuf_t *work;
};

struct dav_deadprop_rollback {
  dav_prop_name name;
  svn_string_t value;
};


/* retrieve the "right" string to use as a repos path */
static const char *get_repos_path (struct dav_resource_private *info)
{
  return info->node_id_str ? info->node_id_str : info->repos_path;
}


/* construct the repos-local name for the given DAV property name */
static void get_repos_propname(dav_db *db, const dav_prop_name *name,
                               char **repos_propname)
{
  if (strcmp(name->ns, SVN_PROP_PREFIX) == 0)
    {
      /* recombine the namespace ("svn:") and the name. */
      svn_stringbuf_set(db->work, SVN_PROP_PREFIX);
      svn_stringbuf_appendcstr(db->work, name->name);
      *repos_propname = db->work->data;
    }
  else if (strcmp(name->ns, SVN_PROP_CUSTOM_PREFIX) == 0)
    {
      /* the name of a custom prop is just the name -- no ns URI */
      *repos_propname = (char *)name->name;
    }
  else
    {
      *repos_propname = NULL;
    }
}

static dav_error *get_value(dav_db *db, const dav_prop_name *name,
                            svn_string_t **pvalue)
{
  char *propname;
  svn_error_t *serr;

  /* get the repos-local name */
  get_repos_propname(db, name, &propname);

  /* ### disallow arbitrary, non-SVN properties. this effectively shuts
     ### off arbitrary DeltaV clients for now. */
  if (propname == NULL)
    {
      /* we know these are not present. */
      *pvalue = NULL;
      return NULL;
    }

  /* ### if db->props exists, then try in there first */

  /* Working Baseline, Baseline, or (Working) Version resource */
  if (db->resource->baselined)
    if (db->resource->type == DAV_RESOURCE_TYPE_WORKING)
      serr = svn_fs_txn_prop(pvalue, db->resource->info->root.txn,
                             propname, db->p);
    else
      serr = svn_fs_revision_prop(pvalue, db->resource->info->repos->fs,
                                  db->resource->info->root.rev,
                                  propname, db->p);
  else
    serr = svn_fs_node_prop(pvalue, db->resource->info->root.root,
                            get_repos_path(db->resource->info),
                            propname, db->p);
  if (serr != NULL)
    return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                               "could not fetch a property");

  return NULL;
}

static dav_error *save_value(dav_db *db, const dav_prop_name *name,
                             const svn_string_t *value)
{
  char *propname;
  svn_error_t *serr;

  /* get the repos-local name */
  get_repos_propname(db, name, &propname);

  /* ### disallow arbitrary, non-SVN properties. this effectively shuts
     ### off arbitrary DeltaV clients for now. */
  if (propname == NULL)
    return dav_new_error(db->p, HTTP_CONFLICT, 0,
                         "Properties may only be defined in the "
                         SVN_PROP_PREFIX " and " SVN_PROP_CUSTOM_PREFIX
                         " namespaces.");

  /* Working Baseline or Working (Version) Resource */
  if (db->resource->baselined)
    serr = svn_fs_change_txn_prop(db->resource->info->root.txn,
                                  propname, value, db->resource->pool);
  else
    serr = svn_fs_change_node_prop(db->resource->info->root.root,
                                   get_repos_path(db->resource->info),
                                   propname, value, db->resource->pool);
  if (serr != NULL)
    return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                               "could not change a property");

  /* a change to the props was made; make sure our cached copy is gone */
  db->props = NULL;

  return NULL;
}

static dav_error *dav_svn_db_open(apr_pool_t *p, const dav_resource *resource,
                                  int ro, dav_db **pdb)
{
  dav_db *db;

  /* Some resource types do not have deadprop databases. Specifically:
     REGULAR, VERSION, and WORKING resources have them. (SVN does not
     have WORKSPACE resources, and isn't covered here) */
  if (resource->type == DAV_RESOURCE_TYPE_HISTORY
      || resource->type == DAV_RESOURCE_TYPE_ACTIVITY
      || resource->type == DAV_RESOURCE_TYPE_PRIVATE)
    {
      *pdb = NULL;
      return NULL;
    }

  /* If the DB is being opened R/W, and this isn't a working resource, then
     we have a problem! */
  if (!ro && resource->type != DAV_RESOURCE_TYPE_WORKING)
    {
      return dav_new_error(p, HTTP_CONFLICT, 0,
                           "Properties may only be changed on working "
                           "resources.");
    }

  db = apr_pcalloc(p, sizeof(*db));

  db->resource = resource;
  db->p = p;

  /* ### temp hack */
  db->work = svn_stringbuf_ncreate("", 0, p);

  /* ### use RO and node's mutable status to look for an error? */

  *pdb = db;

  return NULL;
}

static void dav_svn_db_close(dav_db *db)
{
  /* nothing to do */
}

static dav_error *dav_svn_db_define_namespaces(dav_db *db, dav_xmlns_info *xi)
{
  dav_xmlns_add(xi, "S", SVN_PROP_PREFIX);
  dav_xmlns_add(xi, "C", SVN_PROP_CUSTOM_PREFIX);

  /* ### we don't have any other possible namespaces right now. */

  return NULL;
}

static dav_error *dav_svn_db_output_value(dav_db *db,
                                          const dav_prop_name *name,
                                          dav_xmlns_info *xi,
                                          apr_text_header *phdr, int *found)
{
  svn_string_t *propval;
  svn_stringbuf_t *xmlsafe = NULL;
  const char *prefix;
  const char *s;
  dav_error *err;

  if ((err = get_value(db, name, &propval)) != NULL)
    return err;

  /* return whether the prop was found, then punt or handle it. */
  *found = propval != NULL;
  if (propval == NULL)
    return NULL;

  /* XML-escape our properties before sending them across the wire. */
  svn_xml_escape_string(&xmlsafe, propval, db->p);

  if (strcmp(name->ns, SVN_PROP_CUSTOM_PREFIX) == 0)
    prefix = "C:";
  else
    prefix = "S:";

  if (xmlsafe->len == 0)
    {
      /* empty value. add an empty elem. */
      s = apr_psprintf(db->p, "<%s%s/>" DEBUG_CR, prefix, name->name);
      apr_text_append(db->p, phdr, s);
    }
  else
    {
      /* add <prefix:name>value</prefix:name> */

      s = apr_psprintf(db->p, "<%s%s>" DEBUG_CR, prefix, name->name);
      apr_text_append(db->p, phdr, s);

      /* the value is in our pool which means it has the right lifetime. */
      /* ### at least, per the current mod_dav architecture/API */
      /* ### oops. apr_text is not binary-safe */
      apr_text_append(db->p, phdr, xmlsafe->data);

      s = apr_psprintf(db->p, "</%s%s>" DEBUG_CR, prefix, name->name);
      apr_text_append(db->p, phdr, s);
    }

  return NULL;
}

static dav_error *dav_svn_db_map_namespaces(
    dav_db *db,
    const apr_array_header_t *namespaces,
    dav_namespace_map **mapping)
{
  /* we don't need a namespace mapping right now. nothing to do */

  return NULL;
}

static dav_error *dav_svn_db_store(dav_db *db, const dav_prop_name *name,<commit_msg>Fix proptest.py test 3 failing over ra_dav.<commit_after>/*
 * deadprops.c: mod_dav_svn dead property provider functions for Subversion
 *
 * ====================================================================
 * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */




#include <httpd.h>
#include <mod_dav.h>

#include <apr_hash.h>

#include "dav_svn.h"
#include "svn_xml.h"


struct dav_db {
  const dav_resource *resource;
  apr_pool_t *p;

  /* the resource's properties that we are sequencing over */
  apr_hash_t *props;
  apr_hash_index_t *hi;

  /* used for constructing repos-local names for properties */
  svn_stringbuf_t *work;
};

struct dav_deadprop_rollback {
  dav_prop_name name;
  svn_string_t value;
};


/* retrieve the "right" string to use as a repos path */
static const char *get_repos_path (struct dav_resource_private *info)
{
  return info->node_id_str ? info->node_id_str : info->repos_path;
}


/* construct the repos-local name for the given DAV property name */
static void get_repos_propname(dav_db *db, const dav_prop_name *name,
                               char **repos_propname)
{
  if (strcmp(name->ns, SVN_PROP_PREFIX) == 0)
    {
      /* recombine the namespace ("svn:") and the name. */
      svn_stringbuf_set(db->work, SVN_PROP_PREFIX);
      svn_stringbuf_appendcstr(db->work, name->name);
      *repos_propname = db->work->data;
    }
  else if (strcmp(name->ns, SVN_PROP_CUSTOM_PREFIX) == 0)
    {
      /* the name of a custom prop is just the name -- no ns URI */
      *repos_propname = (char *)name->name;
    }
  else
    {
      *repos_propname = NULL;
    }
}

static dav_error *get_value(dav_db *db, const dav_prop_name *name,
                            svn_string_t **pvalue)
{
  char *propname;
  svn_error_t *serr;

  /* get the repos-local name */
  get_repos_propname(db, name, &propname);

  /* ### disallow arbitrary, non-SVN properties. this effectively shuts
     ### off arbitrary DeltaV clients for now. */
  if (propname == NULL)
    {
      /* we know these are not present. */
      *pvalue = NULL;
      return NULL;
    }

  /* ### if db->props exists, then try in there first */

  /* Working Baseline, Baseline, or (Working) Version resource */
  if (db->resource->baselined)
    if (db->resource->type == DAV_RESOURCE_TYPE_WORKING)
      serr = svn_fs_txn_prop(pvalue, db->resource->info->root.txn,
                             propname, db->p);
    else
      serr = svn_fs_revision_prop(pvalue, db->resource->info->repos->fs,
                                  db->resource->info->root.rev,
                                  propname, db->p);
  else
    serr = svn_fs_node_prop(pvalue, db->resource->info->root.root,
                            get_repos_path(db->resource->info),
                            propname, db->p);
  if (serr != NULL)
    return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                               "could not fetch a property");

  return NULL;
}

static dav_error *save_value(dav_db *db, const dav_prop_name *name,
                             const svn_string_t *value)
{
  char *propname;
  svn_error_t *serr;

  /* get the repos-local name */
  get_repos_propname(db, name, &propname);

  /* ### disallow arbitrary, non-SVN properties. this effectively shuts
     ### off arbitrary DeltaV clients for now. */
  if (propname == NULL)
    return dav_new_error(db->p, HTTP_CONFLICT, 0,
                         "Properties may only be defined in the "
                         SVN_PROP_PREFIX " and " SVN_PROP_CUSTOM_PREFIX
                         " namespaces.");

  /* Working Baseline or Working (Version) Resource */
  if (db->resource->baselined)
    serr = svn_fs_change_txn_prop(db->resource->info->root.txn,
                                  propname, value, db->resource->pool);
  else
    serr = svn_fs_change_node_prop(db->resource->info->root.root,
                                   get_repos_path(db->resource->info),
                                   propname, value, db->resource->pool);
  if (serr != NULL)
    return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                               "could not change a property");

  /* a change to the props was made; make sure our cached copy is gone */
  db->props = NULL;

  return NULL;
}

static dav_error *dav_svn_db_open(apr_pool_t *p, const dav_resource *resource,
                                  int ro, dav_db **pdb)
{
  dav_db *db;

  /* Some resource types do not have deadprop databases. Specifically:
     REGULAR, VERSION, and WORKING resources have them. (SVN does not
     have WORKSPACE resources, and isn't covered here) */
  if (resource->type == DAV_RESOURCE_TYPE_HISTORY
      || resource->type == DAV_RESOURCE_TYPE_ACTIVITY
      || resource->type == DAV_RESOURCE_TYPE_PRIVATE)
    {
      *pdb = NULL;
      return NULL;
    }

  /* If the DB is being opened R/W, and this isn't a working resource, then
     we have a problem! */
  if (!ro && resource->type != DAV_RESOURCE_TYPE_WORKING)
    {
      return dav_new_error(p, HTTP_CONFLICT, 0,
                           "Properties may only be changed on working "
                           "resources.");
    }

  db = apr_pcalloc(p, sizeof(*db));

  db->resource = resource;
  db->p = p;

  /* ### temp hack */
  db->work = svn_stringbuf_ncreate("", 0, p);

  /* ### use RO and node's mutable status to look for an error? */

  *pdb = db;

  return NULL;
}

static void dav_svn_db_close(dav_db *db)
{
  /* nothing to do */
}

static dav_error *dav_svn_db_define_namespaces(dav_db *db, dav_xmlns_info *xi)
{
  dav_xmlns_add(xi, "S", SVN_PROP_PREFIX);
  dav_xmlns_add(xi, "C", SVN_PROP_CUSTOM_PREFIX);

  /* ### we don't have any other possible namespaces right now. */

  return NULL;
}

static dav_error *dav_svn_db_output_value(dav_db *db,
                                          const dav_prop_name *name,
                                          dav_xmlns_info *xi,
                                          apr_text_header *phdr, int *found)
{
  svn_string_t *propval;
  svn_stringbuf_t *xmlsafe = NULL;
  const char *prefix;
  const char *s;
  dav_error *err;

  if ((err = get_value(db, name, &propval)) != NULL)
    return err;

  /* return whether the prop was found, then punt or handle it. */
  *found = propval != NULL;
  if (propval == NULL)
    return NULL;

  /* XML-escape our properties before sending them across the wire. */
  svn_xml_escape_string(&xmlsafe, propval, db->p);

  if (strcmp(name->ns, SVN_PROP_CUSTOM_PREFIX) == 0)
    prefix = "C:";
  else
    prefix = "S:";

  if (xmlsafe->len == 0)
    {
      /* empty value. add an empty elem. */
      s = apr_psprintf(db->p, "<%s%s/>" DEBUG_CR, prefix, name->name);
      apr_text_append(db->p, phdr, s);
    }
  else
    {
      /* add <prefix:name>value</prefix:name> */

      s = apr_psprintf(db->p, "<%s%s>", prefix, name->name);
      apr_text_append(db->p, phdr, s);

      /* the value is in our pool which means it has the right lifetime. */
      /* ### at least, per the current mod_dav architecture/API */
      /* ### oops. apr_text is not binary-safe */
      apr_text_append(db->p, phdr, xmlsafe->data);

      s = apr_psprintf(db->p, "</%s%s>" DEBUG_CR, prefix, name->name);
      apr_text_append(db->p, phdr, s);
    }

  return NULL;
}

static dav_error *dav_svn_db_map_namespaces(
    dav_db *db,
    const apr_array_header_t *namespaces,
    dav_namespace_map **mapping)
{
  /* we don't need a namespace mapping right now. nothing to do */

  return NULL;
}

static dav_error *dav_svn_db_store(dav_db *db, const dav_prop_name *name,
{'fraction_non_alphanumeric': 0.1289417505336993, 'fraction_numerical': 0.0020128087831655993, 'mean_word_length': 2.5094178082191783, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 161, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 20}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3085395', 'n_tokens_mistral': 5455, 'n_tokens_neox': 5248, 'n_words': 1452}