/* pull this in from the other source file */
extern const dav_hooks_locks dav_hooks_locks_fs;
-/* forward-declare this sucker */
+/* forward-declare the hook structures */
static const dav_hooks_repository dav_hooks_repository_fs;
+static const dav_hooks_liveprop dav_hooks_liveprop_fs;
/*
** The namespace URIs that we use. This list and the enumeration must
};
/*
-** The properties that we define.
+** The single property that we define (in the DAV_FS_URI_MYPROPS namespace)
*/
-enum {
- /* using DAV_FS_URI_DAV */
- DAV_PROPID_FS_creationdate = DAV_PROPID_FS,
- DAV_PROPID_FS_displayname,
- DAV_PROPID_FS_getcontentlength,
- DAV_PROPID_FS_getetag,
- DAV_PROPID_FS_getlastmodified,
- DAV_PROPID_FS_source,
-
- /* using DAV_FS_URI_MYPROPS */
- DAV_PROPID_FS_executable
-};
-/* NOTE: the magic "200" is derived from the ranges in mod_dav.h */
-#define DAV_PROPID_FS_OURS(id) (DAV_PROPID_FS <= (id) && \
- (id) < DAV_PROPID_FS + 200)
-
-typedef struct {
- int ns;
- const char * name;
-
- int propid;
-} dav_fs_liveprop_name;
+#define DAV_PROPID_FS_executable 1
-static const dav_fs_liveprop_name dav_fs_props[] =
+static const dav_liveprop_spec dav_fs_props[] =
{
- { DAV_FS_URI_DAV, "creationdate", DAV_PROPID_FS_creationdate },
- { DAV_FS_URI_DAV, "getcontentlength", DAV_PROPID_FS_getcontentlength },
- { DAV_FS_URI_DAV, "getetag", DAV_PROPID_FS_getetag },
- { DAV_FS_URI_DAV, "getlastmodified", DAV_PROPID_FS_getlastmodified },
+ {
+ DAV_FS_URI_DAV,
+ "creationdate",
+ DAV_PROPID_creationdate,
+ 0
+ },
+ {
+ DAV_FS_URI_DAV,
+ "getcontentlength",
+ DAV_PROPID_getcontentlength,
+ 0
+ },
+ {
+ DAV_FS_URI_DAV,
+ "getetag",
+ DAV_PROPID_getetag,
+ 0
+ },
+ {
+ DAV_FS_URI_DAV,
+ "getlastmodified",
+ DAV_PROPID_getlastmodified,
+ 0
+ },
- { DAV_FS_URI_MYPROPS, "executable", DAV_PROPID_FS_executable },
+ {
+ DAV_FS_URI_MYPROPS,
+ "executable",
+ DAV_PROPID_FS_executable,
+ 0 /* handled special in dav_fs_is_writeable */
+ },
/* ### these aren't FS specific */
- { DAV_FS_URI_DAV, "displayname", DAV_PROPID_FS_displayname },
- { DAV_FS_URI_DAV, "source", DAV_PROPID_FS_source },
+ {
+ DAV_FS_URI_DAV,
+ "displayname",
+ DAV_PROPID_displayname,
+ 1,
+ },
+ {
+ DAV_FS_URI_DAV,
+ "source",
+ DAV_PROPID_source,
+ 1,
+ },
{ 0 } /* sentinel */
};
+static const dav_liveprop_group dav_fs_liveprop_group =
+{
+ dav_fs_props,
+ dav_fs_namespace_uris,
+ &dav_hooks_liveprop_fs
+};
+
/* define the dav_stream structure for our use */
struct dav_stream {
dav_fs_getetag,
};
-static int dav_fs_find_prop(const char *ns_uri, const char *name)
-{
- const dav_fs_liveprop_name *scan;
- int ns;
-
- if (*ns_uri == 'h'
- && strcmp(ns_uri, dav_fs_namespace_uris[DAV_FS_URI_MYPROPS]) == 0) {
- ns = DAV_FS_URI_MYPROPS;
- }
- else if (*ns_uri == 'D' && strcmp(ns_uri, "DAV:") == 0) {
- ns = DAV_FS_URI_DAV;
- }
- else {
- /* we don't define this property */
- return 0;
- }
-
- for (scan = dav_fs_props; scan->name != NULL; ++scan)
- if (ns == scan->ns && strcmp(name, scan->name) == 0)
- return scan->propid;
-
- return 0;
-}
-
static dav_prop_insert dav_fs_insert_prop(const dav_resource *resource,
int propid, int insvalue,
ap_text_header *phdr)
const char *s;
dav_prop_insert which;
apr_pool_t *p = resource->info->pool;
- const dav_fs_liveprop_name *scan;
- int ns;
+ 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];
- if (!DAV_PROPID_FS_OURS(propid))
- return DAV_PROP_INSERT_NOTME;
-
/*
** None of FS provider properties are defined if the resource does not
** exist. Just bail for this case.
** look there for the value.
**
** Even though we state that the FS properties are not defined, the
- ** client cannot store dead values -- we deny that thru the is_writable
+ ** client cannot store dead values -- we deny that thru the is_writeable
** hook function.
*/
if (!resource->exists)
return DAV_PROP_INSERT_NOTDEF;
switch (propid) {
- case DAV_PROPID_FS_creationdate:
+ case DAV_PROPID_creationdate:
/*
** Closest thing to a creation date. since we don't actually
** perform the operations that would modify ctime (after we
value = buf;
break;
- case DAV_PROPID_FS_getcontentlength:
+ case DAV_PROPID_getcontentlength:
/* our property, but not defined on collection resources */
if (resource->collection)
return DAV_PROP_INSERT_NOTDEF;
value = buf;
break;
- case DAV_PROPID_FS_getetag:
+ case DAV_PROPID_getetag:
value = dav_fs_getetag(resource);
break;
- case DAV_PROPID_FS_getlastmodified:
+ case DAV_PROPID_getlastmodified:
dav_format_time(DAV_STYLE_RFC822,
resource->info->finfo.mtime,
buf);
break;
#endif /* WIN32 */
- case DAV_PROPID_FS_displayname:
- case DAV_PROPID_FS_source:
+ case DAV_PROPID_displayname:
+ case DAV_PROPID_source:
default:
/*
** This property is not defined. However, it may be a dead
/* assert: value != NULL */
- for (scan = dav_fs_props; scan->name != NULL; ++scan)
- if (scan->propid == propid)
- break;
+ /* get the information and global NS index for the property */
+ global_ns = dav_get_liveprop_info(propid, &dav_fs_liveprop_group, &info);
- /* assert: scan->name != NULL */
-
- /* map our namespace into a global NS index */
- ns = dav_get_liveprop_ns_index(dav_fs_namespace_uris[scan->ns]);
+ /* assert: info != NULL && info->name != NULL */
/* DBG3("FS: inserting lp%d:%s (local %d)", ns, scan->name, scan->ns); */
if (insvalue) {
- /* use D: prefix to refer to the DAV: namespace URI */
s = apr_psprintf(p, "<lp%d:%s>%s</lp%d:%s>" DEBUG_CR,
- ns, scan->name, value, ns, scan->name);
+ global_ns, info->name, value, global_ns, info->name);
which = DAV_PROP_INSERT_VALUE;
}
else {
- /* use D: prefix to refer to the DAV: namespace URI */
- s = apr_psprintf(p, "<lp%d:%s/>" DEBUG_CR, ns, scan->name);
+ s = apr_psprintf(p, "<lp%d:%s/>" DEBUG_CR, global_ns, info->name);
which = DAV_PROP_INSERT_NAME;
}
ap_text_append(p, phdr, s);
return which;
}
-static void dav_fs_insert_all(const dav_resource *resource, int insvalue,
- ap_text_header *phdr)
-{
- if (!resource->exists) {
- /* a lock-null resource */
- /*
- ** ### technically, we should insert empty properties. dunno offhand
- ** ### what part of the spec said this, but it was essentially thus:
- ** ### "the properties should be defined, but may have no value".
- */
- return;
- }
-
- (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_creationdate,
- insvalue, phdr);
- (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_getcontentlength,
- insvalue, phdr);
- (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_getlastmodified,
- insvalue, phdr);
- (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_getetag,
- insvalue, phdr);
-
-#ifndef WIN32
- /*
- ** Note: this property is not defined on the Win32 platform.
- ** dav_fs_insert_prop() won't insert it, but we may as
- ** well not even call it.
- */
- (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_executable,
- insvalue, phdr);
-#endif
-
- /* ### we know the others aren't defined as liveprops */
-}
-
-static dav_prop_rw dav_fs_is_writeable(const dav_resource *resource,
- int propid)
+static int dav_fs_is_writeable(const dav_resource *resource, int propid)
{
- if (!DAV_PROPID_FS_OURS(propid))
- return DAV_PROP_RW_NOTME;
+ const dav_liveprop_spec *info;
- if (propid == DAV_PROPID_FS_displayname
- || propid == DAV_PROPID_FS_source
#ifndef WIN32
- /* this property is not usable (writeable) on the Win32 platform */
- || (propid == DAV_PROPID_FS_executable && !resource->collection)
+ /* this property is not usable (writeable) on the Win32 platform */
+ if (propid == DAV_PROPID_FS_executable && !resource->collection)
+ return 1;
#endif
- )
- return DAV_PROP_RW_YES;
- return DAV_PROP_RW_NO;
+ (void) dav_get_liveprop_info(propid, &dav_fs_liveprop_group, &info);
+ return info->is_writable;
}
static dav_error *dav_fs_patch_validate(const dav_resource *resource,
int dav_fs_find_liveprop(request_rec *r, const char *ns_uri, const char *name,
const dav_hooks_liveprop **hooks)
{
- int propid = dav_fs_find_prop(ns_uri, name);
-
- if (propid == 0)
- return 0;
-
- *hooks = &dav_hooks_liveprop_fs;
- return propid;
+ return dav_do_find_liveprop(ns_uri, name, &dav_fs_liveprop_group, hooks);
}
void dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource,
int insvalue, ap_text_header *phdr)
{
- dav_fs_insert_all(resource, insvalue, phdr);
+ if (!resource->exists) {
+ /* a lock-null resource */
+ /*
+ ** ### technically, we should insert empty properties. dunno offhand
+ ** ### what part of the spec said this, but it was essentially thus:
+ ** ### "the properties should be defined, but may have no value".
+ */
+ return;
+ }
+
+ (void) dav_fs_insert_prop(resource, DAV_PROPID_creationdate,
+ insvalue, phdr);
+ (void) dav_fs_insert_prop(resource, DAV_PROPID_getcontentlength,
+ insvalue, phdr);
+ (void) dav_fs_insert_prop(resource, DAV_PROPID_getlastmodified,
+ insvalue, phdr);
+ (void) dav_fs_insert_prop(resource, DAV_PROPID_getetag,
+ insvalue, phdr);
+
+#ifndef WIN32
+ /*
+ ** Note: this property is not defined on the Win32 platform.
+ ** dav_fs_insert_prop() won't insert it, but we may as
+ ** well not even call it.
+ */
+ (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_executable,
+ insvalue, phdr);
+#endif
+
+ /* ### we know the others aren't defined as liveprops */
}
void dav_fs_register(apr_pool_t *p)
{
/* register the namespace URIs */
- const char * const * uris = dav_fs_namespace_uris;
-
- for ( ; *uris != NULL; ++uris) {
- dav_register_liveprop_namespace(p, *uris);
- }
+ dav_register_liveprop_group(p, &dav_fs_liveprop_group);
/* register the repository provider */
dav_register_provider(p, "filesystem", &dav_fs_provider);
return APR_SUCCESS;
}
-DAV_DECLARE(void) dav_register_liveprop_namespace(apr_pool_t *p,
- const char *uri)
+static void dav_register_liveprop_namespace(apr_pool_t *p, const char *uri)
{
int value;
ap_text_append(p, phdr, s);
}
}
+
+DAV_DECLARE(int) dav_do_find_liveprop(const char *ns_uri, const char *name,
+ const dav_liveprop_group *group,
+ const dav_hooks_liveprop **hooks)
+{
+ const char * const *uris = group->namespace_uris;
+ const dav_liveprop_spec *scan;
+ int ns;
+
+ /* first: locate the namespace in the namespace table */
+ for (ns = 0; uris[ns] != NULL; ++ns)
+ if (strcmp(ns_uri, uris[ns]) == 0)
+ break;
+ if (uris[ns] == NULL) {
+ /* not our property (the namespace matched none of ours) */
+ return 0;
+ }
+
+ /* second: look for the property in the liveprop specs */
+ for (scan = group->specs; scan->name != NULL; ++scan)
+ if (ns == scan->ns && strcmp(name, scan->name) == 0) {
+ *hooks = group->hooks;
+ return scan->propid;
+ }
+
+ /* not our property (same namespace, but no matching prop name) */
+ return 0;
+}
+
+DAV_DECLARE(int) dav_get_liveprop_info(int propid,
+ const dav_liveprop_group *group,
+ const dav_liveprop_spec **info)
+{
+ const dav_liveprop_spec *scan;
+
+ for (scan = group->specs; scan->name != NULL; ++scan) {
+ if (scan->propid == propid) {
+ *info = scan;
+
+ /* map the provider-local NS into a global NS index */
+ return dav_get_liveprop_ns_index(group->namespace_uris[scan->ns]);
+ }
+ }
+
+ /* assert: should not reach this point */
+ *info = NULL;
+ return 0;
+}
+
+DAV_DECLARE(void) dav_register_liveprop_group(apr_pool_t *p,
+ const dav_liveprop_group *group)
+{
+ /* register the namespace URIs */
+ const char * const * uris = group->namespace_uris;
+
+ for ( ; *uris != NULL; ++uris) {
+ dav_register_liveprop_namespace(p, *uris);
+ }
+}
const dav_provider *hooks);
const dav_provider * dav_lookup_provider(const char *name);
-DAV_DECLARE(void) dav_register_liveprop_namespace(apr_pool_t *pool,
- const char *uri);
-DAV_DECLARE(int) dav_get_liveprop_ns_index(const char *uri);
-int dav_get_liveprop_ns_count(void);
-void dav_add_all_liveprop_xmlns(apr_pool_t *p, ap_text_header *phdr);
-
/* ### deprecated */
#define DAV_GET_HOOKS_PROPDB(r) dav_get_propdb_hooks(r)
*/
typedef enum {
- DAV_PROP_INSERT_NOTME, /* prop not defined by this provider */
DAV_PROP_INSERT_NOTDEF, /* property is defined by this provider,
but nothing was inserted because the
(live) property is not defined for this
into the text block */
} dav_prop_insert;
-typedef enum {
- DAV_PROP_RW_NOTME, /* not my property */
- DAV_PROP_RW_NO, /* property is NOT writeable */
- DAV_PROP_RW_YES /* property IS writeable */
-} dav_prop_rw;
-
/* opaque type for PROPPATCH rollback information */
typedef struct dav_liveprop_rollback dav_liveprop_rollback;
{
/*
** Insert a property name/value into a text block. The property to
- ** insert is identified by the propid value. Providers should return
- ** DAV_PROP_INSERT_NOTME if they do not define the specified propid.
- ** If insvalue is true, then the property's value should be inserted;
- ** otherwise, an empty element (ie. just the prop's name) should be
- ** inserted.
+ ** insert is identified by the propid value. If insvalue is true,
+ ** then the property's value should be inserted; otherwise, an empty
+ ** element (ie. just the prop's name) should be inserted.
**
** Returns one of DAV_PROP_INSERT_* based on what happened.
**
** ### we may want a different semantic. i.e. maybe it should be
** ### "can we write <value> into this property?"
**
- ** Returns appropriate read/write status.
+ ** Returns 1 if the live property can be written, 0 if read-only.
*/
- dav_prop_rw (*is_writeable)(const dav_resource *resource, int propid);
+ int (*is_writeable)(const dav_resource *resource, int propid);
/*
** This member defines the set of namespace URIs that the provider
dav_liveprop_rollback *rollback_ctx);
};
+/*
+** dav_liveprop_spec: specify a live property
+**
+** This structure is used as a standard way to determine if a particular
+** property is a live property. Its use is not part of the mandated liveprop
+** interface, but can be used by liveprop providers in conjuction with the
+** utility routines below.
+*/
+typedef struct {
+ int ns; /* provider-local namespace index */
+ const char *name; /* name of the property */
+
+ int propid; /* provider-local property ID */
+
+ int is_writable; /* is the property writeable? */
+
+} dav_liveprop_spec;
+
+/*
+** dav_liveprop_group: specify a group of liveprops
+**
+** This structure specifies a group of live properties, their namespaces,
+** and how to handle them.
+*/
+typedef struct {
+ const dav_liveprop_spec *specs;
+ const char * const *namespace_uris;
+ const dav_hooks_liveprop *hooks;
+
+} dav_liveprop_group;
+
+/* ### docco */
+DAV_DECLARE(int) dav_do_find_liveprop(const char *ns_uri, const char *name,
+ const dav_liveprop_group *group,
+ const dav_hooks_liveprop **hooks);
+
+/* ### docco */
+DAV_DECLARE(int) dav_get_liveprop_info(int propid,
+ const dav_liveprop_group *group,
+ const dav_liveprop_spec **info);
+
+/* ### docco */
+DAV_DECLARE(void) dav_register_liveprop_group(apr_pool_t *pool,
+ const dav_liveprop_group *group);
+
+/* ### docco */
+DAV_DECLARE(int) dav_get_liveprop_ns_index(const char *uri);
+
+/* ### docco */
+int dav_get_liveprop_ns_count(void);
+
+/* ### docco */
+void dav_add_all_liveprop_xmlns(apr_pool_t *p, ap_text_header *phdr);
+
+/*
+** Standard WebDAV Property Identifiers
+**
+** A live property provider does not need to use these; they are simply
+** provided for convenience.
+**
+** Property identifiers need to be unique within a given provider, but not
+** *across* providers (note: this uniqueness constraint was different in
+** older versions of mod_dav).
+**
+** The identifiers start at 20000 to make it easier for providers to avoid
+** conflicts with the standard properties. The properties are arranged
+** alphabetically, and may be reordered from time to time (as properties
+** are introduced).
+**
+** NOTE: there is no problem with reordering (e.g. binary compat) since the
+** identifiers are only used within a given provider, which would pick up
+** the entire set of changes upon a recompile.
+*/
+enum {
+ DAV_PROPID_BEGIN = 20000,
+
+ /* Standard WebDAV properties (RFC 2518 and DeltaV I-D) */
+ DAV_PROPID_comment, /* from DeltaV I-D */
+ DAV_PROPID_creationdate,
+ DAV_PROPID_creator_displayname, /* from DeltaV I-D */
+ DAV_PROPID_displayname,
+ DAV_PROPID_getcontentlanguage,
+ DAV_PROPID_getcontentlength,
+ DAV_PROPID_getcontenttype,
+ DAV_PROPID_getetag,
+ DAV_PROPID_getlastmodified,
+ DAV_PROPID_lockdiscovery,
+ DAV_PROPID_resourcetype,
+ DAV_PROPID_source,
+ DAV_PROPID_supportedlock,
+ DAV_PROPID_supported_method_set, /* from DeltaV I-D */
+ DAV_PROPID_supported_live_property_set, /* from DeltaV I-D */
+ DAV_PROPID_supported_report_set, /* from DeltaV I-D */
+
+ /* DeltaV properties (from the I-D) */
+ DAV_PROPID_activity_collection_set,
+ DAV_PROPID_activity_set,
+ DAV_PROPID_auto_merge_set,
+ DAV_PROPID_auto_version,
+ DAV_PROPID_baseline_selector,
+ DAV_PROPID_baselined_collection,
+ DAV_PROPID_baselined_collection_set,
+ DAV_PROPID_checked_out,
+ DAV_PROPID_checkin_date,
+ DAV_PROPID_checkin_fork,
+ DAV_PROPID_checkout_fork,
+ DAV_PROPID_checkout_set,
+ DAV_PROPID_current_activity_set,
+ DAV_PROPID_current_workspace_set,
+ DAV_PROPID_initial_version,
+ DAV_PROPID_label_name_set,
+ DAV_PROPID_latest_version,
+ DAV_PROPID_merge_set,
+ DAV_PROPID_mutable,
+ DAV_PROPID_predecessor_set,
+ DAV_PROPID_subactivity_set,
+ DAV_PROPID_successor_set,
+ DAV_PROPID_target,
+ DAV_PROPID_unreserved,
+ DAV_PROPID_version,
+ DAV_PROPID_version_history,
+ DAV_PROPID_version_name,
+ DAV_PROPID_version_set,
+ DAV_PROPID_workspace,
+ DAV_PROPID_workspace_checkout_set,
+ DAV_PROPID_workspace_collection_set,
+
+ DAV_PROPID_END
+};
+
/*
** Property Identifier Registration
**
};
+/* NOTE: dav_core_props[] and the following enum must stay in sync. */
/* ### move these into a "core" liveprop provider? */
static const char * const dav_core_props[] =
{
DAV_PROPID_CORE_UNKNOWN
};
-#define DAV_IS_CORE_PROP(propid) ((propid) >= DAV_PROPID_CORE && \
- (propid) <= DAV_PROPID_CORE_UNKNOWN)
/*
** This structure is used to track information needed for a rollback.
for (propid = DAV_PROPID_CORE; *p != NULL; ++p, ++propid)
if (strcmp(elem->name, *p) == 0) {
priv->propid = propid;
+ /* priv->provider == NULL */
return;
}
else if (elem->ns == AP_XML_NS_NONE) {
/* policy: liveprop providers cannot define no-namespace properties */
priv->propid = DAV_PROPID_CORE_UNKNOWN;
+ /* priv->provider == NULL */
return;
}
}
priv->propid = DAV_PROPID_CORE_UNKNOWN;
+ /* priv->provider == NULL */
}
/* is the live property read/write? */
{
int propid = priv->propid;
+ /*
+ ** Check the liveprop provider (if this is a provider-defined prop)
+ */
+ if (priv->provider != NULL) {
+ return (*priv->provider->is_writeable)(propdb->resource, propid);
+ }
+
/* these are defined as read-only */
if (propid == DAV_PROPID_CORE_lockdiscovery
|| propid == DAV_PROPID_CORE_resourcetype
}
/*
- ** Check the liveprop providers
- */
- if (priv->provider != NULL) {
- dav_prop_rw rw;
-
- rw = (*priv->provider->is_writeable)(propdb->resource, propid);
- if (rw == DAV_PROP_RW_YES)
- return 1;
- if (rw == DAV_PROP_RW_NO)
- return 0;
- }
-
- /*
- ** No provider recognized the property, so it must be dead (and writable)
+ ** We don't recognize the property, so it must be dead (and writable)
*/
return 1;
}
{
/* perform a "GET" on the resource's URI (note that the resource
may not correspond to the current request!). */
- propdb->subreq = ap_sub_req_lookup_uri(propdb->resource->uri, propdb->r);
+ propdb->subreq = ap_sub_req_lookup_uri(propdb->resource->uri, propdb->r,
+ NULL);
}
static dav_error * dav_insert_coreprop(dav_propdb *propdb,
*inserted = 0;
- if (DAV_IS_CORE_PROP(priv->propid))
+ if (priv->provider == NULL) {
+ /* this is a "core" property that we define */
return dav_insert_coreprop(propdb, priv->propid, elem->name,
getvals, phdr, inserted);
+ }
/* ask the provider (that defined this prop) to insert the prop */
pi = (*priv->provider->insert_prop)(propdb->resource, priv->propid,
getvals, phdr);
-#if DAV_DEBUG
- if (pi == DAV_PROP_INSERT_NOTME) {
- /* ### the provider should have returned NOTDEF, at least */
- return dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, 0,
- "DESIGN ERROR: a liveprop provider defined "
- "a property, but did not respond to the "
- "insert_prop hook for it.");
- }
-#endif
-
if (pi != DAV_PROP_INSERT_NOTDEF)
*inserted = 1;