diff options
Diffstat (limited to 'rubbos/app/httpd-2.0.64/modules/dav/fs')
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/.deps | 0 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/Makefile | 8 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/Makefile.in | 3 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/NWGNUmakefile | 266 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/config6.m4 | 23 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/dbm.c | 753 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/lock.c | 1517 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/mod_dav_fs.c | 108 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/mod_dav_fs.dsp | 152 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/modules.mk | 3 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/repos.c | 2130 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/fs/repos.h | 78 |
12 files changed, 0 insertions, 5041 deletions
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/.deps b/rubbos/app/httpd-2.0.64/modules/dav/fs/.deps deleted file mode 100644 index e69de29b..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/.deps +++ /dev/null diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/Makefile b/rubbos/app/httpd-2.0.64/modules/dav/fs/Makefile deleted file mode 100644 index 11144e34..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -top_srcdir = /bottlenecks/rubbos/app/httpd-2.0.64 -top_builddir = /bottlenecks/rubbos/app/httpd-2.0.64 -srcdir = /bottlenecks/rubbos/app/httpd-2.0.64/modules/dav/fs -builddir = /bottlenecks/rubbos/app/httpd-2.0.64/modules/dav/fs -VPATH = /bottlenecks/rubbos/app/httpd-2.0.64/modules/dav/fs -# a modules Makefile has no explicit targets -- they will be defined by -# whatever modules are enabled. just grab special.mk to deal with this. -include $(top_srcdir)/build/special.mk diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/Makefile.in b/rubbos/app/httpd-2.0.64/modules/dav/fs/Makefile.in deleted file mode 100644 index 7c5c149d..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/Makefile.in +++ /dev/null @@ -1,3 +0,0 @@ -# a modules Makefile has no explicit targets -- they will be defined by -# whatever modules are enabled. just grab special.mk to deal with this. -include $(top_srcdir)/build/special.mk diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/NWGNUmakefile b/rubbos/app/httpd-2.0.64/modules/dav/fs/NWGNUmakefile deleted file mode 100644 index 1569be42..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/NWGNUmakefile +++ /dev/null @@ -1,266 +0,0 @@ -# -# Declare the sub-directories to be built here -# - -SUBDIRS = \ - $(EOLIST) - -# -# Get the 'head' of the build environment. This includes default targets and -# paths to tools -# - -include $(AP_WORK)\build\NWGNUhead.inc - -# -# build this level's files - -# -# Make sure all needed macro's are defined -# - -# -# These directories will be at the beginning of the include list, followed by -# INCDIRS -# -XINCDIRS += \ - $(APR)/include \ - $(APRUTIL)/include \ - $(AP_WORK)/include \ - $(AP_WORK)/modules/dav/main \ - $(AP_WORK)/server/mpm/NetWare \ - $(NWOS) \ - $(EOLIST) - -# -# These flags will come after CFLAGS -# -XCFLAGS += \ - $(EOLIST) - -# -# These defines will come after DEFINES -# -XDEFINES += \ - $(EOLIST) - -# -# These flags will be added to the link.opt file -# -XLFLAGS += \ - $(EOLIST) - -# -# These values will be appended to the correct variables based on the value of -# RELEASE -# -ifeq "$(RELEASE)" "debug" -XINCDIRS += \ - $(EOLIST) - -XCFLAGS += \ - $(EOLIST) - -XDEFINES += \ - $(EOLIST) - -XLFLAGS += \ - $(EOLIST) -endif - -ifeq "$(RELEASE)" "noopt" -XINCDIRS += \ - $(EOLIST) - -XCFLAGS += \ - $(EOLIST) - -XDEFINES += \ - $(EOLIST) - -XLFLAGS += \ - $(EOLIST) -endif - -ifeq "$(RELEASE)" "release" -XINCDIRS += \ - $(EOLIST) - -XCFLAGS += \ - $(EOLIST) - -XDEFINES += \ - $(EOLIST) - -XLFLAGS += \ - $(EOLIST) -endif - -# -# These are used by the link target if an NLM is being generated -# This is used by the link 'name' directive to name the nlm. If left blank -# TARGET_nlm (see below) will be used. -# -NLM_NAME = modDAVFS - -# -# This is used by the link '-desc ' directive. -# If left blank, NLM_NAME will be used. -# -NLM_DESCRIPTION = Apache $(VERSION_STR) DAV FileSystem Sub-Module - -# -# This is used by the '-threadname' directive. If left blank, -# NLM_NAME Thread will be used. -# -NLM_THREAD_NAME = modDAVFS Thread - -# -# If this is specified, it will override VERSION value in -# $(AP_WORK)\build\NWGNUenvironment.inc -# -NLM_VERSION = - -# -# If this is specified, it will override the default of 64K -# -NLM_STACK_SIZE = 65536 - - -# -# If this is specified it will be used by the link '-entry' directive -# -NLM_ENTRY_SYM = _LibCPrelude - -# -# If this is specified it will be used by the link '-exit' directive -# -NLM_EXIT_SYM = _LibCPostlude - -# -# If this is specified it will be used by the link '-check' directive -# -NLM_CHECK_SYM = - -# -# If this is specified it will be used by the link '-flags' directive -# -NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION - -# -# Declare all target files (you must add your files here) -# - -# -# If there is an NLM target, put it here -# -TARGET_nlm = \ - $(OBJDIR)/moddavfs.nlm \ - $(EOLIST) - -# -# If there is an LIB target, put it here -# -TARGET_lib = \ - $(EOLIST) - -# -# These are the OBJ files needed to create the NLM target above. -# Paths must all use the '/' character -# -FILES_nlm_objs = \ - $(OBJDIR)/mod_dav_fs.o \ - $(OBJDIR)/dbm.o \ - $(OBJDIR)/lock.o \ - $(OBJDIR)/repos.o \ - $(OBJDIR)/libprews.o \ - $(EOLIST) - -# -# These are the LIB files needed to create the NLM target above. -# These will be added as a library command in the link.opt file. -# -FILES_nlm_libs = \ - libcpre.o \ - $(EOLIST) - -# -# These are the modules that the above NLM target depends on to load. -# These will be added as a module command in the link.opt file. -# -FILES_nlm_modules = \ - Apache2 \ - Libc \ - mod_dav \ - $(EOLIST) - -# -# If the nlm has a msg file, put it's path here -# -FILE_nlm_msg = - -# -# If the nlm has a hlp file put it's path here -# -FILE_nlm_hlp = - -# -# If this is specified, it will override $(NWOS)\copyright.txt. -# -FILE_nlm_copyright = - -# -# Any additional imports go here -# -FILES_nlm_Ximports = \ - @libc.imp \ - @$(APR)/aprlib.imp \ - @httpd.imp \ - @ws2nlm.imp \ - @../main/dav.imp \ - $(EOLIST) - -# -# Any symbols exported to here -# -FILES_nlm_exports = \ - dav_fs_module \ - $(EOLIST) - -# -# These are the OBJ files needed to create the LIB target above. -# Paths must all use the '/' character -# -FILES_lib_objs = \ - $(EOLIST) - -# -# implement targets and dependancies (leave this section alone) -# - -libs :: $(OBJDIR) $(TARGET_lib) - -nlms :: libs $(TARGET_nlm) - -# -# Updated this target to create necessary directories and copy files to the -# correct place. (See $(AP_WORK)\build\NWGNUhead.inc for examples) -# -install :: nlms FORCE - copy $(OBJDIR)\moddavfs.nlm $(INSTALL)\Apache2\modules -# -# Any specialized rules here -# - -$(OBJDIR)/%.o: ../../arch/netware/%.c $(OBJDIR)\$(NLM_NAME)_cc.opt - @echo compiling $< - $(CC) $< -o=$(OBJDIR)\$(@F) @$(OBJDIR)\$(NLM_NAME)_cc.opt - -# -# Include the 'tail' makefile that has targets that depend on variables defined -# in this makefile -# - -include $(AP_WORK)\build\NWGNUtail.inc - - diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/config6.m4 b/rubbos/app/httpd-2.0.64/modules/dav/fs/config6.m4 deleted file mode 100644 index 515111cd..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/config6.m4 +++ /dev/null @@ -1,23 +0,0 @@ -dnl modules enabled in this directory by default - -APACHE_MODPATH_INIT(dav/fs) - -dav_fs_objects="mod_dav_fs.lo dbm.lo lock.lo repos.lo" - -if test "x$enable_dav" != "x"; then - dav_fs_enable=$enable_dav -else - dav_fs_enable=$dav_enable -fi - -case "$host" in - *os2*) - # OS/2 DLLs must resolve all symbols at build time - # and we need some from main DAV module - dav_fs_objects="$dav_fs_objects ../main/mod_dav.la" - ;; -esac - -APACHE_MODULE(dav_fs, DAV provider for the filesystem, $dav_fs_objects, , $dav_fs_enable) - -APACHE_MODPATH_FINISH 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 */ -}; diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/lock.c b/rubbos/app/httpd-2.0.64/modules/dav/fs/lock.c deleted file mode 100644 index 20780e15..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/lock.c +++ /dev/null @@ -1,1517 +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 filesystem lock implementation -*/ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_file_io.h" -#include "apr_uuid.h" - -#define APR_WANT_MEMFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_log.h" - -#include "mod_dav.h" -#include "repos.h" - - -/* --------------------------------------------------------------- -** -** Lock database primitives -** -*/ - -/* -** LOCK DATABASES -** -** Lockdiscovery information is stored in the single lock database specified -** by the DAVLockDB directive. Information about this db is stored in the -** global server configuration. -** -** KEY -** -** The database is keyed by a key_type unsigned char (DAV_TYPE_INODE or -** DAV_TYPE_FNAME) followed by inode and device number if possible, -** otherwise full path (in the case of Win32 or lock-null resources). -** -** VALUE -** -** The value consists of a list of elements. -** DIRECT LOCK: [char (DAV_LOCK_DIRECT), -** char (dav_lock_scope), -** char (dav_lock_type), -** int depth, -** time_t expires, -** apr_uuid_t locktoken, -** char[] owner, -** char[] auth_user] -** -** INDIRECT LOCK: [char (DAV_LOCK_INDIRECT), -** apr_uuid_t locktoken, -** time_t expires, -** apr_size_t key_size, -** char[] key] -** The key is to the collection lock that resulted in this indirect lock -*/ - -#define DAV_TRUE 1 -#define DAV_FALSE 0 - -#define DAV_CREATE_LIST 23 -#define DAV_APPEND_LIST 24 - -/* Stored lock_discovery prefix */ -#define DAV_LOCK_DIRECT 1 -#define DAV_LOCK_INDIRECT 2 - -#define DAV_TYPE_INODE 10 -#define DAV_TYPE_FNAME 11 - - -/* ack. forward declare. */ -static dav_error * dav_fs_remove_locknull_member(apr_pool_t *p, - const char *filename, - dav_buffer *pbuf); - -/* -** Use the opaquelock scheme for locktokens -*/ -struct dav_locktoken { - apr_uuid_t uuid; -}; -#define dav_compare_locktoken(plt1, plt2) \ - memcmp(&(plt1)->uuid, &(plt2)->uuid, sizeof((plt1)->uuid)) - - -/* ################################################################# -** ### keep these structures (internal) or move fully to dav_lock? -*/ - -/* -** We need to reliably size the fixed-length portion of -** dav_lock_discovery; best to separate it into another -** struct for a convenient sizeof, unless we pack lock_discovery. -*/ -typedef struct dav_lock_discovery_fixed -{ - char scope; - char type; - int depth; - time_t timeout; -} dav_lock_discovery_fixed; - -typedef struct dav_lock_discovery -{ - struct dav_lock_discovery_fixed f; - - dav_locktoken *locktoken; - const char *owner; /* owner field from activelock */ - const char *auth_user; /* authenticated user who created the lock */ - struct dav_lock_discovery *next; -} dav_lock_discovery; - -/* Indirect locks represent locks inherited from containing collections. - * They reference the lock token for the collection the lock is - * inherited from. A lock provider may also define a key to the - * inherited lock, for fast datbase lookup. The key is opaque outside - * the lock provider. - */ -typedef struct dav_lock_indirect -{ - dav_locktoken *locktoken; - apr_datum_t key; - struct dav_lock_indirect *next; - time_t timeout; -} dav_lock_indirect; - -/* ################################################################# */ - - -/* -** Stored direct lock info - full lock_discovery length: -** prefix + Fixed length + lock token + 2 strings + 2 nulls (one for each string) -*/ -#define dav_size_direct(a) (1 + sizeof(dav_lock_discovery_fixed) \ - + sizeof(apr_uuid_t) \ - + ((a)->owner ? strlen((a)->owner) : 0) \ - + ((a)->auth_user ? strlen((a)->auth_user) : 0) \ - + 2) - -/* Stored indirect lock info - lock token and apr_datum_t */ -#define dav_size_indirect(a) (1 + sizeof(apr_uuid_t) \ - + sizeof(time_t) \ - + sizeof((a)->key.dsize) + (a)->key.dsize) - -/* -** The lockdb structure. -** -** The <db> field may be NULL, meaning one of two things: -** 1) That we have not actually opened the underlying database (yet). The -** <opened> field should be false. -** 2) We opened it readonly and it wasn't present. -** -** The delayed opening (determined by <opened>) makes creating a lockdb -** quick, while deferring the underlying I/O until it is actually required. -** -** We export the notion of a lockdb, but hide the details of it. Most -** implementations will use a database of some kind, but it is certainly -** possible that alternatives could be used. -*/ -struct dav_lockdb_private -{ - request_rec *r; /* for accessing the uuid state */ - apr_pool_t *pool; /* a pool to use */ - const char *lockdb_path; /* where is the lock database? */ - - int opened; /* we opened the database */ - dav_db *db; /* if non-NULL, the lock database */ -}; -typedef struct -{ - dav_lockdb pub; - dav_lockdb_private priv; -} dav_lockdb_combined; - -/* -** The private part of the lock structure. -*/ -struct dav_lock_private -{ - apr_datum_t key; /* key into the lock database */ -}; -typedef struct -{ - dav_lock pub; - dav_lock_private priv; - dav_locktoken token; -} dav_lock_combined; - -/* -** This must be forward-declared so the open_lockdb function can use it. -*/ -extern const dav_hooks_locks dav_hooks_locks_fs; - - -/* internal function for creating locks */ -static dav_lock *dav_fs_alloc_lock(dav_lockdb *lockdb, apr_datum_t key, - const dav_locktoken *locktoken) -{ - dav_lock_combined *comb; - - comb = apr_pcalloc(lockdb->info->pool, sizeof(*comb)); - comb->pub.rectype = DAV_LOCKREC_DIRECT; - comb->pub.info = &comb->priv; - comb->priv.key = key; - - if (locktoken == NULL) { - comb->pub.locktoken = &comb->token; - apr_uuid_get(&comb->token.uuid); - } - else { - comb->pub.locktoken = locktoken; - } - - return &comb->pub; -} - -/* -** dav_fs_parse_locktoken -** -** Parse an opaquelocktoken URI into a locktoken. -*/ -static dav_error * dav_fs_parse_locktoken( - apr_pool_t *p, - const char *char_token, - dav_locktoken **locktoken_p) -{ - dav_locktoken *locktoken; - - if (ap_strstr_c(char_token, "opaquelocktoken:") != char_token) { - return dav_new_error(p, - HTTP_BAD_REQUEST, DAV_ERR_LOCK_UNK_STATE_TOKEN, - "The lock token uses an unknown State-token " - "format and could not be parsed."); - } - char_token += 16; - - locktoken = apr_pcalloc(p, sizeof(*locktoken)); - if (apr_uuid_parse(&locktoken->uuid, char_token)) { - return dav_new_error(p, HTTP_BAD_REQUEST, DAV_ERR_LOCK_PARSE_TOKEN, - "The opaquelocktoken has an incorrect format " - "and could not be parsed."); - } - - *locktoken_p = locktoken; - return NULL; -} - -/* -** dav_fs_format_locktoken -** -** Generate the URI for a locktoken -*/ -static const char *dav_fs_format_locktoken( - apr_pool_t *p, - const dav_locktoken *locktoken) -{ - char buf[APR_UUID_FORMATTED_LENGTH + 1]; - - apr_uuid_format(buf, &locktoken->uuid); - return apr_pstrcat(p, "opaquelocktoken:", buf, NULL); -} - -/* -** dav_fs_compare_locktoken -** -** Determine whether two locktokens are the same -*/ -static int dav_fs_compare_locktoken( - const dav_locktoken *lt1, - const dav_locktoken *lt2) -{ - return dav_compare_locktoken(lt1, lt2); -} - -/* -** dav_fs_really_open_lockdb: -** -** If the database hasn't been opened yet, then open the thing. -*/ -static dav_error * dav_fs_really_open_lockdb(dav_lockdb *lockdb) -{ - dav_error *err; - - if (lockdb->info->opened) - return NULL; - - err = dav_dbm_open_direct(lockdb->info->pool, - lockdb->info->lockdb_path, - lockdb->ro, - &lockdb->info->db); - if (err != NULL) { - return dav_push_error(lockdb->info->pool, - HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_LOCK_OPENDB, - "Could not open the lock database.", - err); - } - - /* all right. it is opened now. */ - lockdb->info->opened = 1; - - return NULL; -} - -/* -** dav_fs_open_lockdb: -** -** "open" the lock database, as specified in the global server configuration. -** If force is TRUE, then the database is opened now, rather than lazily. -** -** Note that only one can be open read/write. -*/ -static dav_error * dav_fs_open_lockdb(request_rec *r, int ro, int force, - dav_lockdb **lockdb) -{ - dav_lockdb_combined *comb; - - comb = apr_pcalloc(r->pool, sizeof(*comb)); - comb->pub.hooks = &dav_hooks_locks_fs; - comb->pub.ro = ro; - comb->pub.info = &comb->priv; - comb->priv.r = r; - comb->priv.pool = r->pool; - - comb->priv.lockdb_path = dav_get_lockdb_path(r); - if (comb->priv.lockdb_path == NULL) { - return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_LOCK_NO_DB, - "A lock database was not specified with the " - "DAVLockDB directive. One must be specified " - "to use the locking functionality."); - } - - /* done initializing. return it. */ - *lockdb = &comb->pub; - - if (force) { - /* ### add a higher-level comment? */ - return dav_fs_really_open_lockdb(*lockdb); - } - - return NULL; -} - -/* -** dav_fs_close_lockdb: -** -** Close it. Duh. -*/ -static void dav_fs_close_lockdb(dav_lockdb *lockdb) -{ - if (lockdb->info->db != NULL) - dav_dbm_close(lockdb->info->db); -} - -/* -** dav_fs_build_fname_key -** -** Given a pathname, build a DAV_TYPE_FNAME lock database key. -*/ -static apr_datum_t dav_fs_build_fname_key(apr_pool_t *p, const char *pathname) -{ - apr_datum_t key; - - /* ### does this allocation have a proper lifetime? need to check */ - /* ### can we use a buffer for this? */ - - /* size is TYPE + pathname + null */ - key.dsize = strlen(pathname) + 2; - key.dptr = apr_palloc(p, key.dsize); - *key.dptr = DAV_TYPE_FNAME; - memcpy(key.dptr + 1, pathname, key.dsize - 1); - if (key.dptr[key.dsize - 2] == '/') - key.dptr[--key.dsize - 1] = '\0'; - return key; -} - -/* -** dav_fs_build_key: Given a resource, return a apr_datum_t key -** to look up lock information for this file. -** -** (inode/dev not supported or file is lock-null): -** apr_datum_t->dvalue = full path -** -** (inode/dev supported and file exists ): -** apr_datum_t->dvalue = inode, dev -*/ -static apr_datum_t dav_fs_build_key(apr_pool_t *p, - const dav_resource *resource) -{ - const char *file = dav_fs_pathname(resource); - apr_datum_t key; - apr_finfo_t finfo; - apr_status_t rv; - - /* ### use lstat() ?? */ - /* - * XXX: What for platforms with no IDENT (dev/inode)? - */ - rv = apr_stat(&finfo, file, APR_FINFO_IDENT, p); - if ((rv == APR_SUCCESS || rv == APR_INCOMPLETE) - && ((finfo.valid & APR_FINFO_IDENT) == APR_FINFO_IDENT)) - { - /* ### can we use a buffer for this? */ - key.dsize = 1 + sizeof(finfo.inode) + sizeof(finfo.device); - key.dptr = apr_palloc(p, key.dsize); - *key.dptr = DAV_TYPE_INODE; - memcpy(key.dptr + 1, &finfo.inode, sizeof(finfo.inode)); - memcpy(key.dptr + 1 + sizeof(finfo.inode), &finfo.device, - sizeof(finfo.device)); - - return key; - } - - return dav_fs_build_fname_key(p, file); -} - -/* -** dav_fs_lock_expired: return 1 (true) if the given timeout is in the past -** or present (the lock has expired), or 0 (false) if in the future -** (the lock has not yet expired). -*/ -static int dav_fs_lock_expired(time_t expires) -{ - return expires != DAV_TIMEOUT_INFINITE && time(NULL) >= expires; -} - -/* -** dav_fs_save_lock_record: Saves the lock information specified in the -** direct and indirect lock lists about path into the lock database. -** If direct and indirect == NULL, the key is removed. -*/ -static dav_error * dav_fs_save_lock_record(dav_lockdb *lockdb, apr_datum_t key, - dav_lock_discovery *direct, - dav_lock_indirect *indirect) -{ - dav_error *err; - apr_datum_t val = { 0 }; - char *ptr; - dav_lock_discovery *dp = direct; - dav_lock_indirect *ip = indirect; - -#if DAV_DEBUG - if (lockdb->ro) { - return dav_new_error(lockdb->info->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "INTERNAL DESIGN ERROR: the lockdb was opened " - "readonly, but an attempt to save locks was " - "performed."); - } -#endif - - if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) { - /* ### add a higher-level error? */ - return err; - } - - /* If nothing to save, delete key */ - if (dp == NULL && ip == NULL) { - /* don't fail if the key is not present */ - /* ### but what about other errors? */ - (void) dav_dbm_delete(lockdb->info->db, key); - return NULL; - } - - while(dp) { - val.dsize += dav_size_direct(dp); - dp = dp->next; - } - while(ip) { - val.dsize += dav_size_indirect(ip); - ip = ip->next; - } - - /* ### can this be apr_palloc() ? */ - /* ### hmmm.... investigate the use of a buffer here */ - ptr = val.dptr = apr_pcalloc(lockdb->info->pool, val.dsize); - dp = direct; - ip = indirect; - - while(dp) { - *ptr++ = DAV_LOCK_DIRECT; /* Direct lock - lock_discovery struct follows */ - memcpy(ptr, dp, sizeof(dp->f)); /* Fixed portion of struct */ - ptr += sizeof(dp->f); - memcpy(ptr, dp->locktoken, sizeof(*dp->locktoken)); - ptr += sizeof(*dp->locktoken); - if (dp->owner == NULL) { - *ptr++ = '\0'; - } - else { - memcpy(ptr, dp->owner, strlen(dp->owner) + 1); - ptr += strlen(dp->owner) + 1; - } - if (dp->auth_user == NULL) { - *ptr++ = '\0'; - } - else { - memcpy(ptr, dp->auth_user, strlen(dp->auth_user) + 1); - ptr += strlen(dp->auth_user) + 1; - } - - dp = dp->next; - } - - while(ip) { - *ptr++ = DAV_LOCK_INDIRECT; /* Indirect lock prefix */ - memcpy(ptr, ip->locktoken, sizeof(*ip->locktoken)); /* Locktoken */ - ptr += sizeof(*ip->locktoken); - memcpy(ptr, &ip->timeout, sizeof(ip->timeout)); /* Expire time */ - ptr += sizeof(ip->timeout); - memcpy(ptr, &ip->key.dsize, sizeof(ip->key.dsize)); /* Size of key */ - ptr += sizeof(ip->key.dsize); - memcpy(ptr, ip->key.dptr, ip->key.dsize); /* Key data */ - ptr += ip->key.dsize; - ip = ip->next; - } - - if ((err = dav_dbm_store(lockdb->info->db, key, val)) != NULL) { - /* ### more details? add an error_id? */ - return dav_push_error(lockdb->info->pool, - HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_LOCK_SAVE_LOCK, - "Could not save lock information.", - err); - } - - return NULL; -} - -/* -** dav_load_lock_record: Reads lock information about key from lock db; -** creates linked lists of the direct and indirect locks. -** -** If add_method = DAV_APPEND_LIST, the result will be appended to the -** head of the direct and indirect lists supplied. -** -** Passive lock removal: If lock has timed out, it will not be returned. -** ### How much "logging" does RFC 2518 require? -*/ -static dav_error * dav_fs_load_lock_record(dav_lockdb *lockdb, apr_datum_t key, - int add_method, - dav_lock_discovery **direct, - dav_lock_indirect **indirect) -{ - apr_pool_t *p = lockdb->info->pool; - dav_error *err; - apr_size_t offset = 0; - int need_save = DAV_FALSE; - apr_datum_t val = { 0 }; - dav_lock_discovery *dp; - dav_lock_indirect *ip; - dav_buffer buf = { 0 }; - - if (add_method != DAV_APPEND_LIST) { - *direct = NULL; - *indirect = NULL; - } - - if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) { - /* ### add a higher-level error? */ - return err; - } - - /* - ** If we opened readonly and the db wasn't there, then there are no - ** locks for this resource. Just exit. - */ - if (lockdb->info->db == NULL) - return NULL; - - if ((err = dav_dbm_fetch(lockdb->info->db, key, &val)) != NULL) - return err; - - if (!val.dsize) - return NULL; - - while (offset < val.dsize) { - switch (*(val.dptr + offset++)) { - case DAV_LOCK_DIRECT: - /* Create and fill a dav_lock_discovery structure */ - - dp = apr_pcalloc(p, sizeof(*dp)); - memcpy(dp, val.dptr + offset, sizeof(dp->f)); - offset += sizeof(dp->f); - dp->locktoken = apr_palloc(p, sizeof(*dp->locktoken)); - memcpy(dp->locktoken, val.dptr + offset, sizeof(*dp->locktoken)); - offset += sizeof(*dp->locktoken); - if (*(val.dptr + offset) == '\0') { - ++offset; - } - else { - dp->owner = apr_pstrdup(p, val.dptr + offset); - offset += strlen(dp->owner) + 1; - } - - if (*(val.dptr + offset) == '\0') { - ++offset; - } - else { - dp->auth_user = apr_pstrdup(p, val.dptr + offset); - offset += strlen(dp->auth_user) + 1; - } - - if (!dav_fs_lock_expired(dp->f.timeout)) { - dp->next = *direct; - *direct = dp; - } - else { - need_save = DAV_TRUE; - - /* Remove timed-out locknull fm .locknull list */ - if (*key.dptr == DAV_TYPE_FNAME) { - const char *fname = key.dptr + 1; - apr_finfo_t finfo; - apr_status_t rv; - - /* if we don't see the file, then it's a locknull */ - rv = apr_lstat(&finfo, fname, APR_FINFO_MIN, p); - if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) { - if ((err = dav_fs_remove_locknull_member(p, fname, &buf)) != NULL) { - /* ### push a higher-level description? */ - return err; - } - } - } - } - break; - - case DAV_LOCK_INDIRECT: - /* Create and fill a dav_lock_indirect structure */ - - ip = apr_pcalloc(p, sizeof(*ip)); - ip->locktoken = apr_palloc(p, sizeof(*ip->locktoken)); - memcpy(ip->locktoken, val.dptr + offset, sizeof(*ip->locktoken)); - offset += sizeof(*ip->locktoken); - memcpy(&ip->timeout, val.dptr + offset, sizeof(ip->timeout)); - offset += sizeof(ip->timeout); - memcpy(&ip->key.dsize, val.dptr + offset, sizeof(ip->key.dsize)); /* length of datum */ - offset += sizeof(ip->key.dsize); - ip->key.dptr = apr_palloc(p, ip->key.dsize); - memcpy(ip->key.dptr, val.dptr + offset, ip->key.dsize); - offset += ip->key.dsize; - - if (!dav_fs_lock_expired(ip->timeout)) { - ip->next = *indirect; - *indirect = ip; - } - else { - need_save = DAV_TRUE; - /* A locknull resource will never be locked indirectly */ - } - - break; - - default: - dav_dbm_freedatum(lockdb->info->db, val); - - /* ### should use a computed_desc and insert corrupt token data */ - --offset; - return dav_new_error(p, - HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_LOCK_CORRUPT_DB, - apr_psprintf(p, - "The lock database was found to " - "be corrupt. offset %" - APR_SIZE_T_FMT ", c=%02x", - offset, val.dptr[offset])); - } - } - - dav_dbm_freedatum(lockdb->info->db, val); - - /* Clean up this record if we found expired locks */ - /* - ** ### shouldn't do this if we've been opened READONLY. elide the - ** ### timed-out locks from the response, but don't save that info back - */ - if (need_save == DAV_TRUE) { - return dav_fs_save_lock_record(lockdb, key, *direct, *indirect); - } - - return NULL; -} - -/* resolve <indirect>, returning <*direct> */ -static dav_error * dav_fs_resolve(dav_lockdb *lockdb, - dav_lock_indirect *indirect, - dav_lock_discovery **direct, - dav_lock_discovery **ref_dp, - dav_lock_indirect **ref_ip) -{ - dav_error *err; - dav_lock_discovery *dir; - dav_lock_indirect *ind; - - if ((err = dav_fs_load_lock_record(lockdb, indirect->key, - DAV_CREATE_LIST, - &dir, &ind)) != NULL) { - /* ### insert a higher-level description? */ - return err; - } - if (ref_dp != NULL) { - *ref_dp = dir; - *ref_ip = ind; - } - - for (; dir != NULL; dir = dir->next) { - if (!dav_compare_locktoken(indirect->locktoken, dir->locktoken)) { - *direct = dir; - return NULL; - } - } - - /* No match found (but we should have found one!) */ - - /* ### use a different description and/or error ID? */ - return dav_new_error(lockdb->info->pool, - HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_LOCK_CORRUPT_DB, - "The lock database was found to be corrupt. " - "An indirect lock's direct lock could not " - "be found."); -} - -/* --------------------------------------------------------------- -** -** Property-related lock functions -** -*/ - -/* -** dav_fs_get_supportedlock: Returns a static string for all supportedlock -** properties. I think we save more returning a static string than -** constructing it every time, though it might look cleaner. -*/ -static const char *dav_fs_get_supportedlock(const dav_resource *resource) -{ - static const char supported[] = DEBUG_CR - "<D:lockentry>" DEBUG_CR - "<D:lockscope><D:exclusive/></D:lockscope>" DEBUG_CR - "<D:locktype><D:write/></D:locktype>" DEBUG_CR - "</D:lockentry>" DEBUG_CR - "<D:lockentry>" DEBUG_CR - "<D:lockscope><D:shared/></D:lockscope>" DEBUG_CR - "<D:locktype><D:write/></D:locktype>" DEBUG_CR - "</D:lockentry>" DEBUG_CR; - - return supported; -} - -/* --------------------------------------------------------------- -** -** General lock functions -** -*/ - -/* --------------------------------------------------------------- -** -** Functions dealing with lock-null resources -** -*/ - -/* -** dav_fs_load_locknull_list: Returns a dav_buffer dump of the locknull file -** for the given directory. -*/ -static dav_error * dav_fs_load_locknull_list(apr_pool_t *p, const char *dirpath, - dav_buffer *pbuf) -{ - apr_finfo_t finfo; - apr_file_t *file = NULL; - dav_error *err = NULL; - apr_size_t amt; - apr_status_t rv; - - dav_buffer_init(p, pbuf, dirpath); - - if (pbuf->buf[pbuf->cur_len - 1] == '/') - pbuf->buf[--pbuf->cur_len] = '\0'; - - dav_buffer_place(p, pbuf, "/" DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE); - - /* reset this in case we leave w/o reading into the buffer */ - pbuf->cur_len = 0; - - if (apr_file_open(&file, pbuf->buf, APR_READ | APR_BINARY, APR_OS_DEFAULT, - p) != APR_SUCCESS) { - return NULL; - } - - rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, file); - if (rv != APR_SUCCESS) { - err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(p, - "Opened but could not stat file %s", - pbuf->buf)); - goto loaderror; - } - - if (finfo.size != (apr_size_t)finfo.size) { - err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(p, - "Opened but rejected huge file %s", - pbuf->buf)); - goto loaderror; - } - - amt = (apr_size_t)finfo.size; - dav_set_bufsize(p, pbuf, amt); - if (apr_file_read(file, pbuf->buf, &amt) != APR_SUCCESS - || amt != finfo.size) { - err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(p, - "Failure reading locknull file " - "for %s", dirpath)); - - /* just in case the caller disregards the returned error */ - pbuf->cur_len = 0; - goto loaderror; - } - - loaderror: - apr_file_close(file); - return err; -} - -/* -** dav_fs_save_locknull_list: Saves contents of pbuf into the -** locknull file for dirpath. -*/ -static dav_error * dav_fs_save_locknull_list(apr_pool_t *p, const char *dirpath, - dav_buffer *pbuf) -{ - const char *pathname; - apr_file_t *file = NULL; - dav_error *err = NULL; - apr_size_t amt; - - if (pbuf->buf == NULL) - return NULL; - - dav_fs_ensure_state_dir(p, dirpath); - pathname = apr_pstrcat(p, - dirpath, - dirpath[strlen(dirpath) - 1] == '/' ? "" : "/", - DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE, - NULL); - - if (pbuf->cur_len == 0) { - /* delete the file if cur_len == 0 */ - if (apr_file_remove(pathname, p) != 0) { - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(p, - "Error removing %s", pathname)); - } - return NULL; - } - - if (apr_file_open(&file, pathname, - APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY, - APR_OS_DEFAULT, p) != APR_SUCCESS) { - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(p, - "Error opening %s for writing", - pathname)); - } - - amt = pbuf->cur_len; - if (apr_file_write(file, pbuf->buf, &amt) != APR_SUCCESS - || amt != pbuf->cur_len) { - err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - apr_psprintf(p, - "Error writing %" APR_SIZE_T_FMT - " bytes to %s", - pbuf->cur_len, pathname)); - } - - apr_file_close(file); - return err; -} - -/* -** dav_fs_remove_locknull_member: Removes filename from the locknull list -** for directory path. -*/ -static dav_error * dav_fs_remove_locknull_member(apr_pool_t *p, - const char *filename, - dav_buffer *pbuf) -{ - dav_error *err; - apr_size_t len; - apr_size_t scanlen; - char *scan; - const char *scanend; - char *dirpath = apr_pstrdup(p, filename); - char *fname = strrchr(dirpath, '/'); - int dirty = 0; - - if (fname != NULL) - *fname++ = '\0'; - else - fname = dirpath; - len = strlen(fname) + 1; - - if ((err = dav_fs_load_locknull_list(p, dirpath, pbuf)) != NULL) { - /* ### add a higher level description? */ - return err; - } - - for (scan = pbuf->buf, scanend = scan + pbuf->cur_len; - scan < scanend; - scan += scanlen) { - scanlen = strlen(scan) + 1; - if (len == scanlen && memcmp(fname, scan, scanlen) == 0) { - pbuf->cur_len -= scanlen; - memmove(scan, scan + scanlen, scanend - (scan + scanlen)); - dirty = 1; - break; - } - } - - if (dirty) { - if ((err = dav_fs_save_locknull_list(p, dirpath, pbuf)) != NULL) { - /* ### add a higher level description? */ - return err; - } - } - - return NULL; -} - -/* Note: used by dav_fs_repos.c */ -dav_error * dav_fs_get_locknull_members( - const dav_resource *resource, - dav_buffer *pbuf) -{ - const char *dirpath; - - /* ### should test this result value... */ - (void) dav_fs_dir_file_name(resource, &dirpath, NULL); - return dav_fs_load_locknull_list(dav_fs_pool(resource), dirpath, pbuf); -} - -/* ### fold into append_lock? */ -/* ### take an optional buf parameter? */ -static dav_error * dav_fs_add_locknull_state( - dav_lockdb *lockdb, - const dav_resource *resource) -{ - dav_buffer buf = { 0 }; - apr_pool_t *p = lockdb->info->pool; - const char *dirpath; - const char *fname; - dav_error *err; - - /* ### should test this result value... */ - (void) dav_fs_dir_file_name(resource, &dirpath, &fname); - - if ((err = dav_fs_load_locknull_list(p, dirpath, &buf)) != NULL) { - return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not load .locknull file.", err); - } - - dav_buffer_append(p, &buf, fname); - buf.cur_len++; /* we want the null-term here */ - - if ((err = dav_fs_save_locknull_list(p, dirpath, &buf)) != NULL) { - return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not save .locknull file.", err); - } - - return NULL; -} - -/* -** dav_fs_remove_locknull_state: Given a request, check to see if r->filename -** is/was a lock-null resource. If so, return it to an existant state. -** -** ### this function is broken... it doesn't check! -** -** In this implementation, this involves two things: -** (a) remove it from the list in the appropriate .DAV/locknull file -** (b) on *nix, convert the key from a filename to an inode. -*/ -static dav_error * dav_fs_remove_locknull_state( - dav_lockdb *lockdb, - const dav_resource *resource) -{ - dav_buffer buf = { 0 }; - dav_error *err; - apr_pool_t *p = lockdb->info->pool; - const char *pathname = dav_fs_pathname(resource); - - if ((err = dav_fs_remove_locknull_member(p, pathname, &buf)) != NULL) { - /* ### add a higher-level description? */ - return err; - } - - { - dav_lock_discovery *ld; - dav_lock_indirect *id; - apr_datum_t key; - - /* - ** Fetch the lock(s) that made the resource lock-null. Remove - ** them under the filename key. Obtain the new inode key, and - ** save the same lock information under it. - */ - key = dav_fs_build_fname_key(p, pathname); - if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST, - &ld, &id)) != NULL) { - /* ### insert a higher-level error description */ - return err; - } - - if ((err = dav_fs_save_lock_record(lockdb, key, NULL, NULL)) != NULL) { - /* ### insert a higher-level error description */ - return err; - } - - key = dav_fs_build_key(p, resource); - if ((err = dav_fs_save_lock_record(lockdb, key, ld, id)) != NULL) { - /* ### insert a higher-level error description */ - return err; - } - } - - return NULL; -} - -static dav_error * dav_fs_create_lock(dav_lockdb *lockdb, - const dav_resource *resource, - dav_lock **lock) -{ - apr_datum_t key; - - key = dav_fs_build_key(lockdb->info->pool, resource); - - *lock = dav_fs_alloc_lock(lockdb, - key, - NULL); - - (*lock)->is_locknull = !resource->exists; - - return NULL; -} - -static dav_error * dav_fs_get_locks(dav_lockdb *lockdb, - const dav_resource *resource, - int calltype, - dav_lock **locks) -{ - apr_pool_t *p = lockdb->info->pool; - apr_datum_t key; - dav_error *err; - dav_lock *lock = NULL; - dav_lock *newlock; - dav_lock_discovery *dp; - dav_lock_indirect *ip; - -#if DAV_DEBUG - if (calltype == DAV_GETLOCKS_COMPLETE) { - return dav_new_error(lockdb->info->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "INTERNAL DESIGN ERROR: DAV_GETLOCKS_COMPLETE " - "is not yet supported"); - } -#endif - - key = dav_fs_build_key(p, resource); - if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST, - &dp, &ip)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - - /* copy all direct locks to the result list */ - for (; dp != NULL; dp = dp->next) { - newlock = dav_fs_alloc_lock(lockdb, key, dp->locktoken); - newlock->is_locknull = !resource->exists; - newlock->scope = dp->f.scope; - newlock->type = dp->f.type; - newlock->depth = dp->f.depth; - newlock->timeout = dp->f.timeout; - newlock->owner = dp->owner; - newlock->auth_user = dp->auth_user; - - /* hook into the result list */ - newlock->next = lock; - lock = newlock; - } - - /* copy all the indirect locks to the result list. resolve as needed. */ - for (; ip != NULL; ip = ip->next) { - newlock = dav_fs_alloc_lock(lockdb, ip->key, ip->locktoken); - newlock->is_locknull = !resource->exists; - - if (calltype == DAV_GETLOCKS_RESOLVED) { - if ((err = dav_fs_resolve(lockdb, ip, &dp, NULL, NULL)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - - newlock->scope = dp->f.scope; - newlock->type = dp->f.type; - newlock->depth = dp->f.depth; - newlock->timeout = dp->f.timeout; - newlock->owner = dp->owner; - newlock->auth_user = dp->auth_user; - } - else { - /* DAV_GETLOCKS_PARTIAL */ - newlock->rectype = DAV_LOCKREC_INDIRECT_PARTIAL; - } - - /* hook into the result list */ - newlock->next = lock; - lock = newlock; - } - - *locks = lock; - return NULL; -} - -static dav_error * dav_fs_find_lock(dav_lockdb *lockdb, - const dav_resource *resource, - const dav_locktoken *locktoken, - int partial_ok, - dav_lock **lock) -{ - dav_error *err; - apr_datum_t key; - dav_lock_discovery *dp; - dav_lock_indirect *ip; - - *lock = NULL; - - key = dav_fs_build_key(lockdb->info->pool, resource); - if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST, - &dp, &ip)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - - for (; dp != NULL; dp = dp->next) { - if (!dav_compare_locktoken(locktoken, dp->locktoken)) { - *lock = dav_fs_alloc_lock(lockdb, key, locktoken); - (*lock)->is_locknull = !resource->exists; - (*lock)->scope = dp->f.scope; - (*lock)->type = dp->f.type; - (*lock)->depth = dp->f.depth; - (*lock)->timeout = dp->f.timeout; - (*lock)->owner = dp->owner; - (*lock)->auth_user = dp->auth_user; - return NULL; - } - } - - for (; ip != NULL; ip = ip->next) { - if (!dav_compare_locktoken(locktoken, ip->locktoken)) { - *lock = dav_fs_alloc_lock(lockdb, ip->key, locktoken); - (*lock)->is_locknull = !resource->exists; - - /* ### nobody uses the resolving right now! */ - if (partial_ok) { - (*lock)->rectype = DAV_LOCKREC_INDIRECT_PARTIAL; - } - else { - (*lock)->rectype = DAV_LOCKREC_INDIRECT; - if ((err = dav_fs_resolve(lockdb, ip, &dp, - NULL, NULL)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - (*lock)->scope = dp->f.scope; - (*lock)->type = dp->f.type; - (*lock)->depth = dp->f.depth; - (*lock)->timeout = dp->f.timeout; - (*lock)->owner = dp->owner; - (*lock)->auth_user = dp->auth_user; - } - return NULL; - } - } - - return NULL; -} - -static dav_error * dav_fs_has_locks(dav_lockdb *lockdb, - const dav_resource *resource, - int *locks_present) -{ - dav_error *err; - apr_datum_t key; - - *locks_present = 0; - - if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) { - /* ### insert a higher-level error description */ - return err; - } - - /* - ** If we opened readonly and the db wasn't there, then there are no - ** locks for this resource. Just exit. - */ - if (lockdb->info->db == NULL) - return NULL; - - key = dav_fs_build_key(lockdb->info->pool, resource); - - *locks_present = dav_dbm_exists(lockdb->info->db, key); - - return NULL; -} - -static dav_error * dav_fs_append_locks(dav_lockdb *lockdb, - const dav_resource *resource, - int make_indirect, - const dav_lock *lock) -{ - apr_pool_t *p = lockdb->info->pool; - dav_error *err; - dav_lock_indirect *ip; - dav_lock_discovery *dp; - apr_datum_t key; - - key = dav_fs_build_key(lockdb->info->pool, resource); - if ((err = dav_fs_load_lock_record(lockdb, key, 0, &dp, &ip)) != NULL) { - /* ### maybe add in a higher-level description */ - return err; - } - - /* - ** ### when we store the lock more directly, we need to update - ** ### lock->rectype and lock->is_locknull - */ - - if (make_indirect) { - for (; lock != NULL; lock = lock->next) { - - /* ### this works for any <lock> rectype */ - dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi)); - - /* ### shut off the const warning for now */ - newi->locktoken = (dav_locktoken *)lock->locktoken; - newi->timeout = lock->timeout; - newi->key = lock->info->key; - newi->next = ip; - ip = newi; - } - } - else { - for (; lock != NULL; lock = lock->next) { - /* create and link in the right kind of lock */ - - if (lock->rectype == DAV_LOCKREC_DIRECT) { - dav_lock_discovery *newd = apr_pcalloc(p, sizeof(*newd)); - - newd->f.scope = lock->scope; - newd->f.type = lock->type; - newd->f.depth = lock->depth; - newd->f.timeout = lock->timeout; - /* ### shut off the const warning for now */ - newd->locktoken = (dav_locktoken *)lock->locktoken; - newd->owner = lock->owner; - newd->auth_user = lock->auth_user; - newd->next = dp; - dp = newd; - } - else { - /* DAV_LOCKREC_INDIRECT(_PARTIAL) */ - - dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi)); - - /* ### shut off the const warning for now */ - newi->locktoken = (dav_locktoken *)lock->locktoken; - newi->key = lock->info->key; - newi->next = ip; - ip = newi; - } - } - } - - if ((err = dav_fs_save_lock_record(lockdb, key, dp, ip)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - - /* we have a special list for recording locknull resources */ - /* ### ack! this can add two copies to the locknull list */ - if (!resource->exists - && (err = dav_fs_add_locknull_state(lockdb, resource)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - - return NULL; -} - -static dav_error * dav_fs_remove_lock(dav_lockdb *lockdb, - const dav_resource *resource, - const dav_locktoken *locktoken) -{ - dav_error *err; - dav_buffer buf = { 0 }; - dav_lock_discovery *dh = NULL; - dav_lock_indirect *ih = NULL; - apr_datum_t key; - - key = dav_fs_build_key(lockdb->info->pool, resource); - - if (locktoken != NULL) { - dav_lock_discovery *dp; - dav_lock_discovery *dprev = NULL; - dav_lock_indirect *ip; - dav_lock_indirect *iprev = NULL; - - if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST, - &dh, &ih)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - - for (dp = dh; dp != NULL; dp = dp->next) { - if (dav_compare_locktoken(locktoken, dp->locktoken) == 0) { - if (dprev) - dprev->next = dp->next; - else - dh = dh->next; - } - dprev = dp; - } - - for (ip = ih; ip != NULL; ip = ip->next) { - if (dav_compare_locktoken(locktoken, ip->locktoken) == 0) { - if (iprev) - iprev->next = ip->next; - else - ih = ih->next; - } - iprev = ip; - } - - } - - /* save the modified locks, or remove all locks (dh=ih=NULL). */ - if ((err = dav_fs_save_lock_record(lockdb, key, dh, ih)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - - /* - ** If this resource is a locknull resource AND no more locks exist, - ** then remove the locknull member. - ** - ** Note: remove_locknull_state() attempts to convert a locknull member - ** to a real member. In this case, all locks are gone, so the - ** locknull resource returns to the null state (ie. doesn't exist), - ** so there is no need to update the lockdb (and it won't find - ** any because a precondition is that none exist). - */ - if (!resource->exists && dh == NULL && ih == NULL - && (err = dav_fs_remove_locknull_member(lockdb->info->pool, - dav_fs_pathname(resource), - &buf)) != NULL) { - /* ### maybe add a higher-level description */ - return err; - } - - return NULL; -} - -static int dav_fs_do_refresh(dav_lock_discovery *dp, - const dav_locktoken_list *ltl, - time_t new_time) -{ - int dirty = 0; - - for (; ltl != NULL; ltl = ltl->next) { - if (dav_compare_locktoken(dp->locktoken, ltl->locktoken) == 0) - { - dp->f.timeout = new_time; - dirty = 1; - } - } - - return dirty; -} - -static dav_error * dav_fs_refresh_locks(dav_lockdb *lockdb, - const dav_resource *resource, - const dav_locktoken_list *ltl, - time_t new_time, - dav_lock **locks) -{ - dav_error *err; - apr_datum_t key; - dav_lock_discovery *dp; - dav_lock_discovery *dp_scan; - dav_lock_indirect *ip; - int dirty = 0; - dav_lock *newlock; - - *locks = NULL; - - key = dav_fs_build_key(lockdb->info->pool, resource); - if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST, - &dp, &ip)) != NULL) { - /* ### maybe add in a higher-level description */ - return err; - } - - /* ### we should be refreshing direct AND (resolved) indirect locks! */ - - /* refresh all of the direct locks on this resource */ - for (dp_scan = dp; dp_scan != NULL; dp_scan = dp_scan->next) { - if (dav_fs_do_refresh(dp_scan, ltl, new_time)) { - /* the lock was refreshed. return the lock. */ - newlock = dav_fs_alloc_lock(lockdb, key, dp_scan->locktoken); - newlock->is_locknull = !resource->exists; - newlock->scope = dp_scan->f.scope; - newlock->type = dp_scan->f.type; - newlock->depth = dp_scan->f.depth; - newlock->timeout = dp_scan->f.timeout; - newlock->owner = dp_scan->owner; - newlock->auth_user = dp_scan->auth_user; - - newlock->next = *locks; - *locks = newlock; - - dirty = 1; - } - } - - /* if we refreshed any locks, then save them back. */ - if (dirty - && (err = dav_fs_save_lock_record(lockdb, key, dp, ip)) != NULL) { - /* ### maybe add in a higher-level description */ - return err; - } - - /* for each indirect lock, find its direct lock and refresh it. */ - for (; ip != NULL; ip = ip->next) { - dav_lock_discovery *ref_dp; - dav_lock_indirect *ref_ip; - - if ((err = dav_fs_resolve(lockdb, ip, &dp_scan, - &ref_dp, &ref_ip)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - if (dav_fs_do_refresh(dp_scan, ltl, new_time)) { - /* the lock was refreshed. return the lock. */ - newlock = dav_fs_alloc_lock(lockdb, ip->key, dp_scan->locktoken); - newlock->is_locknull = !resource->exists; - newlock->scope = dp_scan->f.scope; - newlock->type = dp_scan->f.type; - newlock->depth = dp_scan->f.depth; - newlock->timeout = dp_scan->f.timeout; - newlock->owner = dp_scan->owner; - newlock->auth_user = dp_scan->auth_user; - - newlock->next = *locks; - *locks = newlock; - - /* save the (resolved) direct lock back */ - if ((err = dav_fs_save_lock_record(lockdb, ip->key, ref_dp, - ref_ip)) != NULL) { - /* ### push a higher-level desc? */ - return err; - } - } - } - - return NULL; -} - - -const dav_hooks_locks dav_hooks_locks_fs = -{ - dav_fs_get_supportedlock, - dav_fs_parse_locktoken, - dav_fs_format_locktoken, - dav_fs_compare_locktoken, - dav_fs_open_lockdb, - dav_fs_close_lockdb, - dav_fs_remove_locknull_state, - dav_fs_create_lock, - dav_fs_get_locks, - dav_fs_find_lock, - dav_fs_has_locks, - dav_fs_append_locks, - dav_fs_remove_lock, - dav_fs_refresh_locks, - NULL, /* lookup_resource */ - - NULL /* ctx */ -}; diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/mod_dav_fs.c b/rubbos/app/httpd-2.0.64/modules/dav/fs/mod_dav_fs.c deleted file mode 100644 index dfd190b3..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/mod_dav_fs.c +++ /dev/null @@ -1,108 +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. - */ - -#include "httpd.h" -#include "http_config.h" -#include "apr_strings.h" - -#include "mod_dav.h" -#include "repos.h" - -/* per-server configuration */ -typedef struct { - const char *lockdb_path; - -} dav_fs_server_conf; - -extern module AP_MODULE_DECLARE_DATA dav_fs_module; - -const char *dav_get_lockdb_path(const request_rec *r) -{ - dav_fs_server_conf *conf; - - conf = ap_get_module_config(r->server->module_config, &dav_fs_module); - return conf->lockdb_path; -} - -static void *dav_fs_create_server_config(apr_pool_t *p, server_rec *s) -{ - return apr_pcalloc(p, sizeof(dav_fs_server_conf)); -} - -static void *dav_fs_merge_server_config(apr_pool_t *p, - void *base, void *overrides) -{ - dav_fs_server_conf *parent = base; - dav_fs_server_conf *child = overrides; - dav_fs_server_conf *newconf; - - newconf = apr_pcalloc(p, sizeof(*newconf)); - - newconf->lockdb_path = - child->lockdb_path ? child->lockdb_path : parent->lockdb_path; - - return newconf; -} - -/* - * Command handler for the DAVLockDB directive, which is TAKE1 - */ -static const char *dav_fs_cmd_davlockdb(cmd_parms *cmd, void *config, - const char *arg1) -{ - dav_fs_server_conf *conf; - conf = ap_get_module_config(cmd->server->module_config, - &dav_fs_module); - conf->lockdb_path = ap_server_root_relative(cmd->pool, arg1); - - if (!conf->lockdb_path) { - return apr_pstrcat(cmd->pool, "Invalid DAVLockDB path ", - arg1, NULL); - } - - return NULL; -} - -static const command_rec dav_fs_cmds[] = -{ - /* per server */ - AP_INIT_TAKE1("DAVLockDB", dav_fs_cmd_davlockdb, NULL, RSRC_CONF, - "specify a lock database"), - - { NULL } -}; - -static void register_hooks(apr_pool_t *p) -{ - dav_hook_gather_propsets(dav_fs_gather_propsets, NULL, NULL, - APR_HOOK_MIDDLE); - dav_hook_find_liveprop(dav_fs_find_liveprop, NULL, NULL, APR_HOOK_MIDDLE); - dav_hook_insert_all_liveprops(dav_fs_insert_all_liveprops, NULL, NULL, - APR_HOOK_MIDDLE); - - dav_fs_register(p); -} - -module AP_MODULE_DECLARE_DATA dav_fs_module = -{ - STANDARD20_MODULE_STUFF, - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - dav_fs_create_server_config, /* server config */ - dav_fs_merge_server_config, /* merge server config */ - dav_fs_cmds, /* command table */ - register_hooks, /* register hooks */ -}; diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/mod_dav_fs.dsp b/rubbos/app/httpd-2.0.64/modules/dav/fs/mod_dav_fs.dsp deleted file mode 100644 index 5c2239c9..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/mod_dav_fs.dsp +++ /dev/null @@ -1,152 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_dav_fs" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_dav_fs - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_dav_fs.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_dav_fs.mak" CFG="mod_dav_fs - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_dav_fs - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_dav_fs - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_dav_fs - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_dav_fs_src" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:"Release/mod_dav_fs.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav_fs.so -# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Release/mod_dav_fs.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav_fs.so /opt:ref - -!ELSEIF "$(CFG)" == "mod_dav_fs - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_dav_fs_src" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_dav_fs.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav_fs.so -# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_dav_fs.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav_fs.so - -!ENDIF - -# Begin Target - -# Name "mod_dav_fs - Win32 Release" -# Name "mod_dav_fs - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" -# Begin Source File - -SOURCE=.\dbm.c -# End Source File -# Begin Source File - -SOURCE=.\lock.c -# End Source File -# Begin Source File - -SOURCE=.\mod_dav_fs.c -# End Source File -# Begin Source File - -SOURCE=.\repos.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" -# Begin Source File - -SOURCE=.\repos.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\mod_dav_fs.rc -# End Source File -# Begin Source File - -SOURCE=..\..\..\build\win32\win32ver.awk - -!IF "$(CFG)" == "mod_dav_fs - Win32 Release" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build - Creating Version Resource -InputPath=..\..\..\build\win32\win32ver.awk - -".\mod_dav_fs.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - awk -f ../../../build/win32/win32ver.awk mod_dav_fs.so "dav_fs_module for Apache" ../../../include/ap_release.h > .\mod_dav_fs.rc - -# End Custom Build - -!ELSEIF "$(CFG)" == "mod_dav_fs - Win32 Debug" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build - Creating Version Resource -InputPath=..\..\..\build\win32\win32ver.awk - -".\mod_dav_fs.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - awk -f ../../../build/win32/win32ver.awk mod_dav_fs.so "dav_fs_module for Apache" ../../../include/ap_release.h > .\mod_dav_fs.rc - -# End Custom Build - -!ENDIF - -# End Source File -# End Target -# End Project diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/modules.mk b/rubbos/app/httpd-2.0.64/modules/dav/fs/modules.mk deleted file mode 100644 index ceb52a1b..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/modules.mk +++ /dev/null @@ -1,3 +0,0 @@ -DISTCLEAN_TARGETS = modules.mk -static = -shared = diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/repos.c b/rubbos/app/httpd-2.0.64/modules/dav/fs/repos.c deleted file mode 100644 index bf8da8d0..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/repos.c +++ /dev/null @@ -1,2130 +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 filesystem-based repository provider -*/ - -#include "apr.h" -#include "apr_file_io.h" -#include "apr_strings.h" -#include "apr_buckets.h" - -#if APR_HAVE_STDIO_H -#include <stdio.h> /* for sprintf() */ -#endif - -#include "httpd.h" -#include "http_log.h" -#include "http_protocol.h" /* for ap_set_* (in dav_fs_set_headers) */ -#include "http_request.h" /* for ap_update_mtime() */ - -#include "mod_dav.h" -#include "repos.h" - - -/* to assist in debugging mod_dav's GET handling */ -#define DEBUG_GET_HANDLER 0 - -#define DAV_FS_COPY_BLOCKSIZE 16384 /* copy 16k at a time */ - -/* context needed to identify a resource */ -struct dav_resource_private { - apr_pool_t *pool; /* memory storage pool associated with request */ - const char *pathname; /* full pathname to resource */ - apr_finfo_t finfo; /* filesystem info */ -}; - -/* private context for doing a filesystem walk */ -typedef struct { - /* the input walk parameters */ - const dav_walk_params *params; - - /* reused as we walk */ - dav_walk_resource wres; - - dav_resource res1; - dav_resource_private info1; - dav_buffer path1; - dav_buffer uri_buf; - - /* MOVE/COPY need a secondary path */ - dav_resource res2; - dav_resource_private info2; - dav_buffer path2; - - dav_buffer locknull_buf; - -} dav_fs_walker_context; - -typedef struct { - int is_move; /* is this a MOVE? */ - dav_buffer work_buf; /* handy buffer for copymove_file() */ - - /* CALLBACK: this is a secondary resource managed specially for us */ - const dav_resource *res_dst; - - /* copied from dav_walk_params (they are invariant across the walk) */ - const dav_resource *root; - apr_pool_t *pool; - -} dav_fs_copymove_walk_ctx; - -/* an internal WALKTYPE to walk hidden files (the .DAV directory) */ -#define DAV_WALKTYPE_HIDDEN 0x4000 - -/* an internal WALKTYPE to call collections (again) after their contents */ -#define DAV_WALKTYPE_POSTFIX 0x8000 - -#define DAV_CALLTYPE_POSTFIX 1000 /* a private call type */ - - -/* pull this in from the other source file */ -extern const dav_hooks_locks dav_hooks_locks_fs; - -/* 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 -** stay in sync. -*/ -static const char * const dav_fs_namespace_uris[] = -{ - "DAV:", - "http://apache.org/dav/props/", - - NULL /* sentinel */ -}; -enum { - DAV_FS_URI_DAV, /* the DAV: namespace URI */ - DAV_FS_URI_MYPROPS /* the namespace URI for our custom props */ -}; - -/* -** Does this platform support an executable flag? -** -** ### need a way to portably abstract this query -*/ -#ifndef WIN32 -#define DAV_FS_HAS_EXECUTABLE -#endif - -/* -** The single property that we define (in the DAV_FS_URI_MYPROPS namespace) -*/ -#define DAV_PROPID_FS_executable 1 - -static const dav_liveprop_spec dav_fs_props[] = -{ - /* standard DAV properties */ - { - 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 - }, - - /* our custom properties */ - { - DAV_FS_URI_MYPROPS, - "executable", - DAV_PROPID_FS_executable, - 0 /* handled special in dav_fs_is_writable */ - }, - - { 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 { - apr_pool_t *p; - apr_file_t *f; - const char *pathname; /* we may need to remove it at close time */ -}; - -/* returns an appropriate HTTP status code given an APR status code for a - * failed I/O operation. ### use something besides 500? */ -#define MAP_IO2HTTP(e) (APR_STATUS_IS_ENOSPC(e) ? HTTP_INSUFFICIENT_STORAGE : \ - HTTP_INTERNAL_SERVER_ERROR) - -/* forward declaration for internal treewalkers */ -static dav_error * dav_fs_walk(const dav_walk_params *params, int depth, - dav_response **response); -static dav_error * dav_fs_internal_walk(const dav_walk_params *params, - int depth, int is_move, - const dav_resource *root_dst, - dav_response **response); - -/* -------------------------------------------------------------------- -** -** PRIVATE REPOSITORY FUNCTIONS -*/ -apr_pool_t *dav_fs_pool(const dav_resource *resource) -{ - return resource->info->pool; -} - -const char *dav_fs_pathname(const dav_resource *resource) -{ - return resource->info->pathname; -} - -dav_error * dav_fs_dir_file_name( - const dav_resource *resource, - const char **dirpath_p, - const char **fname_p) -{ - dav_resource_private *ctx = resource->info; - - if (resource->collection) { - *dirpath_p = ctx->pathname; - if (fname_p != NULL) - *fname_p = NULL; - } - else { - const char *testpath, *rootpath; - char *dirpath = ap_make_dirstr_parent(ctx->pool, ctx->pathname); - apr_size_t dirlen = strlen(dirpath); - apr_status_t rv = APR_SUCCESS; - - testpath = dirpath; - if (dirlen > 0) { - rv = apr_filepath_root(&rootpath, &testpath, 0, ctx->pool); - } - - /* remove trailing slash from dirpath, unless it's a root path - */ - if ((rv == APR_SUCCESS && testpath && *testpath) - || rv == APR_ERELATIVE) { - if (dirpath[dirlen - 1] == '/') { - dirpath[dirlen - 1] = '\0'; - } - } - - /* ###: Looks like a response could be appropriate - * - * APR_SUCCESS here tells us the dir is a root - * APR_ERELATIVE told us we had no root (ok) - * APR_EINCOMPLETE an incomplete testpath told us - * there was no -file- name here! - * APR_EBADPATH or other errors tell us this file - * path is undecipherable - */ - - if (rv == APR_SUCCESS || rv == APR_ERELATIVE) { - *dirpath_p = dirpath; - if (fname_p != NULL) - *fname_p = ctx->pathname + dirlen; - } - else { - return dav_new_error(ctx->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "An incomplete/bad path was found in " - "dav_fs_dir_file_name."); - } - } - - return NULL; -} - -/* Note: picked up from ap_gm_timestr_822() */ -/* NOTE: buf must be at least DAV_TIMEBUF_SIZE chars in size */ -static void dav_format_time(int style, apr_time_t sec, char *buf) -{ - apr_time_exp_t tms; - - /* ### what to do if fails? */ - (void) apr_time_exp_gmt(&tms, sec); - - if (style == DAV_STYLE_ISO8601) { - /* ### should we use "-00:00" instead of "Z" ?? */ - - /* 20 chars plus null term */ - sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ", - tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday, - tms.tm_hour, tms.tm_min, tms.tm_sec); - return; - } - - /* RFC 822 date format; as strftime '%a, %d %b %Y %T GMT' */ - - /* 29 chars plus null term */ - sprintf(buf, - "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", - apr_day_snames[tms.tm_wday], - tms.tm_mday, apr_month_snames[tms.tm_mon], - tms.tm_year + 1900, - tms.tm_hour, tms.tm_min, tms.tm_sec); -} - -static dav_error * dav_fs_copymove_file( - int is_move, - apr_pool_t * p, - const char *src, - const char *dst, - dav_buffer *pbuf) -{ - dav_buffer work_buf = { 0 }; - apr_file_t *inf = NULL; - apr_file_t *outf = NULL; - apr_status_t status; - - if (pbuf == NULL) - pbuf = &work_buf; - - dav_set_bufsize(p, pbuf, DAV_FS_COPY_BLOCKSIZE); - - if ((apr_file_open(&inf, src, APR_READ | APR_BINARY, APR_OS_DEFAULT, p)) - != APR_SUCCESS) { - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not open file for reading"); - } - - /* ### do we need to deal with the umask? */ - status = apr_file_open(&outf, dst, APR_WRITE | APR_CREATE | APR_TRUNCATE - | APR_BINARY, APR_OS_DEFAULT, p); - if (status != APR_SUCCESS) { - apr_file_close(inf); - - return dav_new_error(p, MAP_IO2HTTP(status), 0, - "Could not open file for writing"); - } - - while (1) { - apr_size_t len = DAV_FS_COPY_BLOCKSIZE; - - status = apr_file_read(inf, pbuf->buf, &len); - if (status != APR_SUCCESS && status != APR_EOF) { - apr_file_close(inf); - apr_file_close(outf); - - if (apr_file_remove(dst, p) != APR_SUCCESS) { - /* ### ACK! Inconsistent state... */ - - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not delete output after read " - "failure. Server is now in an " - "inconsistent state."); - } - - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not read input file"); - } - - if (status == APR_EOF) - break; - - /* write any bytes that were read */ - status = apr_file_write_full(outf, pbuf->buf, len, NULL); - if (status != APR_SUCCESS) { - apr_file_close(inf); - apr_file_close(outf); - - if (apr_file_remove(dst, p) != APR_SUCCESS) { - /* ### ACK! Inconsistent state... */ - - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not delete output after write " - "failure. Server is now in an " - "inconsistent state."); - } - - return dav_new_error(p, MAP_IO2HTTP(status), 0, - "Could not write output file"); - } - } - - apr_file_close(inf); - apr_file_close(outf); - - if (is_move && apr_file_remove(src, p) != APR_SUCCESS) { - dav_error *err; - int save_errno = errno; /* save the errno that got us here */ - - if (apr_file_remove(dst, p) != APR_SUCCESS) { - /* ### ACK. this creates an inconsistency. do more!? */ - - /* ### use something besides 500? */ - /* Note that we use the latest errno */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not remove source or destination " - "file. Server is now in an inconsistent " - "state."); - } - - /* ### use something besides 500? */ - err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not remove source file after move. " - "Destination was removed to ensure consistency."); - err->save_errno = save_errno; - return err; - } - - return NULL; -} - -/* copy/move a file from within a state dir to another state dir */ -/* ### need more buffers to replace the pool argument */ -static dav_error * dav_fs_copymove_state( - int is_move, - apr_pool_t * p, - const char *src_dir, const char *src_file, - const char *dst_dir, const char *dst_file, - dav_buffer *pbuf) -{ - apr_finfo_t src_finfo; /* finfo for source file */ - apr_finfo_t dst_state_finfo; /* finfo for STATE directory */ - apr_status_t rv; - const char *src; - const char *dst; - - /* build the propset pathname for the source file */ - src = apr_pstrcat(p, src_dir, "/" DAV_FS_STATE_DIR "/", src_file, NULL); - - /* the source file doesn't exist */ - rv = apr_stat(&src_finfo, src, APR_FINFO_NORM, p); - if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) { - return NULL; - } - - /* build the pathname for the destination state dir */ - dst = apr_pstrcat(p, dst_dir, "/" DAV_FS_STATE_DIR, NULL); - - /* ### do we need to deal with the umask? */ - - /* ensure that it exists */ - rv = apr_dir_make(dst, APR_OS_DEFAULT, p); - if (rv != APR_SUCCESS) { - if (!APR_STATUS_IS_EEXIST(rv)) { - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not create internal state directory"); - } - } - - /* get info about the state directory */ - rv = apr_stat(&dst_state_finfo, dst, APR_FINFO_NORM, p); - if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) { - /* Ack! Where'd it go? */ - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "State directory disappeared"); - } - - /* The mkdir() may have failed because a *file* exists there already */ - if (dst_state_finfo.filetype != APR_DIR) { - /* ### try to recover by deleting this file? (and mkdir again) */ - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "State directory is actually a file"); - } - - /* append the target file to the state directory pathname */ - dst = apr_pstrcat(p, dst, "/", dst_file, NULL); - - /* copy/move the file now */ - if (is_move && src_finfo.device == dst_state_finfo.device) { - /* simple rename is possible since it is on the same device */ - if (apr_file_rename(src, dst, p) != APR_SUCCESS) { - /* ### use something besides 500? */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not move state file."); - } - } - else - { - /* gotta copy (and delete) */ - return dav_fs_copymove_file(is_move, p, src, dst, pbuf); - } - - return NULL; -} - -static dav_error *dav_fs_copymoveset(int is_move, apr_pool_t *p, - const dav_resource *src, - const dav_resource *dst, - dav_buffer *pbuf) -{ - const char *src_dir; - const char *src_file; - const char *src_state1; - const char *src_state2; - const char *dst_dir; - const char *dst_file; - const char *dst_state1; - const char *dst_state2; - dav_error *err; - - /* Get directory and filename for resources */ - /* ### should test these result values... */ - (void) dav_fs_dir_file_name(src, &src_dir, &src_file); - (void) dav_fs_dir_file_name(dst, &dst_dir, &dst_file); - - /* Get the corresponding state files for each resource */ - dav_dbm_get_statefiles(p, src_file, &src_state1, &src_state2); - dav_dbm_get_statefiles(p, dst_file, &dst_state1, &dst_state2); -#if DAV_DEBUG - if ((src_state2 != NULL && dst_state2 == NULL) || - (src_state2 == NULL && dst_state2 != NULL)) { - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "DESIGN ERROR: dav_dbm_get_statefiles() " - "returned inconsistent results."); - } -#endif - - err = dav_fs_copymove_state(is_move, p, - src_dir, src_state1, - dst_dir, dst_state1, - pbuf); - - if (err == NULL && src_state2 != NULL) { - err = dav_fs_copymove_state(is_move, p, - src_dir, src_state2, - dst_dir, dst_state2, - pbuf); - - if (err != NULL) { - /* ### CRAP. inconsistency. */ - /* ### should perform some cleanup at the target if we still - ### have the original files */ - - /* Change the error to reflect the bad server state. */ - err->status = HTTP_INTERNAL_SERVER_ERROR; - err->desc = - "Could not fully copy/move the properties. " - "The server is now in an inconsistent state."; - } - } - - return err; -} - -static dav_error *dav_fs_deleteset(apr_pool_t *p, const dav_resource *resource) -{ - const char *dirpath; - const char *fname; - const char *state1; - const char *state2; - const char *pathname; - apr_status_t status; - - /* Get directory, filename, and state-file names for the resource */ - /* ### should test this result value... */ - (void) dav_fs_dir_file_name(resource, &dirpath, &fname); - dav_dbm_get_statefiles(p, fname, &state1, &state2); - - /* build the propset pathname for the file */ - pathname = apr_pstrcat(p, - dirpath, - "/" DAV_FS_STATE_DIR "/", - state1, - NULL); - - /* note: we may get ENOENT if the state dir is not present */ - if ((status = apr_file_remove(pathname, p)) != APR_SUCCESS - && !APR_STATUS_IS_ENOENT(status)) { - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not remove properties."); - } - - if (state2 != NULL) { - /* build the propset pathname for the file */ - pathname = apr_pstrcat(p, - dirpath, - "/" DAV_FS_STATE_DIR "/", - state2, - NULL); - - if ((status = apr_file_remove(pathname, p)) != APR_SUCCESS - && !APR_STATUS_IS_ENOENT(status)) { - /* ### CRAP. only removed half. */ - return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not fully remove properties. " - "The server is now in an inconsistent " - "state."); - } - } - - return NULL; -} - -/* -------------------------------------------------------------------- -** -** REPOSITORY HOOK FUNCTIONS -*/ - -static dav_error * dav_fs_get_resource( - request_rec *r, - const char *root_dir, - const char *label, - int use_checked_in, - dav_resource **result_resource) -{ - dav_resource_private *ctx; - dav_resource *resource; - char *s; - char *filename; - apr_size_t len; - - /* ### optimize this into a single allocation! */ - - /* Create private resource context descriptor */ - ctx = apr_pcalloc(r->pool, sizeof(*ctx)); - ctx->finfo = r->finfo; - - /* ### this should go away */ - ctx->pool = r->pool; - - /* Preserve case on OSes which fold canonical filenames */ -#if 0 - /* ### not available in Apache 2.0 yet */ - filename = r->case_preserved_filename; -#else - filename = r->filename; -#endif - - /* - ** If there is anything in the path_info, then this indicates that the - ** entire path was not used to specify the file/dir. We want to append - ** it onto the filename so that we get a "valid" pathname for null - ** resources. - */ - s = apr_pstrcat(r->pool, filename, r->path_info, NULL); - - /* make sure the pathname does not have a trailing "/" */ - len = strlen(s); - if (len > 1 && s[len - 1] == '/') { - s[len - 1] = '\0'; - } - ctx->pathname = s; - - /* Create resource descriptor */ - resource = apr_pcalloc(r->pool, sizeof(*resource)); - resource->type = DAV_RESOURCE_TYPE_REGULAR; - resource->info = ctx; - resource->hooks = &dav_hooks_repository_fs; - resource->pool = r->pool; - - /* make sure the URI does not have a trailing "/" */ - len = strlen(r->uri); - if (len > 1 && r->uri[len - 1] == '/') { - s = apr_pstrdup(r->pool, r->uri); - s[len - 1] = '\0'; - resource->uri = s; - } - else { - resource->uri = r->uri; - } - - if (r->finfo.filetype != 0) { - resource->exists = 1; - resource->collection = r->finfo.filetype == APR_DIR; - - /* unused info in the URL will indicate a null resource */ - - if (r->path_info != NULL && *r->path_info != '\0') { - if (resource->collection) { - /* only a trailing "/" is allowed */ - if (*r->path_info != '/' || r->path_info[1] != '\0') { - - /* - ** This URL/filename represents a locknull resource or - ** possibly a destination of a MOVE/COPY - */ - resource->exists = 0; - resource->collection = 0; - } - } - else - { - /* - ** The base of the path refers to a file -- nothing should - ** be in path_info. The resource is simply an error: it - ** can't be a null or a locknull resource. - */ - return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, - "The URL contains extraneous path " - "components. The resource could not " - "be identified."); - } - - /* retain proper integrity across the structures */ - if (!resource->exists) { - ctx->finfo.filetype = 0; - } - } - } - - *result_resource = resource; - return NULL; -} - -static dav_error * dav_fs_get_parent_resource(const dav_resource *resource, - dav_resource **result_parent) -{ - dav_resource_private *ctx = resource->info; - dav_resource_private *parent_ctx; - dav_resource *parent_resource; - apr_status_t rv; - char *dirpath; - const char *testroot; - const char *testpath; - - /* If we're at the root of the URL space, then there is no parent. */ - if (strcmp(resource->uri, "/") == 0) { - *result_parent = NULL; - return NULL; - } - - /* If given resource is root, then there is no parent. - * Unless we can retrieve the filepath root, this is - * intendend to fail. If we split the root and - * no path info remains, then we also fail. - */ - testpath = ctx->pathname; - rv = apr_filepath_root(&testroot, &testpath, 0, ctx->pool); - if ((rv != APR_SUCCESS && rv != APR_ERELATIVE) - || !testpath || !*testpath) { - *result_parent = NULL; - return NULL; - } - - /* ### optimize this into a single allocation! */ - - /* Create private resource context descriptor */ - parent_ctx = apr_pcalloc(ctx->pool, sizeof(*parent_ctx)); - - /* ### this should go away */ - parent_ctx->pool = ctx->pool; - - dirpath = ap_make_dirstr_parent(ctx->pool, ctx->pathname); - if (strlen(dirpath) > 1 && dirpath[strlen(dirpath) - 1] == '/') - dirpath[strlen(dirpath) - 1] = '\0'; - parent_ctx->pathname = dirpath; - - parent_resource = apr_pcalloc(ctx->pool, sizeof(*parent_resource)); - parent_resource->info = parent_ctx; - parent_resource->collection = 1; - parent_resource->hooks = &dav_hooks_repository_fs; - parent_resource->pool = resource->pool; - - if (resource->uri != NULL) { - char *uri = ap_make_dirstr_parent(ctx->pool, resource->uri); - if (strlen(uri) > 1 && uri[strlen(uri) - 1] == '/') - uri[strlen(uri) - 1] = '\0'; - parent_resource->uri = uri; - } - - rv = apr_stat(&parent_ctx->finfo, parent_ctx->pathname, - APR_FINFO_NORM, ctx->pool); - if (rv == APR_SUCCESS || rv == APR_INCOMPLETE) { - parent_resource->exists = 1; - } - - *result_parent = parent_resource; - return NULL; -} - -static int dav_fs_is_same_resource( - const dav_resource *res1, - const dav_resource *res2) -{ - dav_resource_private *ctx1 = res1->info; - dav_resource_private *ctx2 = res2->info; - - if (res1->hooks != res2->hooks) - return 0; - - if ((ctx1->finfo.filetype != 0) && (ctx2->finfo.filetype != 0) - && (ctx1->finfo.valid & ctx2->finfo.valid & APR_FINFO_INODE)) { - return ctx1->finfo.inode == ctx2->finfo.inode; - } - else { - return strcmp(ctx1->pathname, ctx2->pathname) == 0; - } -} - -static int dav_fs_is_parent_resource( - const dav_resource *res1, - const dav_resource *res2) -{ - dav_resource_private *ctx1 = res1->info; - dav_resource_private *ctx2 = res2->info; - apr_size_t len1 = strlen(ctx1->pathname); - apr_size_t len2; - - if (res1->hooks != res2->hooks) - return 0; - - /* it is safe to use ctx2 now */ - len2 = strlen(ctx2->pathname); - - return (len2 > len1 - && memcmp(ctx1->pathname, ctx2->pathname, len1) == 0 - && ctx2->pathname[len1] == '/'); -} - -static dav_error * dav_fs_open_stream(const dav_resource *resource, - dav_stream_mode mode, - dav_stream **stream) -{ - apr_pool_t *p = resource->info->pool; - dav_stream *ds = apr_pcalloc(p, sizeof(*ds)); - apr_int32_t flags; - apr_status_t rv; - - switch (mode) { - default: - flags = APR_READ | APR_BINARY; - break; - - case DAV_MODE_WRITE_TRUNC: - flags = APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY; - break; - case DAV_MODE_WRITE_SEEKABLE: - flags = APR_WRITE | APR_CREATE | APR_BINARY; - break; - } - - ds->p = p; - ds->pathname = resource->info->pathname; - rv = apr_file_open(&ds->f, ds->pathname, flags, APR_OS_DEFAULT, ds->p); - if (rv != APR_SUCCESS) { - return dav_new_error(p, MAP_IO2HTTP(rv), 0, - "An error occurred while opening a resource."); - } - - /* (APR registers cleanups for the fd with the pool) */ - - *stream = ds; - return NULL; -} - -static dav_error * dav_fs_close_stream(dav_stream *stream, int commit) -{ - apr_file_close(stream->f); - - if (!commit) { - if (apr_file_remove(stream->pathname, stream->p) != APR_SUCCESS) { - /* ### use a better description? */ - return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, - "There was a problem removing (rolling " - "back) the resource " - "when it was being closed."); - } - } - - return NULL; -} - -static dav_error * dav_fs_write_stream(dav_stream *stream, - const void *buf, apr_size_t bufsize) -{ - apr_status_t status; - - status = apr_file_write_full(stream->f, buf, bufsize, NULL); - if (APR_STATUS_IS_ENOSPC(status)) { - return dav_new_error(stream->p, HTTP_INSUFFICIENT_STORAGE, 0, - "There is not enough storage to write to " - "this resource."); - } - else if (status != APR_SUCCESS) { - /* ### use something besides 500? */ - return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, - "An error occurred while writing to a " - "resource."); - } - return NULL; -} - -static dav_error * dav_fs_seek_stream(dav_stream *stream, apr_off_t abs_pos) -{ - if (apr_file_seek(stream->f, APR_SET, &abs_pos) != APR_SUCCESS) { - /* ### should check whether apr_file_seek set abs_pos was set to the - * correct position? */ - /* ### use something besides 500? */ - return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not seek to specified position in the " - "resource."); - } - return NULL; -} - - -#if DEBUG_GET_HANDLER - -/* only define set_headers() and deliver() for debug purposes */ - - -static dav_error * dav_fs_set_headers(request_rec *r, - const dav_resource *resource) -{ - /* ### this function isn't really used since we have a get_pathname */ - if (!resource->exists) - return NULL; - - /* make sure the proper mtime is in the request record */ - ap_update_mtime(r, resource->info->finfo.mtime); - - /* ### note that these use r->filename rather than <resource> */ - ap_set_last_modified(r); - ap_set_etag(r); - - /* we accept byte-ranges */ - apr_table_setn(r->headers_out, "Accept-Ranges", "bytes"); - - /* set up the Content-Length header */ - ap_set_content_length(r, resource->info->finfo.size); - - /* ### how to set the content type? */ - /* ### until this is resolved, the Content-Type header is busted */ - - return NULL; -} - -static dav_error * dav_fs_deliver(const dav_resource *resource, - ap_filter_t *output) -{ - apr_pool_t *pool = resource->pool; - apr_bucket_brigade *bb; - apr_file_t *fd; - apr_status_t status; - apr_bucket *bkt; - - /* Check resource type */ - if (resource->type != DAV_RESOURCE_TYPE_REGULAR - && resource->type != DAV_RESOURCE_TYPE_VERSION - && resource->type != DAV_RESOURCE_TYPE_WORKING) { - return dav_new_error(pool, HTTP_CONFLICT, 0, - "Cannot GET this type of resource."); - } - if (resource->collection) { - return dav_new_error(pool, HTTP_CONFLICT, 0, - "There is no default response to GET for a " - "collection."); - } - - if ((status = apr_file_open(&fd, resource->info->pathname, - APR_READ | APR_BINARY, 0, - pool)) != APR_SUCCESS) { - return dav_new_error(pool, HTTP_FORBIDDEN, 0, - "File permissions deny server access."); - } - - bb = apr_brigade_create(pool, output->c->bucket_alloc); - - /* ### this does not handle large files. but this is test code anyway */ - bkt = apr_bucket_file_create(fd, 0, - (apr_size_t)resource->info->finfo.size, - pool, output->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, bkt); - - bkt = apr_bucket_eos_create(output->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, bkt); - - if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) { - return dav_new_error(pool, HTTP_FORBIDDEN, 0, - "Could not write contents to filter."); - } - - return NULL; -} - -#endif /* DEBUG_GET_HANDLER */ - - -static dav_error * dav_fs_create_collection(dav_resource *resource) -{ - dav_resource_private *ctx = resource->info; - apr_status_t status; - - status = apr_dir_make(ctx->pathname, APR_OS_DEFAULT, ctx->pool); - if (APR_STATUS_IS_ENOSPC(status)) { - return dav_new_error(ctx->pool, HTTP_INSUFFICIENT_STORAGE, 0, - "There is not enough storage to create " - "this collection."); - } - else if (APR_STATUS_IS_ENOENT(status)) { - return dav_new_error(ctx->pool, HTTP_CONFLICT, 0, - "Cannot create collection; intermediate " - "collection does not exist."); - } - else if (status != APR_SUCCESS) { - /* ### refine this error message? */ - return dav_new_error(ctx->pool, HTTP_FORBIDDEN, 0, - "Unable to create collection."); - } - - /* update resource state to show it exists as a collection */ - resource->exists = 1; - resource->collection = 1; - - return NULL; -} - -static dav_error * dav_fs_copymove_walker(dav_walk_resource *wres, - int calltype) -{ - dav_fs_copymove_walk_ctx *ctx = wres->walk_ctx; - dav_resource_private *srcinfo = wres->resource->info; - dav_resource_private *dstinfo = ctx->res_dst->info; - dav_error *err = NULL; - - if (wres->resource->collection) { - if (calltype == DAV_CALLTYPE_POSTFIX) { - /* Postfix call for MOVE. delete the source dir. - * Note: when copying, we do not enable the postfix-traversal. - */ - /* ### we are ignoring any error here; what should we do? */ - (void) apr_dir_remove(srcinfo->pathname, ctx->pool); - } - else { - /* copy/move of a collection. Create the new, target collection */ - if (apr_dir_make(dstinfo->pathname, APR_OS_DEFAULT, - ctx->pool) != APR_SUCCESS) { - /* ### assume it was a permissions problem */ - /* ### need a description here */ - err = dav_new_error(ctx->pool, HTTP_FORBIDDEN, 0, NULL); - } - } - } - else { - err = dav_fs_copymove_file(ctx->is_move, ctx->pool, - srcinfo->pathname, dstinfo->pathname, - &ctx->work_buf); - /* ### push a higher-level description? */ - } - - /* - ** If we have a "not so bad" error, then it might need to go into a - ** multistatus response. - ** - ** For a MOVE, it will always go into the multistatus. It could be - ** that everything has been moved *except* for the root. Using a - ** multistatus (with no errors for the other resources) will signify - ** this condition. - ** - ** For a COPY, we are traversing in a prefix fashion. If the root fails, - ** then we can just bail out now. - */ - if (err != NULL - && !ap_is_HTTP_SERVER_ERROR(err->status) - && (ctx->is_move - || !dav_fs_is_same_resource(wres->resource, ctx->root))) { - /* ### use errno to generate DAV:responsedescription? */ - dav_add_response(wres, err->status, NULL); - - /* the error is in the multistatus now. do not stop the traversal. */ - return NULL; - } - - return err; -} - -static dav_error *dav_fs_copymove_resource( - int is_move, - const dav_resource *src, - const dav_resource *dst, - int depth, - dav_response **response) -{ - dav_error *err = NULL; - dav_buffer work_buf = { 0 }; - - *response = NULL; - - /* if a collection, recursively copy/move it and its children, - * including the state dirs - */ - if (src->collection) { - dav_walk_params params = { 0 }; - dav_response *multi_status; - - params.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_HIDDEN; - params.func = dav_fs_copymove_walker; - params.pool = src->info->pool; - params.root = src; - - /* params.walk_ctx is managed by dav_fs_internal_walk() */ - - /* postfix is needed for MOVE to delete source dirs */ - if (is_move) - params.walk_type |= DAV_WALKTYPE_POSTFIX; - - /* note that we return the error OR the multistatus. never both */ - - if ((err = dav_fs_internal_walk(¶ms, depth, is_move, dst, - &multi_status)) != NULL) { - /* on a "real" error, then just punt. nothing else to do. */ - return err; - } - - if ((*response = multi_status) != NULL) { - /* some multistatus responses exist. wrap them in a 207 */ - return dav_new_error(src->info->pool, HTTP_MULTI_STATUS, 0, - "Error(s) occurred on some resources during " - "the COPY/MOVE process."); - } - - return NULL; - } - - /* not a collection */ - if ((err = dav_fs_copymove_file(is_move, src->info->pool, - src->info->pathname, dst->info->pathname, - &work_buf)) != NULL) { - /* ### push a higher-level description? */ - return err; - } - - /* copy/move properties as well */ - return dav_fs_copymoveset(is_move, src->info->pool, src, dst, &work_buf); -} - -static dav_error * dav_fs_copy_resource( - const dav_resource *src, - dav_resource *dst, - int depth, - dav_response **response) -{ - dav_error *err; - -#if DAV_DEBUG - if (src->hooks != dst->hooks) { - /* - ** ### strictly speaking, this is a design error; we should not - ** ### have reached this point. - */ - return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "DESIGN ERROR: a mix of repositories " - "was passed to copy_resource."); - } -#endif - - if ((err = dav_fs_copymove_resource(0, src, dst, depth, - response)) == NULL) { - - /* update state of destination resource to show it exists */ - dst->exists = 1; - dst->collection = src->collection; - } - - return err; -} - -static dav_error * dav_fs_move_resource( - dav_resource *src, - dav_resource *dst, - dav_response **response) -{ - dav_resource_private *srcinfo = src->info; - dav_resource_private *dstinfo = dst->info; - dav_error *err; - int can_rename = 0; - -#if DAV_DEBUG - if (src->hooks != dst->hooks) { - /* - ** ### strictly speaking, this is a design error; we should not - ** ### have reached this point. - */ - return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "DESIGN ERROR: a mix of repositories " - "was passed to move_resource."); - } -#endif - - /* determine whether a simple rename will work. - * Assume source exists, else we wouldn't get called. - */ - if (dstinfo->finfo.filetype != 0) { - if (dstinfo->finfo.device == srcinfo->finfo.device) { - /* target exists and is on the same device. */ - can_rename = 1; - } - } - else { - const char *dirpath; - apr_finfo_t finfo; - apr_status_t rv; - - /* destination does not exist, but the parent directory should, - * so try it - */ - dirpath = ap_make_dirstr_parent(dstinfo->pool, dstinfo->pathname); - /* - * XXX: If missing dev ... then what test? - * Really need a try and failover for those platforms. - * - */ - rv = apr_stat(&finfo, dirpath, APR_FINFO_DEV, dstinfo->pool); - if ((rv == APR_SUCCESS || rv == APR_INCOMPLETE) - && (finfo.valid & srcinfo->finfo.valid & APR_FINFO_DEV) - && (finfo.device == srcinfo->finfo.device)) { - can_rename = 1; - } - } - - /* if we can't simply rename, then do it the hard way... */ - if (!can_rename) { - if ((err = dav_fs_copymove_resource(1, src, dst, DAV_INFINITY, - response)) == NULL) { - /* update resource states */ - dst->exists = 1; - dst->collection = src->collection; - src->exists = 0; - src->collection = 0; - } - - return err; - } - - /* a rename should work. do it, and move properties as well */ - - /* no multistatus response */ - *response = NULL; - - /* ### APR has no rename? */ - if (apr_file_rename(srcinfo->pathname, dstinfo->pathname, - srcinfo->pool) != APR_SUCCESS) { - /* ### should have a better error than this. */ - return dav_new_error(srcinfo->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not rename resource."); - } - - /* update resource states */ - dst->exists = 1; - dst->collection = src->collection; - src->exists = 0; - src->collection = 0; - - if ((err = dav_fs_copymoveset(1, src->info->pool, - src, dst, NULL)) == NULL) { - /* no error. we're done. go ahead and return now. */ - return NULL; - } - - /* error occurred during properties move; try to put resource back */ - if (apr_file_rename(dstinfo->pathname, srcinfo->pathname, - srcinfo->pool) != APR_SUCCESS) { - /* couldn't put it back! */ - return dav_push_error(srcinfo->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "The resource was moved, but a failure " - "occurred during the move of its " - "properties. The resource could not be " - "restored to its original location. The " - "server is now in an inconsistent state.", - err); - } - - /* update resource states again */ - src->exists = 1; - src->collection = dst->collection; - dst->exists = 0; - dst->collection = 0; - - /* resource moved back, but properties may be inconsistent */ - return dav_push_error(srcinfo->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "The resource was moved, but a failure " - "occurred during the move of its properties. " - "The resource was moved back to its original " - "location, but its properties may have been " - "partially moved. The server may be in an " - "inconsistent state.", - err); -} - -static dav_error * dav_fs_delete_walker(dav_walk_resource *wres, int calltype) -{ - dav_resource_private *info = wres->resource->info; - - /* do not attempt to remove a null resource, - * or a collection with children - */ - if (wres->resource->exists && - (!wres->resource->collection || calltype == DAV_CALLTYPE_POSTFIX)) { - /* try to remove the resource */ - apr_status_t result; - - result = wres->resource->collection - ? apr_dir_remove(info->pathname, wres->pool) - : apr_file_remove(info->pathname, wres->pool); - - /* - ** If an error occurred, then add it to multistatus response. - ** Note that we add it for the root resource, too. It is quite - ** possible to delete the whole darn tree, yet fail on the root. - ** - ** (also: remember we are deleting via a postfix traversal) - */ - if (result != APR_SUCCESS) { - /* ### assume there is a permissions problem */ - - /* ### use errno to generate DAV:responsedescription? */ - dav_add_response(wres, HTTP_FORBIDDEN, NULL); - } - } - - return NULL; -} - -static dav_error * dav_fs_remove_resource(dav_resource *resource, - dav_response **response) -{ - dav_resource_private *info = resource->info; - - *response = NULL; - - /* if a collection, recursively remove it and its children, - * including the state dirs - */ - if (resource->collection) { - dav_walk_params params = { 0 }; - dav_error *err = NULL; - dav_response *multi_status; - - params.walk_type = (DAV_WALKTYPE_NORMAL - | DAV_WALKTYPE_HIDDEN - | DAV_WALKTYPE_POSTFIX); - params.func = dav_fs_delete_walker; - params.pool = info->pool; - params.root = resource; - - if ((err = dav_fs_walk(¶ms, DAV_INFINITY, - &multi_status)) != NULL) { - /* on a "real" error, then just punt. nothing else to do. */ - return err; - } - - if ((*response = multi_status) != NULL) { - /* some multistatus responses exist. wrap them in a 207 */ - return dav_new_error(info->pool, HTTP_MULTI_STATUS, 0, - "Error(s) occurred on some resources during " - "the deletion process."); - } - - /* no errors... update resource state */ - resource->exists = 0; - resource->collection = 0; - - return NULL; - } - - /* not a collection; remove the file and its properties */ - if (apr_file_remove(info->pathname, info->pool) != APR_SUCCESS) { - /* ### put a description in here */ - return dav_new_error(info->pool, HTTP_FORBIDDEN, 0, NULL); - } - - /* update resource state */ - resource->exists = 0; - resource->collection = 0; - - /* remove properties and return its result */ - return dav_fs_deleteset(info->pool, resource); -} - -/* ### move this to dav_util? */ -/* Walk recursively down through directories, * - * including lock-null resources as we go. */ -static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) -{ - const dav_walk_params *params = fsctx->params; - apr_pool_t *pool = params->pool; - dav_error *err = NULL; - int isdir = fsctx->res1.collection; - apr_finfo_t dirent; - apr_dir_t *dirp; - - /* ensure the context is prepared properly, then call the func */ - err = (*params->func)(&fsctx->wres, - isdir - ? DAV_CALLTYPE_COLLECTION - : DAV_CALLTYPE_MEMBER); - if (err != NULL) { - return err; - } - - if (depth == 0 || !isdir) { - return NULL; - } - - /* put a trailing slash onto the directory, in preparation for appending - * files to it as we discovery them within the directory */ - dav_check_bufsize(pool, &fsctx->path1, DAV_BUFFER_PAD); - fsctx->path1.buf[fsctx->path1.cur_len++] = '/'; - fsctx->path1.buf[fsctx->path1.cur_len] = '\0'; /* in pad area */ - - /* if a secondary path is present, then do that, too */ - if (fsctx->path2.buf != NULL) { - dav_check_bufsize(pool, &fsctx->path2, DAV_BUFFER_PAD); - fsctx->path2.buf[fsctx->path2.cur_len++] = '/'; - fsctx->path2.buf[fsctx->path2.cur_len] = '\0'; /* in pad area */ - } - - /* Note: the URI should ALREADY have a trailing "/" */ - - /* for this first pass of files, all resources exist */ - fsctx->res1.exists = 1; - - /* a file is the default; we'll adjust if we hit a directory */ - fsctx->res1.collection = 0; - fsctx->res2.collection = 0; - - /* open and scan the directory */ - if ((apr_dir_open(&dirp, fsctx->path1.buf, pool)) != APR_SUCCESS) { - /* ### need a better error */ - return dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL); - } - while ((apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp)) == APR_SUCCESS) { - apr_size_t len; - apr_status_t status; - - len = strlen(dirent.name); - - /* avoid recursing into our current, parent, or state directories */ - if (dirent.name[0] == '.' - && (len == 1 || (dirent.name[1] == '.' && len == 2))) { - continue; - } - - if (params->walk_type & DAV_WALKTYPE_AUTH) { - /* ### need to authorize each file */ - /* ### example: .htaccess is normally configured to fail auth */ - - /* stuff in the state directory is never authorized! */ - if (!strcmp(dirent.name, DAV_FS_STATE_DIR)) { - continue; - } - } - /* skip the state dir unless a HIDDEN is performed */ - if (!(params->walk_type & DAV_WALKTYPE_HIDDEN) - && !strcmp(dirent.name, DAV_FS_STATE_DIR)) { - continue; - } - - /* append this file onto the path buffer (copy null term) */ - dav_buffer_place_mem(pool, &fsctx->path1, dirent.name, len + 1, 0); - - - /* ### Optimize me, dirent can give us what we need! */ - status = apr_lstat(&fsctx->info1.finfo, fsctx->path1.buf, - APR_FINFO_NORM, pool); - if (status != APR_SUCCESS && status != APR_INCOMPLETE) { - /* woah! where'd it go? */ - /* ### should have a better error here */ - err = dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL); - break; - } - - /* copy the file to the URI, too. NOTE: we will pad an extra byte - for the trailing slash later. */ - dav_buffer_place_mem(pool, &fsctx->uri_buf, dirent.name, len + 1, 1); - - /* if there is a secondary path, then do that, too */ - if (fsctx->path2.buf != NULL) { - dav_buffer_place_mem(pool, &fsctx->path2, dirent.name, len + 1, 0); - } - - /* set up the (internal) pathnames for the two resources */ - fsctx->info1.pathname = fsctx->path1.buf; - fsctx->info2.pathname = fsctx->path2.buf; - - /* set up the URI for the current resource */ - fsctx->res1.uri = fsctx->uri_buf.buf; - - /* ### for now, only process regular files (e.g. skip symlinks) */ - if (fsctx->info1.finfo.filetype == APR_REG) { - /* call the function for the specified dir + file */ - if ((err = (*params->func)(&fsctx->wres, - DAV_CALLTYPE_MEMBER)) != NULL) { - /* ### maybe add a higher-level description? */ - break; - } - } - else if (fsctx->info1.finfo.filetype == APR_DIR) { - apr_size_t save_path_len = fsctx->path1.cur_len; - apr_size_t save_uri_len = fsctx->uri_buf.cur_len; - apr_size_t save_path2_len = fsctx->path2.cur_len; - - /* adjust length to incorporate the subdir name */ - fsctx->path1.cur_len += len; - fsctx->path2.cur_len += len; - - /* adjust URI length to incorporate subdir and a slash */ - fsctx->uri_buf.cur_len += len + 1; - fsctx->uri_buf.buf[fsctx->uri_buf.cur_len - 1] = '/'; - fsctx->uri_buf.buf[fsctx->uri_buf.cur_len] = '\0'; - - /* switch over to a collection */ - fsctx->res1.collection = 1; - fsctx->res2.collection = 1; - - /* recurse on the subdir */ - /* ### don't always want to quit on error from single child */ - if ((err = dav_fs_walker(fsctx, depth - 1)) != NULL) { - /* ### maybe add a higher-level description? */ - break; - } - - /* put the various information back */ - fsctx->path1.cur_len = save_path_len; - fsctx->path2.cur_len = save_path2_len; - fsctx->uri_buf.cur_len = save_uri_len; - - fsctx->res1.collection = 0; - fsctx->res2.collection = 0; - - /* assert: res1.exists == 1 */ - } - } - - /* ### check the return value of this? */ - apr_dir_close(dirp); - - if (err != NULL) - return err; - - if (params->walk_type & DAV_WALKTYPE_LOCKNULL) { - apr_size_t offset = 0; - - /* null terminate the directory name */ - fsctx->path1.buf[fsctx->path1.cur_len - 1] = '\0'; - - /* Include any lock null resources found in this collection */ - fsctx->res1.collection = 1; - if ((err = dav_fs_get_locknull_members(&fsctx->res1, - &fsctx->locknull_buf)) != NULL) { - /* ### maybe add a higher-level description? */ - return err; - } - - /* put a slash back on the end of the directory */ - fsctx->path1.buf[fsctx->path1.cur_len - 1] = '/'; - - /* these are all non-existant (files) */ - fsctx->res1.exists = 0; - fsctx->res1.collection = 0; - memset(&fsctx->info1.finfo, 0, sizeof(fsctx->info1.finfo)); - - while (offset < fsctx->locknull_buf.cur_len) { - apr_size_t len = strlen(fsctx->locknull_buf.buf + offset); - dav_lock *locks = NULL; - - /* - ** Append the locknull file to the paths and the URI. Note that - ** we don't have to pad the URI for a slash since a locknull - ** resource is not a collection. - */ - dav_buffer_place_mem(pool, &fsctx->path1, - fsctx->locknull_buf.buf + offset, len + 1, 0); - dav_buffer_place_mem(pool, &fsctx->uri_buf, - fsctx->locknull_buf.buf + offset, len + 1, 0); - if (fsctx->path2.buf != NULL) { - dav_buffer_place_mem(pool, &fsctx->path2, - fsctx->locknull_buf.buf + offset, - len + 1, 0); - } - - /* set up the (internal) pathnames for the two resources */ - fsctx->info1.pathname = fsctx->path1.buf; - fsctx->info2.pathname = fsctx->path2.buf; - - /* set up the URI for the current resource */ - fsctx->res1.uri = fsctx->uri_buf.buf; - - /* - ** To prevent a PROPFIND showing an expired locknull - ** resource, query the lock database to force removal - ** of both the lock entry and .locknull, if necessary.. - ** Sure, the query in PROPFIND would do this.. after - ** the locknull resource was already included in the - ** return. - ** - ** NOTE: we assume the caller has opened the lock database - ** if they have provided DAV_WALKTYPE_LOCKNULL. - */ - /* ### we should also look into opening it read-only and - ### eliding timed-out items from the walk, yet leaving - ### them in the locknull database until somebody opens - ### the thing writable. - */ - /* ### probably ought to use has_locks. note the problem - ### mentioned above, though... we would traverse this as - ### a locknull, but then a PROPFIND would load the lock - ### info, causing a timeout and the locks would not be - ### reported. Therefore, a null resource would be returned - ### in the PROPFIND. - ### - ### alternative: just load unresolved locks. any direct - ### locks will be timed out (correct). any indirect will - ### not (correct; consider if a parent timed out -- the - ### timeout routines do not walk and remove indirects; - ### even the resolve func would probably fail when it - ### tried to find a timed-out direct lock). - */ - if ((err = dav_lock_query(params->lockdb, &fsctx->res1, - &locks)) != NULL) { - /* ### maybe add a higher-level description? */ - return err; - } - - /* call the function for the specified dir + file */ - if (locks != NULL && - (err = (*params->func)(&fsctx->wres, - DAV_CALLTYPE_LOCKNULL)) != NULL) { - /* ### maybe add a higher-level description? */ - return err; - } - - offset += len + 1; - } - - /* reset the exists flag */ - fsctx->res1.exists = 1; - } - - if (params->walk_type & DAV_WALKTYPE_POSTFIX) { - /* replace the dirs' trailing slashes with null terms */ - fsctx->path1.buf[--fsctx->path1.cur_len] = '\0'; - fsctx->uri_buf.buf[--fsctx->uri_buf.cur_len] = '\0'; - if (fsctx->path2.buf != NULL) { - fsctx->path2.buf[--fsctx->path2.cur_len] = '\0'; - } - - /* this is a collection which exists */ - fsctx->res1.collection = 1; - - return (*params->func)(&fsctx->wres, DAV_CALLTYPE_POSTFIX); - } - - return NULL; -} - -static dav_error * dav_fs_internal_walk(const dav_walk_params *params, - int depth, int is_move, - const dav_resource *root_dst, - dav_response **response) -{ - dav_fs_walker_context fsctx = { 0 }; - dav_error *err; - dav_fs_copymove_walk_ctx cm_ctx = { 0 }; - -#if DAV_DEBUG - if ((params->walk_type & DAV_WALKTYPE_LOCKNULL) != 0 - && params->lockdb == NULL) { - return dav_new_error(params->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "DESIGN ERROR: walker called to walk locknull " - "resources, but a lockdb was not provided."); - } -#endif - - fsctx.params = params; - fsctx.wres.walk_ctx = params->walk_ctx; - fsctx.wres.pool = params->pool; - - /* ### zero out versioned, working, baselined? */ - - fsctx.res1 = *params->root; - fsctx.res1.pool = params->pool; - - fsctx.res1.info = &fsctx.info1; - fsctx.info1 = *params->root->info; - - /* the pathname is stored in the path1 buffer */ - dav_buffer_init(params->pool, &fsctx.path1, fsctx.info1.pathname); - fsctx.info1.pathname = fsctx.path1.buf; - - if (root_dst != NULL) { - /* internal call from the COPY/MOVE code. set it up. */ - - fsctx.wres.walk_ctx = &cm_ctx; - cm_ctx.is_move = is_move; - cm_ctx.res_dst = &fsctx.res2; - cm_ctx.root = params->root; - cm_ctx.pool = params->pool; - - fsctx.res2 = *root_dst; - fsctx.res2.exists = 0; - fsctx.res2.collection = 0; - fsctx.res2.uri = NULL; /* we don't track this */ - fsctx.res2.pool = params->pool; - - fsctx.res2.info = &fsctx.info2; - fsctx.info2 = *root_dst->info; - - /* res2 does not exist -- clear its finfo structure */ - memset(&fsctx.info2.finfo, 0, sizeof(fsctx.info2.finfo)); - - /* the pathname is stored in the path2 buffer */ - dav_buffer_init(params->pool, &fsctx.path2, fsctx.info2.pathname); - fsctx.info2.pathname = fsctx.path2.buf; - } - - /* prep the URI buffer */ - dav_buffer_init(params->pool, &fsctx.uri_buf, params->root->uri); - - /* if we have a directory, then ensure the URI has a trailing "/" */ - if (fsctx.res1.collection - && fsctx.uri_buf.buf[fsctx.uri_buf.cur_len - 1] != '/') { - - /* this will fall into the pad area */ - fsctx.uri_buf.buf[fsctx.uri_buf.cur_len++] = '/'; - fsctx.uri_buf.buf[fsctx.uri_buf.cur_len] = '\0'; - } - - /* the current resource's URI is stored in the uri_buf buffer */ - fsctx.res1.uri = fsctx.uri_buf.buf; - - /* point the callback's resource at our structure */ - fsctx.wres.resource = &fsctx.res1; - - /* always return the error, and any/all multistatus responses */ - err = dav_fs_walker(&fsctx, depth); - *response = fsctx.wres.response; - return err; -} - -static dav_error * dav_fs_walk(const dav_walk_params *params, int depth, - dav_response **response) -{ - /* always return the error, and any/all multistatus responses */ - return dav_fs_internal_walk(params, depth, 0, NULL, response); -} - -/* dav_fs_etag: Stolen from ap_make_etag. Creates a strong etag - * for file path. - * ### do we need to return weak tags sometimes? - */ -static const char *dav_fs_getetag(const dav_resource *resource) -{ - dav_resource_private *ctx = resource->info; - - if (!resource->exists) - return apr_pstrdup(ctx->pool, ""); - - if (ctx->finfo.filetype != 0) { - return apr_psprintf(ctx->pool, "\"%lx-%lx-%lx\"", - (unsigned long) ctx->finfo.inode, - (unsigned long) ctx->finfo.size, - (unsigned long) ctx->finfo.mtime); - } - - return apr_psprintf(ctx->pool, "\"%lx\"", (unsigned long) ctx->finfo.mtime); -} - -static const dav_hooks_repository dav_hooks_repository_fs = -{ - DEBUG_GET_HANDLER, /* normally: special GET handling not required */ - dav_fs_get_resource, - dav_fs_get_parent_resource, - dav_fs_is_same_resource, - dav_fs_is_parent_resource, - dav_fs_open_stream, - dav_fs_close_stream, - dav_fs_write_stream, - dav_fs_seek_stream, -#if DEBUG_GET_HANDLER - dav_fs_set_headers, - dav_fs_deliver, -#else - NULL, - NULL, -#endif - dav_fs_create_collection, - dav_fs_copy_resource, - dav_fs_move_resource, - dav_fs_remove_resource, - dav_fs_walk, - dav_fs_getetag, -}; - -static dav_prop_insert dav_fs_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_fs_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_fs_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_fs_namespace_uris[info->ns]); - } - apr_text_append(p, phdr, s); - - /* we inserted what was asked for */ - return what; -} - -static int dav_fs_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_fs_liveprop_group, &info); - return info->is_writable; -} - -static dav_error *dav_fs_patch_validate(const dav_resource *resource, - const apr_xml_elem *elem, - int operation, - void **context, - int *defer_to_dead) -{ - const apr_text *cdata; - const apr_text *f_cdata; - char value; - dav_elem_private *priv = elem->priv; - - if (priv->propid != DAV_PROPID_FS_executable) { - *defer_to_dead = 1; - return NULL; - } - - if (operation == DAV_PROP_OP_DELETE) { - return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, - "The 'executable' property cannot be removed."); - } - - cdata = elem->first_cdata.first; - - /* ### hmm. this isn't actually looking at all the possible text items */ - f_cdata = elem->first_child == NULL - ? NULL - : elem->first_child->following_cdata.first; - - /* DBG3("name=%s cdata=%s f_cdata=%s",elem->name,cdata ? cdata->text : "[null]",f_cdata ? f_cdata->text : "[null]"); */ - - if (cdata == NULL) { - if (f_cdata == NULL) { - return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, - "The 'executable' property expects a single " - "character, valued 'T' or 'F'. There was no " - "value submitted."); - } - cdata = f_cdata; - } - else if (f_cdata != NULL) - goto too_long; - - if (cdata->next != NULL || strlen(cdata->text) != 1) - goto too_long; - - value = cdata->text[0]; - if (value != 'T' && value != 'F') { - return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, - "The 'executable' property expects a single " - "character, valued 'T' or 'F'. The value " - "submitted is invalid."); - } - - *context = (void *)(value == 'T'); - - return NULL; - - too_long: - return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, - "The 'executable' property expects a single " - "character, valued 'T' or 'F'. The value submitted " - "has too many characters."); - -} - -static dav_error *dav_fs_patch_exec(const dav_resource *resource, - const apr_xml_elem *elem, - int operation, - void *context, - dav_liveprop_rollback **rollback_ctx) -{ - int value = context != NULL; - apr_fileperms_t perms = resource->info->finfo.protection; - int old_value = (perms & APR_UEXECUTE) != 0; - - /* assert: prop == executable. operation == SET. */ - - /* don't do anything if there is no change. no rollback info either. */ - /* DBG2("new value=%d (old=%d)", value, old_value); */ - if (value == old_value) - return NULL; - - perms &= ~APR_UEXECUTE; - if (value) - perms |= APR_UEXECUTE; - - if (apr_file_perms_set(resource->info->pathname, perms) != APR_SUCCESS) { - return dav_new_error(resource->info->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not set the executable flag of the " - "target resource."); - } - - /* update the resource and set up the rollback context */ - resource->info->finfo.protection = perms; - *rollback_ctx = (dav_liveprop_rollback *)old_value; - - return NULL; -} - -static void dav_fs_patch_commit(const dav_resource *resource, - int operation, - void *context, - dav_liveprop_rollback *rollback_ctx) -{ - /* nothing to do */ -} - -static dav_error *dav_fs_patch_rollback(const dav_resource *resource, - int operation, - void *context, - dav_liveprop_rollback *rollback_ctx) -{ - apr_fileperms_t perms = resource->info->finfo.protection & ~APR_UEXECUTE; - int value = rollback_ctx != NULL; - - /* assert: prop == executable. operation == SET. */ - - /* restore the executable bit */ - if (value) - perms |= APR_UEXECUTE; - - if (apr_file_perms_set(resource->info->pathname, perms) != APR_SUCCESS) { - return dav_new_error(resource->info->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "After a failure occurred, the resource's " - "executable flag could not be restored."); - } - - /* restore the resource's state */ - resource->info->finfo.protection = perms; - - return NULL; -} - - -static const dav_hooks_liveprop dav_hooks_liveprop_fs = -{ - dav_fs_insert_prop, - dav_fs_is_writable, - dav_fs_namespace_uris, - dav_fs_patch_validate, - dav_fs_patch_exec, - dav_fs_patch_commit, - dav_fs_patch_rollback -}; - -static const dav_provider dav_fs_provider = -{ - &dav_hooks_repository_fs, - &dav_hooks_db_dbm, - &dav_hooks_locks_fs, - NULL, /* vsn */ - NULL, /* binding */ - NULL, /* search */ - - NULL /* ctx */ -}; - -void dav_fs_gather_propsets(apr_array_header_t *uris) -{ -#ifdef DAV_FS_HAS_EXECUTABLE - *(const char **)apr_array_push(uris) = - "<http://apache.org/dav/propset/fs/1>"; -#endif -} - -int dav_fs_find_liveprop(const dav_resource *resource, - const char *ns_uri, const char *name, - const dav_hooks_liveprop **hooks) -{ - /* don't try to find any liveprops if this isn't "our" resource */ - if (resource->hooks != &dav_hooks_repository_fs) - return 0; - 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, - dav_prop_insert what, apr_text_header *phdr) -{ - /* don't insert any liveprops if this isn't "our" resource */ - if (resource->hooks != &dav_hooks_repository_fs) - return; - - 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, - what, phdr); - (void) dav_fs_insert_prop(resource, DAV_PROPID_getcontentlength, - what, phdr); - (void) dav_fs_insert_prop(resource, DAV_PROPID_getlastmodified, - what, phdr); - (void) dav_fs_insert_prop(resource, DAV_PROPID_getetag, - what, phdr); - -#ifdef DAV_FS_HAS_EXECUTABLE - /* Only insert this property if it is defined for this platform. */ - (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_executable, - what, phdr); -#endif - - /* ### we know the others aren't defined as liveprops */ -} - -void dav_fs_register(apr_pool_t *p) -{ - /* register the namespace URIs */ - dav_register_liveprop_group(p, &dav_fs_liveprop_group); - - /* register the repository provider */ - dav_register_provider(p, "filesystem", &dav_fs_provider); -} diff --git a/rubbos/app/httpd-2.0.64/modules/dav/fs/repos.h b/rubbos/app/httpd-2.0.64/modules/dav/fs/repos.h deleted file mode 100644 index d7962d56..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/fs/repos.h +++ /dev/null @@ -1,78 +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. - */ - -/* -** Declarations for the filesystem repository implementation -*/ - -#ifndef _DAV_FS_REPOS_H_ -#define _DAV_FS_REPOS_H_ - -/* the subdirectory to hold all DAV-related information for a directory */ -#define DAV_FS_STATE_DIR ".DAV" -#define DAV_FS_STATE_FILE_FOR_DIR ".state_for_dir" -#define DAV_FS_LOCK_NULL_FILE ".locknull" - - -/* ensure that our state subdirectory is present */ -void dav_fs_ensure_state_dir(apr_pool_t *p, const char *dirname); - -/* return the storage pool associated with a resource */ -apr_pool_t *dav_fs_pool(const dav_resource *resource); - -/* return the full pathname for a resource */ -const char *dav_fs_pathname(const dav_resource *resource); - -/* return the directory and filename for a resource */ -dav_error * dav_fs_dir_file_name(const dav_resource *resource, - const char **dirpath, - const char **fname); - -/* return the list of locknull members in this resource's directory */ -dav_error * dav_fs_get_locknull_members(const dav_resource *resource, - dav_buffer *pbuf); - - -/* DBM functions used by the repository and locking providers */ -extern const dav_hooks_db dav_hooks_db_dbm; - -dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, int ro, - dav_db **pdb); -void dav_dbm_get_statefiles(apr_pool_t *p, const char *fname, - const char **state1, const char **state2); -dav_error * dav_dbm_delete(dav_db *db, apr_datum_t key); -dav_error * dav_dbm_store(dav_db *db, apr_datum_t key, apr_datum_t value); -dav_error * dav_dbm_fetch(dav_db *db, apr_datum_t key, apr_datum_t *pvalue); -void dav_dbm_freedatum(dav_db *db, apr_datum_t data); -int dav_dbm_exists(dav_db *db, apr_datum_t key); -void dav_dbm_close(dav_db *db); - -/* where is the lock database located? */ -const char *dav_get_lockdb_path(const request_rec *r); - -const dav_hooks_locks *dav_fs_get_lock_hooks(request_rec *r); -const dav_hooks_propdb *dav_fs_get_propdb_hooks(request_rec *r); - -void dav_fs_gather_propsets(apr_array_header_t *uris); -int dav_fs_find_liveprop(const dav_resource *resource, - const char *ns_uri, const char *name, - const dav_hooks_liveprop **hooks); -void dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource, - dav_prop_insert what, apr_text_header *phdr); - -void dav_fs_register(apr_pool_t *p); - -#endif /* _DAV_FS_REPOS_H_ */ |