dav_error *
dav_svn__get_locks_report(const dav_resource *resource,
                          const apr_xml_doc *doc,
                          ap_filter_t *output)
{
  apr_bucket_brigade *bb;
  svn_error_t *err;
  dav_error *derr = NULL;
  apr_status_t apr_err;
  apr_hash_t *locks;
  dav_svn__authz_read_baton arb;
  svn_depth_t depth = svn_depth_unknown;
  apr_xml_attr *this_attr;

  /* The request URI should be a public one representing an fs path. */
  if ((! resource->info->repos_path)
      || (! resource->info->repos->repos))
    return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0,
                              "get-locks-report run on resource which doesn't "
                              "represent a path within a repository.");

  arb.r = resource->info->r;
  arb.repos = resource->info->repos;

  /* See if the client provided additional information for this request. */
  for (this_attr = doc->root->attr; this_attr; this_attr = this_attr->next)
    {
      if (strcmp(this_attr->name, "depth") == 0)
        {
          depth = svn_depth_from_word(this_attr->value);
          if ((depth != svn_depth_empty) &&
              (depth != svn_depth_files) &&
              (depth != svn_depth_immediates) &&
              (depth != svn_depth_infinity))
            return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0,
                                      "Invalid 'depth' specified in "
                                      "get-locks-report request.");
          continue;
        }
    }

  /* For compatibility, our default depth is infinity. */
  if (depth == svn_depth_unknown)
    depth = svn_depth_infinity;

  /* Fetch the locks, but allow authz_read checks to happen on each. */
  if ((err = svn_repos_fs_get_locks2(&locks,
                                     resource->info->repos->repos,
                                     resource->info->repos_path, depth,
                                     dav_svn__authz_read_func(&arb), &arb,
                                     resource->pool)) != SVN_NO_ERROR)
    return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR,
                                err->message, resource->pool);

  bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);

  if ((apr_err = send_get_lock_response(locks, output, bb, resource->pool)))
    derr = dav_svn__convert_err(svn_error_create(apr_err, 0, NULL),
                                HTTP_INTERNAL_SERVER_ERROR,
                                "Error writing REPORT response.",
                                resource->pool);

  return dav_svn__final_flush_or_error(resource->info->r, bb, output,
                                       derr, resource->pool);
}
Example #2
0
svn_error_t *
svn_client__handle_externals(apr_hash_t *externals_new,
                             apr_hash_t *ambient_depths,
                             const char *repos_root_url,
                             const char *target_abspath,
                             svn_depth_t requested_depth,
                             svn_boolean_t *timestamp_sleep,
                             svn_client_ctx_t *ctx,
                             apr_pool_t *scratch_pool)
{
  apr_hash_t *old_external_defs;
  apr_hash_index_t *hi;
  apr_pool_t *iterpool;

  SVN_ERR_ASSERT(repos_root_url);

  iterpool = svn_pool_create(scratch_pool);

  SVN_ERR(svn_wc__externals_defined_below(&old_external_defs,
                                          ctx->wc_ctx, target_abspath,
                                          scratch_pool, iterpool));

  for (hi = apr_hash_first(scratch_pool, externals_new);
       hi;
       hi = apr_hash_next(hi))
    {
      const char *local_abspath = svn__apr_hash_index_key(hi);
      const char *desc_text = svn__apr_hash_index_val(hi);
      svn_depth_t ambient_depth = svn_depth_infinity;

      svn_pool_clear(iterpool);

      if (ambient_depths)
        {
          const char *ambient_depth_w;

          ambient_depth_w = apr_hash_get(ambient_depths, local_abspath,
                                         svn__apr_hash_index_klen(hi));

          if (ambient_depth_w == NULL)
            {
              return svn_error_createf(
                        SVN_ERR_WC_CORRUPT, NULL,
                        _("Traversal of '%s' found no ambient depth"),
                        svn_dirent_local_style(local_abspath, scratch_pool));
            }
          else
            {
              ambient_depth = svn_depth_from_word(ambient_depth_w);
            }
        }

      SVN_ERR(handle_externals_change(ctx, repos_root_url, timestamp_sleep,
                                      local_abspath,
                                      desc_text, old_external_defs,
                                      ambient_depth, requested_depth,
                                      iterpool));
    }

  /* Remove the remaining externals */
  for (hi = apr_hash_first(scratch_pool, old_external_defs);
       hi;
       hi = apr_hash_next(hi))
    {
      const char *item_abspath = svn__apr_hash_index_key(hi);
      const char *defining_abspath = svn__apr_hash_index_val(hi);
      const char *parent_abspath;

      svn_pool_clear(iterpool);

      SVN_ERR(wrap_external_error(
                          ctx, item_abspath,
                          handle_external_item_removal(ctx, defining_abspath,
                                                       item_abspath, iterpool),
                          iterpool));

      /* Are there any unversioned directories between the removed
       * external and the DEFINING_ABSPATH which we can remove? */
      parent_abspath = item_abspath;
      do {
        svn_node_kind_t kind;

        parent_abspath = svn_dirent_dirname(parent_abspath, iterpool);
        SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, parent_abspath,
                                  FALSE /* show_deleted*/,
                                  FALSE /* show_hidden */,
                                  iterpool));
        if (kind == svn_node_none)
          {
            svn_error_t *err;

            err = svn_io_dir_remove_nonrecursive(parent_abspath, iterpool);
            if (err)
              {
                if (APR_STATUS_IS_ENOTEMPTY(err->apr_err))
                  {
                    svn_error_clear(err);
                    break; /* No parents to delete */
                  }
                else if (APR_STATUS_IS_ENOENT(err->apr_err)
                         || APR_STATUS_IS_ENOTDIR(err->apr_err))
                  {
                    svn_error_clear(err);
                    /* Fall through; parent dir might be unversioned */
                  }
                else
                  return svn_error_trace(err);
              }
          }
      } while (strcmp(parent_abspath, defining_abspath) != 0);
    }


  svn_pool_destroy(iterpool);
  return SVN_NO_ERROR;
}
Example #3
0
/* Allocate an entry from POOL and read it from [*BUF, END).  The
   buffer may be modified in place while parsing.  Return the new
   entry in *NEW_ENTRY.  Advance *BUF to point at the end of the entry
   record.
   The entries file format should be provided in ENTRIES_FORMAT. */
static svn_error_t *
read_entry(svn_wc_entry_t **new_entry,
           char **buf, const char *end,
           int entries_format,
           apr_pool_t *pool)
{
    svn_wc_entry_t *entry = alloc_entry(pool);
    const char *name;

#define MAYBE_DONE if (**buf == '\f') goto done

    /* Find the name and set up the entry under that name. */
    SVN_ERR(read_path(&name, buf, end, pool));
    entry->name = name ? name : SVN_WC_ENTRY_THIS_DIR;

    /* Set up kind. */
    {
        const char *kindstr;
        SVN_ERR(read_val(&kindstr, buf, end));
        if (kindstr)
        {
            if (strcmp(kindstr, ENTRIES_VALUE_FILE) == 0)
                entry->kind = svn_node_file;
            else if (strcmp(kindstr, ENTRIES_VALUE_DIR) == 0)
                entry->kind = svn_node_dir;
            else
                return svn_error_createf
                       (SVN_ERR_NODE_UNKNOWN_KIND, NULL,
                        _("Entry '%s' has invalid node kind"),
                        (name ? name : SVN_WC_ENTRY_THIS_DIR));
        }
        else
            entry->kind = svn_node_none;
    }
    MAYBE_DONE;

    /* Attempt to set revision (resolve_to_defaults may do it later, too) */
    SVN_ERR(read_revnum(&entry->revision, buf, end, pool));
    MAYBE_DONE;

    /* Attempt to set up url path (again, see resolve_to_defaults). */
    SVN_ERR(read_url(&entry->url, buf, end, entries_format, pool));
    MAYBE_DONE;

    /* Set up repository root.  Make sure it is a prefix of url. */
    SVN_ERR(read_url(&entry->repos, buf, end, entries_format, pool));
    if (entry->repos && entry->url
            && ! svn_uri__is_ancestor(entry->repos, entry->url))
        return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
                                 _("Entry for '%s' has invalid repository "
                                   "root"),
                                 name ? name : SVN_WC_ENTRY_THIS_DIR);
    MAYBE_DONE;

    /* Look for a schedule attribute on this entry. */
    {
        const char *schedulestr;
        SVN_ERR(read_val(&schedulestr, buf, end));
        entry->schedule = svn_wc_schedule_normal;
        if (schedulestr)
        {
            if (strcmp(schedulestr, ENTRIES_VALUE_ADD) == 0)
                entry->schedule = svn_wc_schedule_add;
            else if (strcmp(schedulestr, ENTRIES_VALUE_DELETE) == 0)
                entry->schedule = svn_wc_schedule_delete;
            else if (strcmp(schedulestr, ENTRIES_VALUE_REPLACE) == 0)
                entry->schedule = svn_wc_schedule_replace;
            else
                return svn_error_createf(
                           SVN_ERR_ENTRY_ATTRIBUTE_INVALID, NULL,
                           _("Entry '%s' has invalid 'schedule' value"),
                           name ? name : SVN_WC_ENTRY_THIS_DIR);
        }
    }
    MAYBE_DONE;

    /* Attempt to set up text timestamp. */
    SVN_ERR(read_time(&entry->text_time, buf, end, pool));
    MAYBE_DONE;

    /* Checksum. */
    SVN_ERR(read_str(&entry->checksum, buf, end, pool));
    MAYBE_DONE;

    /* Setup last-committed values. */
    SVN_ERR(read_time(&entry->cmt_date, buf, end, pool));
    MAYBE_DONE;

    SVN_ERR(read_revnum(&entry->cmt_rev, buf, end, pool));
    MAYBE_DONE;

    SVN_ERR(read_str(&entry->cmt_author, buf, end, pool));
    MAYBE_DONE;

    /* has-props, has-prop-mods, cachable-props, present-props are all
       deprecated. Read any values that may be in the 'entries' file, but
       discard them, and just put default values into the entry. */
    {
        const char *unused_value;

        /* has-props flag. */
        SVN_ERR(read_val(&unused_value, buf, end));
        entry->has_props = FALSE;
        MAYBE_DONE;

        /* has-prop-mods flag. */
        SVN_ERR(read_val(&unused_value, buf, end));
        entry->has_prop_mods = FALSE;
        MAYBE_DONE;

        /* Use the empty string for cachable_props, indicating that we no
           longer attempt to cache any properties. An empty string for
           present_props means that no cachable props are present. */

        /* cachable-props string. */
        SVN_ERR(read_val(&unused_value, buf, end));
        entry->cachable_props = "";
        MAYBE_DONE;

        /* present-props string. */
        SVN_ERR(read_val(&unused_value, buf, end));
        entry->present_props = "";
        MAYBE_DONE;
    }

    /* Is this entry in a state of mental torment (conflict)? */
    {
        SVN_ERR(read_path(&entry->prejfile, buf, end, pool));
        MAYBE_DONE;
        SVN_ERR(read_path(&entry->conflict_old, buf, end, pool));
        MAYBE_DONE;
        SVN_ERR(read_path(&entry->conflict_new, buf, end, pool));
        MAYBE_DONE;
        SVN_ERR(read_path(&entry->conflict_wrk, buf, end, pool));
        MAYBE_DONE;
    }

    /* Is this entry copied? */
    SVN_ERR(read_bool(&entry->copied, ENTRIES_BOOL_COPIED, buf, end));
    MAYBE_DONE;

    SVN_ERR(read_url(&entry->copyfrom_url, buf, end, entries_format, pool));
    MAYBE_DONE;
    SVN_ERR(read_revnum(&entry->copyfrom_rev, buf, end, pool));
    MAYBE_DONE;

    /* Is this entry deleted? */
    SVN_ERR(read_bool(&entry->deleted, ENTRIES_BOOL_DELETED, buf, end));
    MAYBE_DONE;

    /* Is this entry absent? */
    SVN_ERR(read_bool(&entry->absent, ENTRIES_BOOL_ABSENT, buf, end));
    MAYBE_DONE;

    /* Is this entry incomplete? */
    SVN_ERR(read_bool(&entry->incomplete, ENTRIES_BOOL_INCOMPLETE, buf, end));
    MAYBE_DONE;

    /* UUID. */
    SVN_ERR(read_str(&entry->uuid, buf, end, pool));
    MAYBE_DONE;

    /* Lock token. */
    SVN_ERR(read_str(&entry->lock_token, buf, end, pool));
    MAYBE_DONE;

    /* Lock owner. */
    SVN_ERR(read_str(&entry->lock_owner, buf, end, pool));
    MAYBE_DONE;

    /* Lock comment. */
    SVN_ERR(read_str(&entry->lock_comment, buf, end, pool));
    MAYBE_DONE;

    /* Lock creation date. */
    SVN_ERR(read_time(&entry->lock_creation_date, buf, end, pool));
    MAYBE_DONE;

    /* Changelist. */
    SVN_ERR(read_str(&entry->changelist, buf, end, pool));
    MAYBE_DONE;

    /* Keep entry in working copy after deletion? */
    SVN_ERR(read_bool(&entry->keep_local, ENTRIES_BOOL_KEEP_LOCAL, buf, end));
    MAYBE_DONE;

    /* Translated size */
    {
        const char *val;

        /* read_val() returns NULL on an empty (e.g. default) entry line,
           and entry has already been initialized accordingly already */
        SVN_ERR(read_val(&val, buf, end));
        if (val)
            entry->working_size = (apr_off_t)apr_strtoi64(val, NULL, 0);
    }
    MAYBE_DONE;

    /* Depth. */
    {
        const char *result;
        SVN_ERR(read_val(&result, buf, end));
        if (result)
        {
            svn_boolean_t invalid;
            svn_boolean_t is_this_dir;

            entry->depth = svn_depth_from_word(result);

            /* Verify the depth value:
               THIS_DIR should not have an excluded value and SUB_DIR should only
               have excluded value. Remember that infinity value is not stored and
               should not show up here. Otherwise, something bad may have
               happened. However, infinity value itself will always be okay. */
            is_this_dir = !name;
            /* '!=': XOR */
            invalid = is_this_dir != (entry->depth != svn_depth_exclude);
            if (entry->depth != svn_depth_infinity && invalid)
                return svn_error_createf(
                           SVN_ERR_ENTRY_ATTRIBUTE_INVALID, NULL,
                           _("Entry '%s' has invalid 'depth' value"),
                           name ? name : SVN_WC_ENTRY_THIS_DIR);
        }
        else
            entry->depth = svn_depth_infinity;

    }
    MAYBE_DONE;

    /* Tree conflict data. */
    SVN_ERR(read_str(&entry->tree_conflict_data, buf, end, pool));
    MAYBE_DONE;

    /* File external URL and revision. */
    {
        const char *str;
        SVN_ERR(read_str(&str, buf, end, pool));
        SVN_ERR(svn_wc__unserialize_file_external(&entry->file_external_path,
                &entry->file_external_peg_rev,
                &entry->file_external_rev,
                str,
                pool));
    }
    MAYBE_DONE;

done:
    *new_entry = entry;
    return SVN_NO_ERROR;
}