/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 */
dav_buffer ns_table; /* table of namespace URIs */ short ns_count; /* number of entries in table */ int ns_table_dirty; /* ns_table was modified */
apr_hash_t *uri_index; /* map URIs to (1-based) table indices */
dav_buffer wb_key; /* work buffer for dav_gdbm_key */
apr_datum_t iter; /* iteration key */
};
/* ------------------------------------------------------------------------- * * 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).
*/
/* There might not be a <db> if we had problems creating it. */ if (db == NULL) {
errcode = 1;
errstr = "Could not open database."; if (APR_STATUS_IS_EDSOOPEN(status))
ap_log_error(APLOG_MARK, APLOG_CRIT, status, ap_server_conf, APLOGNO(00576) "The DBM driver could not be loaded");
} else {
(void) apr_dbm_geterror(db->file, &errcode, errbuf, sizeof(errbuf));
errstr = apr_pstrdup(p, errbuf);
}
/* ensure that our state subdirectory is present */ /* ### does this belong here or in dav_fs_repos.c ?? */ void dav_fs_ensure_state_dir(apr_pool_t * p, constchar *dirname)
{ constchar *pathname = apr_pstrcat(p, dirname, "/" DAV_FS_STATE_DIR, NULL);
/* ### do we need to deal with the umask? */
/* just try to make it, ignoring any resulting errors */
(void) apr_dir_make(pathname, APR_OS_DEFAULT, p);
}
#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) if ((status = apr_dbm_get_driver(&driver, NULL, &err, p)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf, APLOGNO(10289) "mod_dav_fs: The DBM library '%s' could not be loaded: %s",
err->reason, err->msg); return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 1, status, "Could not load library for database.");
} if ((status = apr_dbm_open2(&file, driver, pathname,
ro ? APR_DBM_READONLY : APR_DBM_RWCREATE,
APR_OS_DEFAULT, p))
!= APR_SUCCESS && !ro) { return dav_fs_dbm_error(NULL, p, status);
} #else if ((status = apr_dbm_open(&file, pathname,
ro ? APR_DBM_READONLY : APR_DBM_RWCREATE,
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 */ return dav_fs_dbm_error(NULL, p, status);
} #endif
/* may be NULL if we tried to open a non-existent db as read-only */ if (file != NULL) { /* we have an open database... return it */
*pdb = apr_pcalloc(p, sizeof(**pdb));
(*pdb)->pool = p;
(*pdb)->file = file;
}
/* Get directory and filename for resource */ /* ### should test this result value... */
(void) dav_fs_dir_file_name(resource, &dirpath, &fname);
/* If not opening read-only, ensure the state dir exists */ if (!ro) { /* ### what are the perf implications of always checking this? */
dav_fs_ensure_state_dir(p, dirpath);
}
if (!key.dptr) { /* no key could be created (namespace not known) => no value */
memset(pvalue, 0, sizeof(*pvalue));
status = APR_SUCCESS;
} else {
status = apr_dbm_fetch(db->file, key, pvalue);
}
typedefstruct { unsignedchar 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.
*/
/* ** 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.
*/ static apr_datum_t dav_build_key(dav_db *db, const dav_prop_name *name)
{ char nsbuf[20];
apr_size_t l_ns, l_name = strlen(name->name);
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".
*/ if (*name->ns == '\0') {
nsbuf[0] = '\0';
l_ns = 0;
} else { long ns_id = (long)apr_hash_get(db->uri_index, name->ns,
APR_HASH_KEY_STRING);
if (ns_id == 0) { /* the namespace was not found(!) */ return key; /* zeroed */
}
/* ** Return if an error occurred, or there is no database. ** ** NOTE: db could be NULL if we attempted to open a readonly ** database that doesn't exist. If we require read/write ** access, then a database was created and opened.
*/ if ((err = dav_dbm_open(pool, resource, ro, &db)) != NULL
|| db == NULL) return err;
if (value.dptr == NULL) {
dav_propdb_metadata m = {
DAV_DBVSN_MAJOR, DAV_DBVSN_MINOR, 0
};
/* ** 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.
*/
key.dptr = "NS_TABLE";
key.dsize = 8; if (dav_dbm_exists(db, key)) {
dav_dbm_close(db);
/* call it a major version error */ return dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR,
DAV_ERR_PROP_BAD_MAJOR, 0, "Prop database has the wrong major " "version number and cannot be used.");
}
/* initialize a new metadata structure */
dav_set_bufsize(pool, &db->ns_table, sizeof(m));
memcpy(db->ns_table.buf, &m, sizeof(m));
} else {
dav_propdb_metadata m; long ns; constchar *uri;
memcpy(&m, value.dptr, sizeof(m)); if (m.major != DAV_DBVSN_MAJOR) {
dav_dbm_close(db);
return dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR,
DAV_ERR_PROP_BAD_MAJOR, 0, "Prop database has the wrong major " "version number and cannot be used.");
}
db->version = m.minor;
db->ns_count = ntohs(m.ns_count);
dav_dbm_freedatum(db, value);
/* create db->uri_index */ for (ns = 0, uri = db->ns_table.buf + sizeof(dav_propdb_metadata);
ns++ < db->ns_count;
uri += strlen(uri) + 1) {
/* we must copy the key, in case ns_table.buf moves */
apr_hash_set(db->uri_index,
apr_pstrdup(pool, uri), APR_HASH_KEY_STRING,
(void *)ns);
}
}
*pdb = db; return NULL;
}
staticvoid dav_propdb_close(dav_db *db)
{
if (db->ns_table_dirty) {
dav_propdb_metadata m;
apr_datum_t key;
apr_datum_t value;
dav_error *err;
/* fill in the metadata that we store into the prop db. */
m.major = DAV_DBVSN_MAJOR;
m.minor = db->version; /* ### keep current minor version? */
m.ns_count = htons(db->ns_count);
/* within the prop values, we use "ns%d" for prefixes... register them */ for (ns = 0; ns < db->ns_count; ++ns, uri += strlen(uri) + 1) {
/* 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). */
dav_xmlns_add(xi,
apr_psprintf(xi->pool, "ns%d", ns),
apr_pstrdup(xi->pool, uri));
}
/* ** 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.
*/
m->ns_map = pmap = apr_palloc(db->pool, namespaces->nelts * sizeof(*pmap)); for (i = namespaces->nelts, puri = (constchar **)namespaces->elts;
i-- > 0;
++puri, ++pmap) {
/* copy the uri in case the passed-in namespaces changes in
some way. */
apr_hash_set(db->uri_index, apr_pstrdup(db->pool, uri), uri_len,
(void *)((long)(db->ns_count + 1)));
/* 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 */
apr_xml_quote_elem(db->pool, (apr_xml_elem *)elem);
/* generate a text blob for the xml:lang plus the contents */
apr_xml_to_text(db->pool, elem, APR_XML_X2T_LANG_INNER, NULL,
mapping->ns_map,
(constchar **)&value.dptr, &value.dsize);
/* free the previous key. note: if the loop is aborted, then the DBM
will toss the key (via pool cleanup) */ if (db->iter.dptr != NULL)
dav_dbm_freedatum(db, db->iter);
if ((err = dav_dbm_nextkey(db, &db->iter)) != NULL) return err;
/* skip past the METADATA key */ if (db->iter.dptr != NULL && *db->iter.dptr == 'M') return dav_propdb_next_name(db, pname);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.