dbm.c revision 3d81f57512275ca06a60a9bcbd23c1f8b429fdf2
/* Copyright 2000-2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** DAV extension module for Apache 2.0.*
** - Database support using DBM-style databases,
** part of the filesystem repository implementation
*/
/*
** This implementation uses a SDBM database per file and directory to
** record the properties. These databases are kept in a subdirectory (of
** the directory in question or the directory that holds the file in
** question) named by the macro DAV_FS_STATE_DIR (.DAV). The filename of the
** database is equivalent to the target filename, and is
** DAV_FS_STATE_FILE_FOR_DIR (.state_for_dir) for the directory itself.
*/
#include "apr_strings.h"
#include "apr_file_io.h"
#include "apr_dbm.h"
#define APR_WANT_BYTEFUNC
#include "apr_want.h" /* for ntohs and htons */
#include "mod_dav.h"
#include "repos.h"
struct dav_db {
/* when used as a property database: */
int version; /* *minor* version of this db */
short ns_count; /* number of entries in table */
int ns_table_dirty; /* ns_table was modified */
};
/* -------------------------------------------------------------------------
*
* GENERIC DBM ACCESS
*
* For the most part, this just uses the APR DBM functions. They are wrapped
* a bit with some error handling (using the mod_dav error functions).
*/
{
}
{
int save_errno = errno;
int errcode;
const char *errstr;
char errbuf[200];
if (status == APR_SUCCESS)
return NULL;
/* There might not be a <db> if we had problems creating it. */
errcode = 1;
errstr = "Could not open property database.";
}
else {
}
return err;
}
/* ensure that our state subdirectory is present */
/* ### does this belong here or in dav_fs_repos.c ?? */
{
/* ### do we need to deal with the umask? */
/* just try to make it, ignoring any resulting errors */
}
/* dav_dbm_open_direct: Opens a *dbm database specified by path.
* ro = boolean read-only flag.
*/
{
APR_OS_DEFAULT, p))
!= APR_SUCCESS
&& !ro) {
/* ### do something with 'status' */
/* we can't continue if we couldn't open the file
and we need to write */
}
/* may be NULL if we tried to open a non-existent db as read-only */
/* we have an open database... return it */
}
return NULL;
}
{
const char *dirpath;
const char *fname;
const char *pathname;
/* Get directory and filename for resource */
/* ### should test this result value... */
/* If not opening read-only, ensure the state dir exists */
if (!ro) {
/* ### what are the perf implications of always checking this? */
}
NULL);
/* ### readers cannot open while a writer has this open; we should
### perform a few retries with random pauses. */
/* ### do we need to deal with the umask? */
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
/* -------------------------------------------------------------------------
*
* PROPERTY DATABASE FUNCTIONS
*/
#define DAV_GDBM_NS_KEY "METADATA"
#define DAV_GDBM_NS_KEY_LEN 8
typedef struct {
unsigned char major;
#define DAV_DBVSN_MAJOR 4
/*
** V4 -- 0.9.9 ..
** Prior versions could have keys or values with invalid
** namespace prefixes as a result of the xmlns="" form not
** resetting the default namespace to be "no namespace". The
** namespace would be set to "" which is invalid; it should
** be set to "no namespace".
**
** V3 -- 0.9.8
** Prior versions could have values with invalid namespace
** prefixes due to an incorrect mapping of input to propdb
** namespace indices. Version bumped to obsolete the old
** values.
**
** V2 -- 0.9.7
** This introduced the xml:lang value into the property value's
** record in the propdb.
**
** V1 -- .. 0.9.6
** Initial version.
*/
unsigned char minor;
#define DAV_DBVSN_MINOR 0
short ns_count;
struct dav_deadprop_rollback {
};
struct dav_namespace_map {
int *ns_map;
};
/*
** Internal function to build a key
**
** WARNING: returns a pointer to a "static" buffer holding the key. The
** value must be copied or no longer used if this function is
** called again.
*/
{
char nsbuf[20];
apr_datum_t key = { 0 };
/*
* Convert namespace ID to a string. "no namespace" is an empty string,
* so the keys will have the form ":name". Otherwise, the keys will
* have the form "#:name".
*/
nsbuf[0] = '\0';
l_ns = 0;
}
else {
if (ns_id == 0) {
/* the namespace was not found(!) */
return key; /* zeroed */
}
}
/* assemble: #:name */
/* build the database key */
return key;
}
{
const char *s;
/* skip past the xml:lang value */
if (*value == '\0') {
/* the property is an empty value */
if (*name == ':') {
/* "no namespace" case */
}
else {
}
}
else if (*lang != '\0') {
if (*name == ':') {
/* "no namespace" case */
}
else {
}
}
else if (*name == ':') {
/* "no namespace" case */
}
else {
}
}
{
apr_datum_t value = { 0 };
/*
** Return if an error occurred, or there is no database.
**
** NOTE: db could be NULL if we attempted to open a readonly
** access, then a database was created and opened.
*/
return err;
/* ### push a higher-level description? */
return err;
}
dav_propdb_metadata m = {
};
/*
** If there is no METADATA key, then the database may be
** from versions 0.9.0 .. 0.9.4 (which would be incompatible).
** These can be identified by the presence of an NS_TABLE entry.
*/
/* call it a major version error */
"Prop database has the wrong major "
"version number and cannot be used.");
}
/* initialize a new metadata structure */
}
else {
long ns;
const char *uri;
if (m.major != DAV_DBVSN_MAJOR) {
"Prop database has the wrong major "
"version number and cannot be used.");
}
/* create db->uri_index */
/* we must copy the key, in case ns_table.buf moves */
(void *)ns);
}
}
return NULL;
}
{
if (db->ns_table_dirty) {
/* fill in the metadata that we store into the prop db. */
m.major = DAV_DBVSN_MAJOR;
/* ### what to do with the error? */
}
}
{
int ns;
/* within the prop values, we use "ns%d" for prefixes... register them */
/* Empty URIs signify the empty namespace. These do not get a
namespace prefix. when we generate the value, we will simply
leave off the prefix, which is defined by mod_dav to be the
empty namespace. */
if (*uri == '\0')
continue;
/* ns_table.buf can move, so copy its value (we want the values to
last as long as the provided dav_xmlns_info). */
}
return NULL;
}
const dav_prop_name *name,
int *found)
{
return err;
*found = 0;
return NULL;
}
*found = 1;
return NULL;
}
static dav_error * dav_propdb_map_namespaces(
const apr_array_header_t *namespaces,
{
int i;
int *pmap;
const char **puri;
/*
** Iterate over the provided namespaces. If a namespace already appears
** in our internal map of URI -> ns_id, then store that in the map. If
** we don't know the namespace yet, then add it to the map and to our
** table of known namespaces.
*/
i-- > 0;
if (ns_id == 0) {
/* copy the uri in case the passed-in namespaces changes in
some way. */
}
else {
}
}
*mapping = m;
return NULL;
}
const apr_xml_elem *elem,
{
/* Note: mapping->ns_map was set up in dav_propdb_map_namespaces() */
/* ### use a db- subpool for these values? clear on exit? */
/* quote all the values in the element */
/* ### be nice to do this without affecting the element itself */
/* ### of course, the cast indicates Badness is occurring here */
/* generate a text blob for the xml:lang plus the contents */
}
{
}
{
}
{
while (ns_id--)
p += strlen(p) + 1;
return p;
}
{
if (s == NULL) {
}
else if (*s == ':') {
}
else {
if (s[1] == ':') {
}
else {
}
}
}
{
/* free the previous key. note: if the loop is aborted, then the DBM
will toss the key (via pool cleanup) */
return err;
/* skip past the METADATA key */
return NULL;
}
{
return err;
/* skip past the METADATA key */
return NULL;
}
const dav_prop_name *name,
{
return err;
}
return NULL;
}
{
/* don't fail if the thing isn't really there. */
return NULL;
}
}
const dav_hooks_db dav_hooks_db_dbm =
{
NULL /* ctx */
};