diff options
Diffstat (limited to 'rubbos/app/httpd-2.0.64/modules/dav/fs/dbm.c')
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/dbm.c | 753 |
1 files changed, 0 insertions, 753 deletions
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/dbm.c b/rubbos/app/httpd-2.0.64/modules/dav/fs/dbm.c deleted file mode 100644 index a772a75d..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/dbm.c +++ /dev/null @@ -1,753 +0,0 @@ -/* 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 */ - -#include "mod_dav.h" -#include "repos.h" - - -struct dav_db { - apr_pool_t *pool; - apr_dbm_t *file; - - /* when used as a property database: */ - - int version; /* *minor* version of this db */ - - 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). - */ - -void dav_dbm_get_statefiles(apr_pool_t *p, const char *fname, - const char **state1, const char **state2) -{ - if (fname == NULL) - fname = DAV_FS_STATE_FILE_FOR_DIR; - - apr_dbm_get_usednames(p, fname, state1, state2); -} - -static dav_error * dav_fs_dbm_error(dav_db *db, apr_pool_t *p, - apr_status_t status) -{ - int save_errno = errno; - int errcode; - const char *errstr; - dav_error *err; - char errbuf[200]; - - if (status == APR_SUCCESS) - return NULL; - - p = db ? db->pool : p; - - /* There might not be a <db> if we had problems creating it. */ - if (db == NULL) { - errcode = 1; - errstr = "Could not open property database."; - } - else { - (void) apr_dbm_geterror(db->file, &errcode, errbuf, sizeof(errbuf)); - errstr = apr_pstrdup(p, errbuf); - } - - err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, errcode, errstr); - err->save_errno = save_errno; - return err; -} - -/* 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, const char *dirname) -{ - const char *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); -} - -/* dav_dbm_open_direct: Opens a *dbm database specified by path. - * ro = boolean read-only flag. - */ -dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, int ro, - dav_db **pdb) -{ - apr_status_t status; - apr_dbm_t *file; - - *pdb = NULL; - - 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); - } - - /* 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; - } - - return NULL; -} - -static dav_error * dav_dbm_open(apr_pool_t * p, const dav_resource *resource, - int ro, dav_db **pdb) -{ - const char *dirpath; - const char *fname; - const char *pathname; - - /* 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); - } - - pathname = apr_pstrcat(p, dirpath, "/" DAV_FS_STATE_DIR "/", - fname ? fname : DAV_FS_STATE_FILE_FOR_DIR, - 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? */ - - return dav_dbm_open_direct(p, pathname, ro, pdb); -} - -void dav_dbm_close(dav_db *db) -{ - apr_dbm_close(db->file); -} - -dav_error * dav_dbm_fetch(dav_db *db, apr_datum_t key, apr_datum_t *pvalue) -{ - apr_status_t status = apr_dbm_fetch(db->file, key, pvalue); - - return dav_fs_dbm_error(db, NULL, status); -} - -dav_error * dav_dbm_store(dav_db *db, apr_datum_t key, apr_datum_t value) -{ - apr_status_t status = apr_dbm_store(db->file, key, value); - - return dav_fs_dbm_error(db, NULL, status); -} - -dav_error * dav_dbm_delete(dav_db *db, apr_datum_t key) -{ - apr_status_t status = apr_dbm_delete(db->file, key); - - return dav_fs_dbm_error(db, NULL, status); -} - -int dav_dbm_exists(dav_db *db, apr_datum_t key) -{ - return apr_dbm_exists(db->file, key); -} - -static dav_error * dav_dbm_firstkey(dav_db *db, apr_datum_t *pkey) -{ - apr_status_t status = apr_dbm_firstkey(db->file, pkey); - - return dav_fs_dbm_error(db, NULL, status); -} - -static dav_error * dav_dbm_nextkey(dav_db *db, apr_datum_t *pkey) -{ - apr_status_t status = apr_dbm_nextkey(db->file, pkey); - - return dav_fs_dbm_error(db, NULL, status); -} - -void dav_dbm_freedatum(dav_db *db, apr_datum_t data) -{ - apr_dbm_freedatum(db->file, data); -} - -/* ------------------------------------------------------------------------- - * - * 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; - -} dav_propdb_metadata; - -struct dav_deadprop_rollback { - apr_datum_t key; - apr_datum_t value; -}; - -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. -*/ -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 { - int ns_id = (int)apr_hash_get(db->uri_index, name->ns, - APR_HASH_KEY_STRING); - - - if (ns_id == 0) { - /* the namespace was not found(!) */ - return key; /* zeroed */ - } - - l_ns = sprintf(nsbuf, "%d", ns_id - 1); - } - - /* assemble: #:name */ - dav_set_bufsize(db->pool, &db->wb_key, l_ns + 1 + l_name + 1); - memcpy(db->wb_key.buf, nsbuf, l_ns); - db->wb_key.buf[l_ns] = ':'; - memcpy(&db->wb_key.buf[l_ns + 1], name->name, l_name + 1); - - /* build the database key */ - key.dsize = l_ns + 1 + l_name + 1; - key.dptr = db->wb_key.buf; - - return key; -} - -static void dav_append_prop(apr_pool_t *pool, - const char *name, const char *value, - apr_text_header *phdr) -{ - const char *s; - const char *lang = value; - - /* skip past the xml:lang value */ - value += strlen(lang) + 1; - - if (*value == '\0') { - /* the property is an empty value */ - if (*name == ':') { - /* "no namespace" case */ - s = apr_psprintf(pool, "<%s/>" DEBUG_CR, name+1); - } - else { - s = apr_psprintf(pool, "<ns%s/>" DEBUG_CR, name); - } - } - else if (*lang != '\0') { - if (*name == ':') { - /* "no namespace" case */ - s = apr_psprintf(pool, "<%s xml:lang=\"%s\">%s</%s>" DEBUG_CR, - name+1, lang, value, name+1); - } - else { - s = apr_psprintf(pool, "<ns%s xml:lang=\"%s\">%s</ns%s>" DEBUG_CR, - name, lang, value, name); - } - } - else if (*name == ':') { - /* "no namespace" case */ - s = apr_psprintf(pool, "<%s>%s</%s>" DEBUG_CR, name+1, value, name+1); - } - else { - s = apr_psprintf(pool, "<ns%s>%s</ns%s>" DEBUG_CR, name, value, name); - } - - apr_text_append(pool, phdr, s); -} - -static dav_error * dav_propdb_open(apr_pool_t *pool, - const dav_resource *resource, int ro, - dav_db **pdb) -{ - dav_db *db; - dav_error *err; - apr_datum_t key; - apr_datum_t value = { 0 }; - - *pdb = NULL; - - /* - ** 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; - - db->uri_index = apr_hash_make(pool); - - key.dptr = DAV_GDBM_NS_KEY; - key.dsize = DAV_GDBM_NS_KEY_LEN; - if ((err = dav_dbm_fetch(db, key, &value)) != NULL) { - /* ### push a higher-level description? */ - 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, - "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; - int ns; - const char *uri; - - dav_set_bufsize(pool, &db->ns_table, value.dsize); - memcpy(db->ns_table.buf, value.dptr, value.dsize); - - 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, - "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; -} - -static void 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; - - key.dptr = DAV_GDBM_NS_KEY; - key.dsize = DAV_GDBM_NS_KEY_LEN; - - value.dptr = db->ns_table.buf; - value.dsize = db->ns_table.cur_len; - - /* 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); - - memcpy(db->ns_table.buf, &m, sizeof(m)); - - err = dav_dbm_store(db, key, value); - /* ### what to do with the error? */ - } - - dav_dbm_close(db); -} - -static dav_error * dav_propdb_define_namespaces(dav_db *db, dav_xmlns_info *xi) -{ - int ns; - const char *uri = db->ns_table.buf + sizeof(dav_propdb_metadata); - - /* 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)); - } - - return NULL; -} - -static dav_error * dav_propdb_output_value(dav_db *db, - const dav_prop_name *name, - dav_xmlns_info *xi, - apr_text_header *phdr, - int *found) -{ - apr_datum_t key = dav_build_key(db, name); - apr_datum_t value; - dav_error *err; - - if ((err = dav_dbm_fetch(db, key, &value)) != NULL) - return err; - if (value.dptr == NULL) { - *found = 0; - return NULL; - } - *found = 1; - - dav_append_prop(db->pool, key.dptr, value.dptr, phdr); - - dav_dbm_freedatum(db, value); - - return NULL; -} - -static dav_error * dav_propdb_map_namespaces( - dav_db *db, - const apr_array_header_t *namespaces, - dav_namespace_map **mapping) -{ - dav_namespace_map *m = apr_palloc(db->pool, sizeof(*m)); - 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. - */ - m->ns_map = pmap = apr_palloc(db->pool, namespaces->nelts * sizeof(*pmap)); - for (i = namespaces->nelts, puri = (const char **)namespaces->elts; - i-- > 0; - ++puri, ++pmap) { - - const char *uri = *puri; - apr_size_t uri_len = strlen(uri); - int ns_id = (int)apr_hash_get(db->uri_index, uri, uri_len); - - if (ns_id == 0) { - dav_check_bufsize(db->pool, &db->ns_table, uri_len + 1); - memcpy(db->ns_table.buf + db->ns_table.cur_len, uri, uri_len + 1); - db->ns_table.cur_len += uri_len + 1; - - /* 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 *)(db->ns_count + 1)); - - db->ns_table_dirty = 1; - - *pmap = db->ns_count++; - } - else { - *pmap = ns_id - 1; - } - } - - *mapping = m; - return NULL; -} - -static dav_error * dav_propdb_store(dav_db *db, const dav_prop_name *name, - const apr_xml_elem *elem, - dav_namespace_map *mapping) -{ - apr_datum_t key = dav_build_key(db, name); - apr_datum_t value; - - /* 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, - (const char **)&value.dptr, &value.dsize); - - return dav_dbm_store(db, key, value); -} - -static dav_error * dav_propdb_remove(dav_db *db, const dav_prop_name *name) -{ - apr_datum_t key = dav_build_key(db, name); - return dav_dbm_delete(db, key); -} - -static int dav_propdb_exists(dav_db *db, const dav_prop_name *name) -{ - apr_datum_t key = dav_build_key(db, name); - return dav_dbm_exists(db, key); -} - -static const char *dav_get_ns_table_uri(dav_db *db, int ns_id) -{ - const char *p = db->ns_table.buf + sizeof(dav_propdb_metadata); - - while (ns_id--) - p += strlen(p) + 1; - - return p; -} - -static void dav_set_name(dav_db *db, dav_prop_name *pname) -{ - const char *s = db->iter.dptr; - - if (s == NULL) { - pname->ns = pname->name = NULL; - } - else if (*s == ':') { - pname->ns = ""; - pname->name = s + 1; - } - else { - int id = atoi(s); - - pname->ns = dav_get_ns_table_uri(db, id); - if (s[1] == ':') { - pname->name = s + 2; - } - else { - pname->name = ap_strchr_c(s + 2, ':') + 1; - } - } -} - -static dav_error * dav_propdb_next_name(dav_db *db, dav_prop_name *pname) -{ - dav_error *err; - - /* 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); - - dav_set_name(db, pname); - return NULL; -} - -static dav_error * dav_propdb_first_name(dav_db *db, dav_prop_name *pname) -{ - dav_error *err; - - if ((err = dav_dbm_firstkey(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); - - dav_set_name(db, pname); - return NULL; -} - -static dav_error * dav_propdb_get_rollback(dav_db *db, - const dav_prop_name *name, - dav_deadprop_rollback **prollback) -{ - dav_deadprop_rollback *rb = apr_pcalloc(db->pool, sizeof(*rb)); - apr_datum_t key; - apr_datum_t value; - dav_error *err; - - key = dav_build_key(db, name); - rb->key.dptr = apr_pstrdup(db->pool, key.dptr); - rb->key.dsize = key.dsize; - - if ((err = dav_dbm_fetch(db, key, &value)) != NULL) - return err; - if (value.dptr != NULL) { - rb->value.dptr = apr_pmemdup(db->pool, value.dptr, value.dsize); - rb->value.dsize = value.dsize; - } - - *prollback = rb; - return NULL; -} - -static dav_error * dav_propdb_apply_rollback(dav_db *db, - dav_deadprop_rollback *rollback) -{ - if (rollback->value.dptr == NULL) { - /* don't fail if the thing isn't really there. */ - (void) dav_dbm_delete(db, rollback->key); - return NULL; - } - - return dav_dbm_store(db, rollback->key, rollback->value); -} - -const dav_hooks_db dav_hooks_db_dbm = -{ - dav_propdb_open, - dav_propdb_close, - dav_propdb_define_namespaces, - dav_propdb_output_value, - dav_propdb_map_namespaces, - dav_propdb_store, - dav_propdb_remove, - dav_propdb_exists, - dav_propdb_first_name, - dav_propdb_next_name, - dav_propdb_get_rollback, - dav_propdb_apply_rollback, - - NULL /* ctx */ -}; |