repos.c revision cccd31fa4a72fe23cc3249c06db181b274a55a69
458N/A/* ==================================================================== 458N/A * The Apache Software License, Version 1.1 458N/A * Copyright (c) 2000 The Apache Software Foundation. All rights 458N/A * Redistribution and use in source and binary forms, with or without 458N/A * modification, are permitted provided that the following conditions 458N/A * 1. Redistributions of source code must retain the above copyright 458N/A * notice, this list of conditions and the following disclaimer. 458N/A * 2. Redistributions in binary form must reproduce the above copyright 458N/A * notice, this list of conditions and the following disclaimer in 458N/A * the documentation and/or other materials provided with the 458N/A * 3. The end-user documentation included with the redistribution, 458N/A * if any, must include the following acknowledgment: 5680N/A * "This product includes software developed by the 5466N/A * Alternately, this acknowledgment may appear in the software itself, 458N/A * if and wherever such third-party acknowledgments normally appear. 458N/A * 4. The names "Apache" and "Apache Software Foundation" must 458N/A * not be used to endorse or promote products derived from this 458N/A * software without prior written permission. For written 458N/A * permission, please contact apache@apache.org. 618N/A * 5. Products derived from this software may not be called "Apache", 458N/A * nor may "Apache" appear in their name, without prior written 2833N/A * permission of the Apache Software Foundation. 5181N/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 618N/A * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 3555N/A * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 1258N/A * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 458N/A * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 5181N/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2899N/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 3817N/A * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 3817N/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 3817N/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 3817N/A * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1567N/A * ==================================================================== 1567N/A * This software consists of voluntary contributions made by many 1567N/A * individuals on behalf of the Apache Software Foundation. For more 1567N/A * information on the Apache Software Foundation, please see 969N/A** DAV filesystem-based repository provider 646N/A/* to assist in debugging mod_dav's GET handling */ 646N/A/* context needed to identify a resource */ 5934N/A/* private context for doing a filesystem walk */ 5934N/A /* the input walk parameters */ 581N/A /* reused as we walk */ 458N/A /* CALLBACK: this is a secondary resource managed specially for us */ 458N/A /* copied from dav_walk_params (they are invariant across the walk) */ 3497N/A/* an internal WALKTYPE to walk hidden files (the .DAV directory) */ 3497N/A/* an internal WALKTYPE to call collections (again) after their contents */ 3497N/A/* pull this in from the other source file */ 3693N/A/* forward-declare the hook structures */ 3497N/A** The namespace URIs that we use. This list and the enumeration must 3497N/A** The single property that we define (in the DAV_FS_URI_MYPROPS namespace) 1567N/A 0
/* handled special in dav_fs_is_writable */ 3817N/A/* define the dav_stream structure for our use */ /* forward declaration for internal treewalkers */ /* -------------------------------------------------------------------- ** PRIVATE REPOSITORY FUNCTIONS /* remove trailing slash from dirpath, unless it's the root dir */ /* Note: picked up from ap_gm_timestr_822() */ /* NOTE: buf must be at least DAV_TIMEBUF_SIZE chars in size */ /* ### what to do if fails? */ /* ### should we use "-00:00" instead of "Z" ?? */ /* 20 chars plus null term */ /* RFC 822 date format; as strftime '%a, %d %b %Y %T GMT' */ /* 29 chars plus null term */ "%s, %.2d %s %d %.2d:%.2d:%.2d GMT",
/* ### use something besides 500? */ "Could not open file for reading");
/* ### do we need to deal with the umask? */ /* ### use something besides 500? */ "Could not open file for writing");
/* ### ACK! Inconsistent state... */ /* ### use something besides 500? */ "Could not delete output after read " "failure. Server is now in an " /* ### use something besides 500? */ "Could not read input file");
/* write any bytes that were read (applies to APR_EOF, too) */ /* ### ACK! Inconsistent state... */ /* ### use something besides 500? */ "Could not delete output after write " "failure. Server is now in an " "There is not enough storage to write to " /* ### use something besides 500? */ "Could not write output file");
/* ### ACK. this creates an inconsistency. do more!? */ /* ### use something besides 500? */ /* Note that we use the latest errno */ "Could not remove source or destination " "file. Server is now in an inconsistent " /* ### use something besides 500? */ "Could not remove source file after move. " "Destination was removed to ensure consistency.");
/* copy/move a file from within a state dir to another state dir */ /* ### need more buffers to replace the pool argument */ /* build the propset pathname for the source file */ /* the source file doesn't exist */ /* build the pathname for the destination state dir */ /* ### do we need to deal with the umask? */ /* ensure that it exists */ /* ### use something besides 500? */ "Could not create internal state directory");
/* get info about the state directory */ /* Ack! Where'd it go? */ /* ### use something besides 500? */ "State directory disappeared");
/* The mkdir() may have failed because a *file* exists there already */ /* ### try to recover by deleting this file? (and mkdir again) */ /* ### use something besides 500? */ "State directory is actually a file");
/* append the target file to the state directory pathname */ /* simple rename is possible since it is on the same device */ /* ### use something besides 500? */ "Could not move state file.");
/* gotta copy (and delete) */ /* Get directory and filename for resources */ /* Get the corresponding state files for each resource */ "DESIGN ERROR: dav_dbm_get_statefiles() " "returned inconsistent results.");
/* ### 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. */ "Could not fully copy/move the properties. " "The server is now in an inconsistent state.";
/* Get directory, filename, and state-file names for the resource */ /* build the propset pathname for the file */ /* note: we may get ENOENT if the state dir is not present */ "Could not remove properties.");
/* build the propset pathname for the file */ /* ### CRAP. only removed half. */ "Could not fully remove properties. " "The server is now in an inconsistent " /* -------------------------------------------------------------------- ** REPOSITORY HOOK FUNCTIONS /* ### optimize this into a single allocation! */ /* Create private resource context descriptor */ /* ### this should go away */ /* Preserve case on OSes which fold canonical filenames */ /* ### not available in Apache 2.0 yet */ ** 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 /* make sure the pathname does not have a trailing "/" */ if (
len >
1 && s[
len -
1] ==
'/') {
/* Create resource descriptor */ /* make sure the URI does not have a trailing "/" */ /* unused info in the URL will indicate a null resource */ /* only a trailing "/" is allowed */ ** possibly a destination of a MOVE/COPY ** 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 NULL;
/* becomes HTTP_NOT_FOUND */ /* retain proper integrity across the structures */ /* If given resource is root, then there is no parent */ /* ### optimize this into a single allocation! */ /* Create private resource context descriptor */ /* ### this should go away */ /* it is safe to use ctx2 now */ /* ### use something besides 500? */ "An error occurred while opening a resource.");
/* (APR registers cleanups for the fd with the pool) */ /* ### use a better description? */ "There was a problem removing (rolling " "when it was being closed.");
/* ### use something besides 500? */ "An error occurred while reading from a " "There is not enough storage to write to " /* ### use something besides 500? */ "An error occurred while writing to a " /* ### should check whether apr_seek set abs_pos was set to the /* ### use something besides 500? */ "Could not seek to specified position in the " /* ### this function isn't really used since we have a get_pathname */ /* make sure the proper mtime is in the request record */ /* ### note that these use r->filename rather than <resource> */ /* we accept byte-ranges */ /* set up the Content-Length header */ /* ### how to set the content type? */ /* ### until this is resolved, the Content-Type header is busted */ /* nothing to free ... */ "There is not enough storage to create " /* ### refine this error message? */ "Unable to create collection.");
/* update resource state to show it exists as a collection */ /* 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? */ /* copy/move of a collection. Create the new, target collection */ /* ### assume it was a permissions problem */ /* ### need a description here */ /* ### push a higher-level description? */ ** If we have a "not so bad" error, then it might need to go into a ** 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 ** For a COPY, we are traversing in a prefix fashion. If the root fails, ** then we can just bail out now. /* ### use errno to generate DAV:responsedescription? */ /* the error is in the multistatus now. do not stop the traversal. */ /* if a collection, recursively copy/move it and its children, * including the state dirs /* params.walk_ctx is managed by dav_fs_internal_walk() */ /* postfix is needed for MOVE to delete source dirs */ /* note that we return the error OR the multistatus. never both */ /* on a "real" error, then just punt. nothing else to do. */ /* some multistatus responses exist. wrap them in a 207 */ "Error(s) occurred on some resources during " /* ### push a higher-level description? */ ** ### strictly speaking, this is a design error; we should not ** ### have reached this point. "DESIGN ERROR: a mix of repositories " "was passed to copy_resource.");
/* update state of destination resource to show it exists */ ** ### strictly speaking, this is a design error; we should not ** ### have reached this point. "DESIGN ERROR: a mix of repositories " "was passed to move_resource.");
/* determine whether a simple rename will work. * Assume source exists, else we wouldn't get called. /* target exists and is on the same device. */ /* destination does not exist, but the parent directory should, /* if we can't simply rename, then do it the hard way... */ /* update resource states */ /* a rename should work. do it, and move properties as well */ /* no multistatus response */ /* ### APR has no rename? */ /* ### should have a better error than this. */ "Could not rename resource.");
/* update resource states */ /* no error. we're done. go ahead and return now. */ /* error occurred during properties move; try to put resource back */ /* couldn't put it back! */ "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.",
/* update resource states again */ /* resource moved back, but properties may be inconsistent */ "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 " /* do not attempt to remove a null resource, * or a collection with children /* try to remove the resource */ ** 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) /* ### assume there is a permissions problem */ /* ### use errno to generate DAV:responsedescription? */ /* if a collection, recursively remove it and its children, * including the state dirs /* on a "real" error, then just punt. nothing else to do. */ /* some multistatus responses exist. wrap them in a 207 */ "Error(s) occurred on some resources during " "the deletion process.");
/* no errors... update resource state */ /* not a collection; remove the file and its properties */ /* ### put a description in here */ /* update resource state */ /* remove properties and return its result */ /* ### move this to dav_util? */ /* Walk recursively down through directories, * * including lock-null resources as we go. */ /* ensure the context is prepared properly, then call the func */ /* put a trailing slash onto the directory, in preparation for appending * files to it as we discovery them within the directory */ /* if a secondary path is present, then do that, too */ /* Note: the URI should ALREADY have a trailing "/" */ /* for this first pass of files, all resources exist */ /* a file is the default; we'll adjust if we hit a directory */ /* open and scan the directory */ /* ### need a better error */ /* avoid recursing into our current, parent, or state directories */ /* ### need to authorize each file */ /* ### example: .htaccess is normally configured to fail auth */ /* stuff in the state directory is never authorized! */ /* skip the state dir unless a HIDDEN is performed */ /* append this file onto the path buffer (copy null term) */ /* woah! where'd it go? */ /* ### should have a better error here */ /* copy the file to the URI, too. NOTE: we will pad an extra byte for the trailing slash later. */ /* if there is a secondary path, then do that, too */ /* set up the (internal) pathnames for the two resources */ /* set up the URI for the current resource */ /* ### for now, only process regular files (e.g. skip symlinks) */ /* call the function for the specified dir + file */ /* ### maybe add a higher-level description? */ /* adjust length to incorporate the subdir name */ /* adjust URI length to incorporate subdir and a slash */ /* switch over to a collection */ /* recurse on the subdir */ /* ### don't always want to quit on error from single child */ /* ### maybe add a higher-level description? */ /* put the various information back */ /* assert: res1.exists == 1 */ /* ### check the return value of this? */ /* null terminate the directory name */ /* Include any lock null resources found in this collection */ /* ### maybe add a higher-level description? */ /* put a slash back on the end of the directory */ /* these are all non-existant (files) */ ** 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. /* set up the (internal) pathnames for the two resources */ /* set up the URI for the current resource */ ** 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 ** 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 /* ### 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 ### 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). /* ### maybe add a higher-level description? */ /* call the function for the specified dir + file */ /* ### maybe add a higher-level description? */ /* reset the exists flag */ /* replace the dirs' trailing slashes with null terms */ /* this is a collection which exists */ "DESIGN ERROR: walker called to walk locknull " "resources, but a lockdb was not provided.");
/* ### zero out versioned, working, baselined? */ /* the pathname is stored in the path1 buffer */ /* internal call from the COPY/MOVE code. set it up. */ /* res2 does not exist -- clear its finfo structure */ /* the pathname is stored in the path2 buffer */ /* prep the URI buffer */ /* if we have a directory, then ensure the URI has a trailing "/" */ /* this will fall into the pad area */ /* the current resource's URI is stored in the uri_buf buffer */ /* point the callback's resource at our structure */ /* always return the error, and any/all multistatus responses */ /* always return the error, and any/all multistatus responses */ /* dav_fs_etag: Stolen from ap_make_etag. Creates a strong etag * ### do we need to return weak tags sometimes? /* an HTTP-date can be 29 chars plus a null term */ /* a 64-bit size can be 20 chars plus a null term */ ** 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 ** 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. /* our property, but not defined on collection resources */ /* our property, but not defined on the Win32 platform */ /* our property, but not defined on collection resources */ /* the files are "ours" so we only need to check owner exec privs */ /* ### what the heck was this property? */ /* assert: value != NULL */ /* get the information and global NS index for the property */ /* assert: info != NULL && info->name != NULL */ /* DBG3("FS: inserting lp%d:%s (local %d)", ns, scan->name, scan->ns); */ /* we inserted a name or value (this prop is done) */ /* this property is not usable (writable) on the Win32 platform */ "The 'executable' property cannot be removed.");
/* ### hmm. this isn't actually looking at all the possible text items */ /* DBG3("name=%s cdata=%s f_cdata=%s",elem->name,cdata ? cdata->text : "[null]",f_cdata ? f_cdata->text : "[null]"); */ "The 'executable' property expects a single " "character, valued 'T' or 'F'. There was no " "The 'executable' property expects a single " "character, valued 'T' or 'F'. The value " "submitted is invalid.");
"The 'executable' property expects a single " "character, valued 'T' or 'F'. The value submitted " "has too many characters.");
/* 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); */ "Could not set the executable flag of the " /* update the resource and set up the rollback context */ /* assert: prop == executable. operation == SET. */ /* restore the executable bit */ "After a failure occurred, the resource's " "executable flag could not be restored.");
/* restore the resource's state */ /* 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". ** Note: this property is not defined on the Win32 platform. ** dav_fs_insert_prop() won't insert it, but we may as ** well not even call it. /* ### we know the others aren't defined as liveprops */ /* register the namespace URIs */ /* register the repository provider */