Exemple #1
0
static int dav_core_is_writable(const dav_resource *resource, int propid)
{
    const dav_liveprop_spec *info;

    (void) dav_get_liveprop_info(propid, &dav_core_liveprop_group, &info);
    return info->is_writable;
}
static int
dav_rawx_is_writable(const dav_resource *resource, int propid)
{
	const dav_liveprop_spec *info;

#ifdef DAV_FS_HAS_EXECUTABLE
	/* if we have the executable property, and this isn't a collection,
	   then the property is writable. */
	if (propid == DAV_PROPID_FS_executable && !resource->collection)
		return 1;
#endif

	(void) dav_get_liveprop_info(propid, &dav_rawx_liveprop_group, &info);
	return info->is_writable;
}
Exemple #3
0
static dav_prop_insert dav_acl_insert_prop(const dav_resource *resource,
                                           int propid, dav_prop_insert what,
                                           apr_text_header *phdr)
{
    const char *value = NULL;
    const char *s = NULL;
    apr_pool_t *p = resource->pool;
    const dav_liveprop_spec *info;
    int global_ns, rc;

    if (!resource->exists)
	return DAV_PROP_INSERT_NOTDEF;

    /* ### we may want to respond to DAV_PROPID_resourcetype for PRIVATE
       ### resources. need to think on "proper" interaction with mod_dav */

    switch (propid) {
    case ACL_PROPID_acl:
	if (what == DAV_PROP_INSERT_VALUE) {
	    /* request_rec *r = resource->hooks->get_request_rec(resource) */;
	    xmlBufferPtr buf = NULL;
	    const char *pch = NULL;
	    xmlDocPtr doc;
	    xmlNodePtr node;

	    rc = dav_acl_get_acl(resource, &pch, &rc);
	    if (rc < 0)
		return DAV_PROP_INSERT_NOTDEF;

	    doc = xmlParseMemory(pch, rc);
	    node = doc && doc->children ? doc->children : NULL;

	    buf = xmlBufferCreate();
	    xmlNodeDump(buf, doc, node, 0, 1);
	    xmlFreeDoc(doc);

	    apr_text_append(p, phdr, apr_psprintf (p, "%s" DEBUG_CR,
			    buf->content));
	    /* we inserted whatever was asked for */
	    xmlBufferFree(buf);
	    return what;
	}
	break;

    case ACL_PROPID_acl_restrictions:
	value = "<D:required-principal>"
		"<D:authenticated/>"
		"<D:unauthenticated/>"
		"<D:self/>"
		"<D:all/>"
		"<D:href/>"
		"<D:property><D:owner/></D:property>"
		"<D:property><D:group/></D:property>"
		"</D:required-principal>";
	break;

    case ACL_PROPID_supported_privilege_set:
	if (what == DAV_PROP_INSERT_VALUE) {
	    xmlBufferPtr buf = NULL;

	    xmlDocPtr doc = xmlNewDoc((const xmlChar *) XML_VERSION);
	    xmlNsPtr ns;
	    xmlNodePtr cur, child, node;
	    int acl, cups;

	    dav_acl_get_aggregated(resource, &acl, &cups);

	    doc->children = xmlNewDocNode(doc, NULL,
					  (const xmlChar *) "root", NULL);
	    xmlSetNs(doc->children,
		     ns = xmlNewNs(doc->children, (const xmlChar *) "DAV:",
		     (const xmlChar *) "D"));

	    node = xmlNewChild(doc->children, ns,
				(const xmlChar *) "supported-privilege-set",
				NULL);

	    cur = add_supported(node, ns, "all", 0, "All privileges");

	    child = add_supported(cur, ns, "read", 0, "Read");

	    add_supported(acl ? child : cur, ns, "read-acl", 0, "Read ACL");

	    add_supported(cups ? child : cur, ns,
			  "read-current-user-privilege-set", 0,
			  "Read Current User");

	    child = add_supported(cur, ns, "write", 0, "Write");

	    add_supported(child, ns, "write-acl", 0, "Write ACL");
	    add_supported(child, ns, "write-content", 0, "Write content");
	    add_supported(child, ns, "write-properties", 0,
							"Write properties");

	    if (resource->collection) {
		add_supported(child, ns, "bind", 0, "Create a collection");
		add_supported(child, ns, "unbind", 0, "Remove a collection");
	    }
	    add_supported(cur, ns, "unlock", 0, "Unlock");

	    buf = xmlBufferCreate();
	    xmlNodeDump(buf, doc, node, 0, 1);
	    xmlFreeDoc(doc);

	    apr_text_append(p, phdr, apr_psprintf(p, "%s" DEBUG_CR,
							buf->content));
	    /* we inserted whatever was asked for */
	    xmlBufferFree(buf);
	    return what;
	}
	break;

    case ACL_PROPID_group_membership:
	value = dav_acl_get_group_membership(resource);
	if (value == NULL)
	    return DAV_PROP_INSERT_NOTDEF;
	break;

    case ACL_PROPID_owner:
	value = dav_acl_get_owner(resource);
	if (value == NULL)
	    return DAV_PROP_INSERT_NOTDEF;
	break;

    case ACL_PROPID_alternate_uri_set:
	value = "";  /* may be empty */
	break;

    case ACL_PROPID_inherited_acl_set:
	value = "";  /* not supported because of complexity... */
	break;

    case ACL_PROPID_current_user_privilege_set:
	value = dav_acl_get_privs(resource);
	break;

    case ACL_PROPID_principal_collection_set:
	{
	    request_rec *r = resource->hooks->get_request_rec(resource);

	    const char *pcsz = dav_acl_get_principals(r);

	    value = apr_psprintf(p, "<D:href>%s/</D:href>", pcsz ? pcsz : "");
	}
	break;

    case ACL_PROPID_current_user_principal:
	value = dav_acl_get_auth_principal(resource);
	if (value)
	    value = apr_psprintf(p, "<D:href>%s</D:href>", value);
	else
	    value = "<D:unauthenticated/>";
	break;

    default:
	/* ### what the heck was this property? */
	return DAV_PROP_INSERT_NOTDEF;
    }

    /* assert: value != NULL */

    /* get the information and global NS index for the property */
    global_ns = dav_get_liveprop_info(propid, &dav_acl_liveprop_group, &info);

    /* assert: info != NULL && info->name != NULL */

    if (what == DAV_PROP_INSERT_VALUE)
	s = apr_psprintf(p, "<lp%d:%s>%s</lp%d:%s>" DEBUG_CR,
			 global_ns, info->name, value, global_ns, info->name);
    else if (what == DAV_PROP_INSERT_NAME)
	s = apr_psprintf(p, "<lp%d:%s/>" DEBUG_CR, global_ns, info->name);
    else
	/* assert: what == DAV_PROP_INSERT_SUPPORTED */
	s = apr_psprintf(p,
			 "<D:supported-live-property D:name=\"%s\" "
			 "D:namespace=\"%s\"/>" DEBUG_CR,
			 info->name, dav_acl_namespace_uris[info->ns]);

    apr_text_append(p, phdr, s);

    /* we inserted whatever was asked for */
    return what;
}
static dav_prop_insert
insert_prop_internal(const dav_resource *resource,
                     int propid,
                     dav_prop_insert what,
                     apr_text_header *phdr,
                     apr_pool_t *scratch_pool,
                     apr_pool_t *result_pool)
{
  const char *value = NULL;
  const char *s;
  const dav_liveprop_spec *info;
  int global_ns;
  svn_error_t *serr;

  /*
  ** Almost none of the SVN provider properties are defined if the
  ** resource does not exist.  We do need to return the one VCC
  ** property and baseline-relative-path on lock-null resources,
  ** however, so that svn clients can run 'svn unlock' and 'svn info'
  ** on these things.
  **
  ** Even though we state that the SVN properties are not defined, the
  ** client cannot store dead values -- we deny that thru the is_writable
  ** hook function.
  */
  if ((! resource->exists)
      && (propid != DAV_PROPID_version_controlled_configuration)
      && (propid != SVN_PROPID_baseline_relative_path))
    return DAV_PROP_INSERT_NOTSUPP;

  /* ### we may want to respond to DAV_PROPID_resourcetype for PRIVATE
     ### resources. need to think on "proper" interaction with mod_dav */

  switch (propid)
    {
    case DAV_PROPID_getlastmodified:
    case DAV_PROPID_creationdate:
      {
        /* In subversion terms, the date attached to a file's CR is
           the true "last modified" time.  However, we're defining
           creationdate in the same way.  IMO, the "creationdate" is
           really the date attached to the revision in which the item
           *first* came into existence; this would found by tracing
           back through the log of the file -- probably via
           svn_fs_revisions_changed.  gstein, is it a bad thing that
           we're currently using 'creationdate' to mean the same thing
           as 'last modified date'?  */
        const char *datestring;
        apr_time_t timeval;
        enum time_format format;

        /* ### for now, our global VCC has no such property. */
        if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
            && (resource->info->restype == DAV_SVN_RESTYPE_VCC
                || resource->info->restype == DAV_SVN_RESTYPE_ME))
          {
            return DAV_PROP_INSERT_NOTSUPP;
          }

        if (propid == DAV_PROPID_creationdate)
          {
            /* Return an ISO8601 date; this is what the svn client
               expects, and rfc2518 demands it. */
            format = time_format_iso8601;
          }
        else /* propid == DAV_PROPID_getlastmodified */
          {
            format = time_format_rfc1123;
          }

        if (0 != get_last_modified_time(&datestring, &timeval,
                                        resource, format, scratch_pool))
          {
            return DAV_PROP_INSERT_NOTDEF;
          }

        value = apr_xml_quote_string(scratch_pool, datestring, 1);
        break;
      }

    case DAV_PROPID_creator_displayname:
      {
        svn_revnum_t committed_rev = SVN_INVALID_REVNUM;
        svn_string_t *last_author = NULL;

        /* ### for now, our global VCC has no such property. */
        if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
            && (resource->info->restype == DAV_SVN_RESTYPE_VCC
                || resource->info->restype == DAV_SVN_RESTYPE_ME))
          {
            return DAV_PROP_INSERT_NOTSUPP;
          }

        if (resource->baselined && resource->type == DAV_RESOURCE_TYPE_VERSION)
          {
            /* A baseline URI. */
            committed_rev = resource->info->root.rev;
          }
        else if (resource->type == DAV_RESOURCE_TYPE_REGULAR
                 || resource->type == DAV_RESOURCE_TYPE_WORKING
                 || resource->type == DAV_RESOURCE_TYPE_VERSION)
          {
            /* Get the CR field out of the node's skel.  Notice that the
               root object might be an ID root -or- a revision root. */
            serr = svn_fs_node_created_rev(&committed_rev,
                                           resource->info->root.root,
                                           resource->info->repos_path,
                                           scratch_pool);
            if (serr != NULL)
              {
                /* ### what to do? */
                svn_error_clear(serr);
                value = "###error###";
                break;
              }
          }
        else
          {
            return DAV_PROP_INSERT_NOTSUPP;
          }

        serr = get_path_revprop(&last_author,
                                resource,
                                committed_rev,
                                SVN_PROP_REVISION_AUTHOR,
                                scratch_pool);
        if (serr)
          {
            /* ### what to do? */
            svn_error_clear(serr);
            value = "###error###";
            break;
          }

        if (last_author == NULL)
          return DAV_PROP_INSERT_NOTDEF;

        value = apr_xml_quote_string(scratch_pool, last_author->data, 1);
        break;
      }

    case DAV_PROPID_getcontentlanguage:
      /* ### need something here */
      return DAV_PROP_INSERT_NOTSUPP;
      break;

    case DAV_PROPID_getcontentlength:
      {
        svn_filesize_t len = 0;

        /* our property, but not defined on collection resources */
        if (resource->collection || resource->baselined)
          return DAV_PROP_INSERT_NOTSUPP;

        serr = svn_fs_file_length(&len, resource->info->root.root,
                                  resource->info->repos_path, scratch_pool);
        if (serr != NULL)
          {
            svn_error_clear(serr);
            value = "0";  /* ### what to do? */
            break;
          }

        value = apr_psprintf(scratch_pool, "%" SVN_FILESIZE_T_FMT, len);
        break;
      }

    case DAV_PROPID_getcontenttype:
      {
        /* The subversion client assumes that any file without an
           svn:mime-type property is of type text/plain.  So it seems
           safe (and consistent) to assume the same on the server.  */
        svn_string_t *pval;
        const char *mime_type = NULL;

        if (resource->baselined && resource->type == DAV_RESOURCE_TYPE_VERSION)
          return DAV_PROP_INSERT_NOTSUPP;

        if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
            && (resource->info->restype == DAV_SVN_RESTYPE_VCC
                || resource->info->restype == DAV_SVN_RESTYPE_ME))
          {
            return DAV_PROP_INSERT_NOTSUPP;
          }

        if (resource->collection) /* defaults for directories */
          {
            if (resource->info->repos->xslt_uri)
              mime_type = "text/xml";
            else
              mime_type = "text/html; charset=UTF-8";
          }
        else
          {
            if ((serr = svn_fs_node_prop(&pval, resource->info->root.root,
                                         resource->info->repos_path,
                                         SVN_PROP_MIME_TYPE, scratch_pool)))
              {
                svn_error_clear(serr);
                pval = NULL;
              }

            if (pval)
              mime_type = pval->data;
            else if ((! resource->info->repos->is_svn_client)
                     && resource->info->r->content_type)
              mime_type = resource->info->r->content_type;
            else
              mime_type = "text/plain";

            if ((serr = svn_mime_type_validate(mime_type, scratch_pool)))
              {
                /* Probably serr->apr == SVN_ERR_BAD_MIME_TYPE, but
                   there's no point even checking.  No matter what the
                   error is, we can't claim to have a mime type for
                   this resource. */
                ap_log_rerror(APLOG_MARK, APLOG_WARNING, serr->apr_err, 
                              resource->info->r, "%s", serr->message);
                svn_error_clear(serr);
                return DAV_PROP_INSERT_NOTDEF;
              }
          }

        value = mime_type;
        break;
      }

    case DAV_PROPID_getetag:
      if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
          && (resource->info->restype == DAV_SVN_RESTYPE_VCC
              || resource->info->restype == DAV_SVN_RESTYPE_ME))
        {
          return DAV_PROP_INSERT_NOTSUPP;
        }

      value = dav_svn__getetag(resource, scratch_pool);
      break;

    case DAV_PROPID_auto_version:
      /* we only support one autoversioning behavior, and thus only
         return this one static value; someday when we support
         locking, there are other possible values/behaviors for this. */
      if (resource->info->repos->autoversioning)
        value = "DAV:checkout-checkin";
      else
        return DAV_PROP_INSERT_NOTDEF;
      break;

    case DAV_PROPID_baseline_collection:
      /* only defined for Baselines */
      /* ### whoops. also defined for a VCC. deal with it later. */
      if (resource->type != DAV_RESOURCE_TYPE_VERSION || !resource->baselined)
        return DAV_PROP_INSERT_NOTSUPP;
      value = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_BC,
                                 resource->info->root.rev, NULL,
                                 1 /* add_href */, scratch_pool);
      break;

    case DAV_PROPID_checked_in:
      /* only defined for VCRs (in the public space and in a BC space) */
      /* ### note that a VCC (a special VCR) is defined as _PRIVATE for now */
      if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
          && (resource->info->restype == DAV_SVN_RESTYPE_VCC
              || resource->info->restype == DAV_SVN_RESTYPE_ME))
        {
          svn_revnum_t revnum;

          serr = svn_fs_youngest_rev(&revnum, resource->info->repos->fs,
                                     scratch_pool);
          if (serr != NULL)
            {
              /* ### what to do? */
              svn_error_clear(serr);
              value = "###error###";
              break;
            }
          s = dav_svn__build_uri(resource->info->repos,
                                 DAV_SVN__BUILD_URI_BASELINE,
                                 revnum, NULL, 0 /* add_href */, scratch_pool);
          value = apr_psprintf(scratch_pool, "<D:href>%s</D:href>",
                               apr_xml_quote_string(scratch_pool, s, 1));
        }
      else if (resource->type != DAV_RESOURCE_TYPE_REGULAR)
        {
          /* not defined for this resource type */
          return DAV_PROP_INSERT_NOTSUPP;
        }
      else
        {
          svn_revnum_t rev_to_use =
            dav_svn__get_safe_cr(resource->info->root.root,
                                 resource->info->repos_path, scratch_pool);

          s = dav_svn__build_uri(resource->info->repos,
                                 DAV_SVN__BUILD_URI_VERSION,
                                 rev_to_use, resource->info->repos_path,
                                0 /* add_href */, scratch_pool);
          value = apr_psprintf(scratch_pool, "<D:href>%s</D:href>",
                               apr_xml_quote_string(scratch_pool, s, 1));
        }
      break;

    case DAV_PROPID_version_controlled_configuration:
      /* only defined for VCRs */
      /* ### VCRs within the BC should not have this property! */
      /* ### note that a VCC (a special VCR) is defined as _PRIVATE for now */
      if (resource->type != DAV_RESOURCE_TYPE_REGULAR)
        return DAV_PROP_INSERT_NOTSUPP;
      value = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_VCC,
                                 SVN_IGNORED_REVNUM, NULL,
                                 1 /* add_href */, scratch_pool);
      break;

    case DAV_PROPID_version_name:
      /* only defined for Version Resources and Baselines */
      /* ### whoops. also defined for VCRs. deal with it later. */
      if ((resource->type != DAV_RESOURCE_TYPE_VERSION)
          && (! resource->versioned))
        return DAV_PROP_INSERT_NOTSUPP;

      if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
          && (resource->info->restype == DAV_SVN_RESTYPE_VCC
              || resource->info->restype == DAV_SVN_RESTYPE_ME))
        {
          return DAV_PROP_INSERT_NOTSUPP;
        }

      if (resource->baselined)
        {
          /* just the revision number for baselines */
          value = apr_psprintf(scratch_pool, "%ld",
                               resource->info->root.rev);
        }
      else
        {
          svn_revnum_t committed_rev = SVN_INVALID_REVNUM;

          /* Get the CR field out of the node's skel.  Notice that the
             root object might be an ID root -or- a revision root. */
          serr = svn_fs_node_created_rev(&committed_rev,
                                         resource->info->root.root,
                                         resource->info->repos_path,
                                         scratch_pool);
          if (serr != NULL)
            {
              /* ### what to do? */
              svn_error_clear(serr);
              value = "###error###";
              break;
            }

          /* Convert the revision into a quoted string */
          s = apr_psprintf(scratch_pool, "%ld", committed_rev);
          value = apr_xml_quote_string(scratch_pool, s, 1);
        }
      break;

    case SVN_PROPID_baseline_relative_path:
      /* only defined for VCRs */
      /* ### VCRs within the BC should not have this property! */
      /* ### note that a VCC (a special VCR) is defined as _PRIVATE for now */
      if (resource->type != DAV_RESOURCE_TYPE_REGULAR)
        return DAV_PROP_INSERT_NOTSUPP;

      /* drop the leading slash, so it is relative */
      s = resource->info->repos_path + 1;
      value = apr_xml_quote_string(scratch_pool, s, 1);
      break;

    case SVN_PROPID_md5_checksum:
      if ((! resource->collection)
          && (! resource->baselined)
          && (resource->type == DAV_RESOURCE_TYPE_REGULAR
              || resource->type == DAV_RESOURCE_TYPE_WORKING
              || resource->type == DAV_RESOURCE_TYPE_VERSION))
        {
          svn_checksum_t *checksum;

          serr = svn_fs_file_checksum(&checksum, svn_checksum_md5,
                                      resource->info->root.root,
                                      resource->info->repos_path, TRUE,
                                      scratch_pool);
          if (serr != NULL)
            {
              /* ### what to do? */
              svn_error_clear(serr);
              value = "###error###";
              break;
            }

          value = svn_checksum_to_cstring(checksum, scratch_pool);

          if (! value)
            return DAV_PROP_INSERT_NOTSUPP;
        }
      else
        return DAV_PROP_INSERT_NOTSUPP;

      break;

    case SVN_PROPID_repository_uuid:
      serr = svn_fs_get_uuid(resource->info->repos->fs, &value, scratch_pool);
      if (serr != NULL)
        {
          /* ### what to do? */
          svn_error_clear(serr);
          value = "###error###";
          break;
        }
      break;

    case SVN_PROPID_deadprop_count:
      {
        unsigned int propcount;
        apr_hash_t *proplist;

        if (resource->type != DAV_RESOURCE_TYPE_REGULAR)
          return DAV_PROP_INSERT_NOTSUPP;

        serr = svn_fs_node_proplist(&proplist,
                                    resource->info->root.root,
                                    resource->info->repos_path, scratch_pool);
        if (serr != NULL)
          {
            /* ### what to do? */
            svn_error_clear(serr);
            value = "###error###";
            break;
          }

        propcount = apr_hash_count(proplist);
        value = apr_psprintf(scratch_pool, "%u", propcount);
        break;
      }

    default:
      /* ### what the heck was this property? */
      return DAV_PROP_INSERT_NOTDEF;
    }

  /* assert: value != NULL */

  /* get the information and global NS index for the property */
  global_ns = dav_get_liveprop_info(propid, &dav_svn__liveprop_group, &info);

  /* assert: info != NULL && info->name != NULL */

  if (what == DAV_PROP_INSERT_NAME
      || (what == DAV_PROP_INSERT_VALUE && *value == '\0')) {
    s = apr_psprintf(result_pool, "<lp%d:%s/>" DEBUG_CR, global_ns,
                     info->name);
  }
  else if (what == DAV_PROP_INSERT_VALUE) {
    s = apr_psprintf(result_pool, "<lp%d:%s>%s</lp%d:%s>" DEBUG_CR,
                     global_ns, info->name, value, global_ns, info->name);
  }
  else {
    /* assert: what == DAV_PROP_INSERT_SUPPORTED */
    s = apr_psprintf(result_pool,
                     "<D:supported-live-property D:name=\"%s\" "
                     "D:namespace=\"%s\"/>" DEBUG_CR,
                     info->name, namespace_uris[info->ns]);
  }
  apr_text_append(result_pool, phdr, s);

  /* we inserted whatever was asked for */
  return what;
}
Exemple #5
0
static dav_prop_insert dav_core_insert_prop(const dav_resource *resource,
                                            int propid, dav_prop_insert what,
                                            apr_text_header *phdr)
{
    const char *value = NULL;
    const char *s;
    apr_pool_t *p = resource->pool;
    const dav_liveprop_spec *info;
    long global_ns;

    switch (propid)
    {
    case DAV_PROPID_resourcetype:
        { /* additional type info provided by external modules ? */
            int i;

            apr_array_header_t *extensions =
                ap_list_provider_names(p, DAV_RESOURCE_TYPE_GROUP, "0");
            ap_list_provider_names_t *entry =
                (ap_list_provider_names_t *)extensions->elts;

            for (i = 0; i < extensions->nelts; i++, entry++) {
                const dav_resource_type_provider *res_hooks =
                    dav_get_resource_type_providers(entry->provider_name);
                const char *name = NULL, *uri = NULL;

                if (!res_hooks || !res_hooks->get_resource_type)
                    continue;

                if (!res_hooks->get_resource_type(resource, &name, &uri) &&
            name) {

                    if (!uri || !strcasecmp(uri, "DAV:"))
                        value = apr_pstrcat(p, value ? value : "",
                        "<D:", name, "/>", NULL);
            else
                        value = apr_pstrcat(p, value ? value : "",
                        "<x:", name,
                        " xmlns:x=\"", uri,
                        "\"/>", NULL);
                }
        }
        }
        switch (resource->type) {
        case DAV_RESOURCE_TYPE_VERSION:
            if (resource->baselined) {
                value = apr_pstrcat(p, value ? value : "", "<D:baseline/>", NULL);
                break;
            }
            /* fall through */
        case DAV_RESOURCE_TYPE_REGULAR:
        case DAV_RESOURCE_TYPE_WORKING:
            if (resource->collection) {
                value = apr_pstrcat(p, value ? value : "", "<D:collection/>", NULL);
            }
            else {
                /* ### should we denote lock-null resources? */
                if (value == NULL) {
                value = "";        /* becomes: <D:resourcetype/> */
            }
            }
            break;
        case DAV_RESOURCE_TYPE_HISTORY:
            value = apr_pstrcat(p, value ? value : "", "<D:version-history/>", NULL);
            break;
        case DAV_RESOURCE_TYPE_WORKSPACE:
            value = apr_pstrcat(p, value ? value : "", "<D:collection/>", NULL);
            break;
        case DAV_RESOURCE_TYPE_ACTIVITY:
            value = apr_pstrcat(p, value ? value : "", "<D:activity/>", NULL);
            break;

        default:
            /* ### bad juju */
            return DAV_PROP_INSERT_NOTDEF;
        }
        break;

    case DAV_PROPID_comment:
    case DAV_PROPID_creator_displayname:
    case DAV_PROPID_displayname:
    case DAV_PROPID_source:
    default:
        /*
        ** This property is known, but not defined as a liveprop. However,
        ** it may be a dead property.
        */
        return DAV_PROP_INSERT_NOTDEF;
    }

    /* assert: value != NULL */

    /* get the information and global NS index for the property */
    global_ns = dav_get_liveprop_info(propid, &dav_core_liveprop_group, &info);

    /* assert: info != NULL && info->name != NULL */

    if (what == DAV_PROP_INSERT_SUPPORTED) {
        s = apr_psprintf(p,
                         "<D:supported-live-property D:name=\"%s\" "
                         "D:namespace=\"%s\"/>" DEBUG_CR,
                         info->name, dav_core_namespace_uris[info->ns]);
    }
    else if (what == DAV_PROP_INSERT_VALUE && *value != '\0') {
        s = apr_psprintf(p, "<lp%ld:%s>%s</lp%ld:%s>" DEBUG_CR,
                         global_ns, info->name, value, global_ns, info->name);
    }
    else {
        s = apr_psprintf(p, "<lp%ld:%s/>" DEBUG_CR, global_ns, info->name);
    }
    apr_text_append(p, phdr, s);

    /* we inserted what was asked for */
    return what;
}
static dav_prop_insert
dav_rawx_insert_prop(const dav_resource *resource, int propid, dav_prop_insert what, apr_text_header *phdr)
{
	const char *value;
	const char *s;
	apr_pool_t *p = resource->info->pool;
	const dav_liveprop_spec *info;
	int global_ns;

	/* an HTTP-date can be 29 chars plus a null term */
	/* a 64-bit size can be 20 chars plus a null term */
	char buf[DAV_TIMEBUF_SIZE];

	/*
	 ** None of FS provider properties are defined if the resource does not
	 ** exist. Just bail for this case.
	 **
	 ** Even though we state that the FS properties are not defined, the
	 ** client cannot store dead values -- we deny that thru the is_writable
	 ** hook function.
	 */
	if (!resource->exists)
		return DAV_PROP_INSERT_NOTDEF;

	switch (propid) {
		case DAV_PROPID_creationdate:
			/*
			 ** Closest thing to a creation date. since we don't actually
			 ** perform the operations that would modify ctime (after we
			 ** create the file), then we should be pretty safe here.
			 */
			dav_format_time(DAV_STYLE_ISO8601,
					resource->info->finfo.ctime,
					buf);
			value = buf;
			break;

		case DAV_PROPID_getcontentlength:
			/* our property, but not defined on collection resources */
			if (resource->collection)
				return DAV_PROP_INSERT_NOTDEF;

			(void) sprintf(buf, "%" APR_OFF_T_FMT, resource->info->finfo.size);
			value = buf;
			break;

		case DAV_PROPID_getetag:
			value = dav_rawx_getetag(resource);
			break;

		case DAV_PROPID_getlastmodified:
			dav_format_time(DAV_STYLE_RFC822,
					resource->info->finfo.mtime,
					buf);
			value = buf;
			break;

		case DAV_PROPID_FS_executable:
			/* our property, but not defined on collection resources */
			if (resource->collection)
				return DAV_PROP_INSERT_NOTDEF;

			/* our property, but not defined on this platform */
			if (!(resource->info->finfo.valid & APR_FINFO_UPROT))
				return DAV_PROP_INSERT_NOTDEF;

			/* the files are "ours" so we only need to check owner exec privs */
			if (resource->info->finfo.protection & APR_UEXECUTE)
				value = "T";
			else
				value = "F";
			break;

		default:
			/* ### what the heck was this property? */
			return DAV_PROP_INSERT_NOTDEF;
	}

	/* assert: value != NULL */

	/* get the information and global NS index for the property */
	global_ns = dav_get_liveprop_info(propid, &dav_rawx_liveprop_group, &info);

	/* assert: info != NULL && info->name != NULL */

	/* DBG3("FS: inserting lp%d:%s  (local %d)", ns, scan->name, scan->ns); */

	if (what == DAV_PROP_INSERT_VALUE) {
		s = apr_psprintf(p, "<lp%d:%s>%s</lp%d:%s>" DEBUG_CR,
				global_ns, info->name, value, global_ns, info->name);
	}
	else if (what == DAV_PROP_INSERT_NAME) {
		s = apr_psprintf(p, "<lp%d:%s/>" DEBUG_CR, global_ns, info->name);
	}
	else {
		/* assert: what == DAV_PROP_INSERT_SUPPORTED */
		s = apr_psprintf(p,
				"<D:supported-live-property D:name=\"%s\" "
				"D:namespace=\"%s\"/>" DEBUG_CR,
				info->name, dav_rawx_namespace_uris[info->ns]);
	}
	apr_text_append(p, phdr, s);

	/* we inserted what was asked for */
	return what;
}