Roxen.git
/
server
/
base_server
/
module.pike
version
»
Context lines:
10
20
40
80
file
none
3
Roxen.git/server/base_server/module.pike:1:
// This file is part of Roxen WebServer. // Copyright © 1996 - 2001, Roxen IS.
-
// $Id: module.pike,v 1.
209
2004/05/
13
17
:
45
:
20
mast Exp $
+
// $Id: module.pike,v 1.
210
2004/05/
14
21
:
18
:
04
mast Exp $
#include <module_constants.h> #include <module.h> #include <request_trace.h> constant __pragma_save_parent__ = 1; inherit "basic_defvar"; mapping(string:array(int)) error_log=([]);
Roxen.git/server/base_server/module.pike:632:
//! normalized with @[VFS.normalize_path]. { return has_suffix (path, "/") ? path : path + "/"; } string|int authenticated_user_id (string path, RequestID id) //! Return a value that uniquely identifies the user that the given //! request is authenticated as. //! //! This function is e.g. used by the default lock implementation to
-
//! tell different users holding locks apart.
+
//! tell different users holding locks apart.
WARNING: Due to some
+
//! design issues in the lock system, it's likely that it will change
+
//! to not use this function in the future.
//! //! @param path //! The requested path below the filesystem location. It has been //! normalized with @[VFS.normalize_path]. { // Leave this to the standard auth system by default. User uid = my_configuration()->authenticate (id); return uid && uid->name(); }
Roxen.git/server/base_server/module.pike:748:
add_locks = 0; TRACE_LEAVE(sprintf("Done, found %d locks.", sizeof(locks))); return sizeof(locks) && locks; } //! Check if there are one or more locks that apply to @[path] for the //! user the request is authenticated as. //!
+
//! WARNING: This function has some design issues and will very likely
+
//! get a different interface. Compatibility is NOT guaranteed.
+
//!
//! @param path //! Normalized path below the filesystem location. //! //! @param recursive //! If @expr{1@} also check recursively under @[path] for locks. //! //! @returns //! The valid return values are: //! @mixed //! @type DAVLock
Roxen.git/server/base_server/module.pike:800:
//! persistent storage of them. The default implementation does not //! store locks persistently. //! //! @note //! The default implementation only handles the @expr{"DAV:write"@} //! lock type. DAVLock|LockFlag check_locks(string path, int(0..1) recursive, RequestID id) {
-
// Common case.
-
if (!sizeof(file_locks) && !sizeof(prefix_locks)) return 0;
-
+
TRACE_ENTER(sprintf("check_locks(%O, %d, X)", path, recursive), this);
-
+
// Common case.
+
if (!sizeof(file_locks) && !sizeof(prefix_locks)) {
+
TRACE_LEAVE ("Got no locks");
+
return 0;
+
}
+
path = resource_id (path, id); mixed auth_user = authenticated_user_id (path, id); if (DAVLock lock = file_locks[path] && file_locks[path][auth_user] || prefix_locks[path] && prefix_locks[path][auth_user]) { TRACE_LEAVE(sprintf("Found lock %O.", lock->locktoken)); return lock; }
Roxen.git/server/base_server/module.pike:850:
lock->locktoken)); return LOCK_EXCL_AT; } shared = LOCK_SHARED_AT; break; } } } if (!recursive) {
-
TRACE_LEAVE(
sprintf(
"Returning %O.", shared)
)
;
+
SIMPLE_
TRACE_LEAVE("Returning %O.", shared);
return shared; } int(0..1) locked_by_auth_user; // We want to know if there are any locks with @[path] as prefix // that apply to us. LOOP_OVER_BOTH (string prefix, mapping(mixed:DAVLock) locks, { if (has_prefix(prefix, path)) { if (locks[auth_user])
Roxen.git/server/base_server/module.pike:875:
TRACE_LEAVE(sprintf("Found other user's exclusive lock %O.", lock->locktoken)); return LOCK_EXCL_BELOW; } if (!shared) shared = LOCK_SHARED_BELOW; break; } } });
-
TRACE_LEAVE(
sprintf(
"Returning %O.", locked_by_auth_user ? LOCK_OWN_BELOW : shared)
)
;
+
SIMPLE_
TRACE_LEAVE("Returning %O.", locked_by_auth_user ? LOCK_OWN_BELOW : shared);
return locked_by_auth_user ? LOCK_OWN_BELOW : shared; } //! Register @[lock] on the path @[path] under the assumption that //! there is no other lock already that conflicts with this one, i.e. //! that @code{check_locks(path,lock->recursive,id)@} would return //! @expr{LOCK_NONE@} if @expr{lock->lockscope@} is //! @expr{"DAV:exclusive"@}, or @expr{< LOCK_OWN_BELOW@} if //! @expr{lock->lockscope@} is @expr{"DAV:shared"@}. //!
Roxen.git/server/base_server/module.pike:923:
} else { if (file_locks[path]) { file_locks[path][auth_user] = lock; } else { file_locks[path] = ([ auth_user:lock ]); } } TRACE_LEAVE("Ok."); }
+
//! Unregister @[lock] that currently is locking the resource at
+
//! @[path]. It's assumed that the lock is registered for exactly that
+
//! path.
+
//!
+
//! This function is only provided as a helper to call from
+
//! @[unlock_file] if the default lock implementation is to be used.
+
//!
+
//! @param path
+
//! Normalized path (below the filesystem location) that the lock
+
//! applies to.
+
//!
+
//! @param lock
+
//! The lock to unregister. (It must not be changed or destructed.)
+
//!
+
//! @returns
+
//! Returns a status mapping on any error, zero otherwise.
+
static void unregister_lock (string path, DAVLock lock, RequestID id)
+
{
+
TRACE_ENTER(sprintf("unregister_lock(%O, lock(%O), X).", path, lock->locktoken),
+
this);
+
mixed auth_user = authenticated_user_id (path, id);
+
path = resource_id (path, id);
+
DAVLock removed_lock;
+
if (lock->recursive) {
+
removed_lock = m_delete(prefix_locks[path], auth_user);
+
if (!sizeof (prefix_locks[path])) m_delete (prefix_locks, path);
+
}
+
else if (file_locks[path]) {
+
removed_lock = m_delete (file_locks[path], auth_user);
+
if (!sizeof (file_locks[path])) m_delete (file_locks, path);
+
}
+
ASSERT_IF_DEBUG (lock /*%O*/ == removed_lock /*%O*/, lock, removed_lock);
+
TRACE_LEAVE("Ok.");
+
return 0;
+
}
+
//! Register @[lock] on the path @[path] under the assumption that //! there is no other lock already that conflicts with this one, i.e. //! that @code{check_locks(path,lock->recursive,id)@} would return //! @expr{LOCK_NONE@} if @expr{lock->lockscope@} is //! @expr{"DAV:exclusive"@}, or @expr{<= LOCK_SHARED_AT@} if //! @expr{lock->lockscope@} is @expr{"DAV:shared"@}. //! //! The implementation must at least support the @expr{"DAV:write"@} //! lock type (RFC 2518, section 7). Briefly: An exclusive lock on a //! file prohibits other users from changing its content. An exclusive //! lock on a directory (aka collection) prohibits other users from //! adding or removing files or directories in it. An exclusive lock //! on a file or directory prohibits other users from setting or //! deleting any of its properties. A shared lock prohibits users //! without locks to do any of this, and it prohibits other users from //! obtaining an exclusive lock. A resource that doesn't exist can be //! locked, provided the directory it would be in exists (relaxed in
-
//! RFC 2518Bis (working draft)).
+
//! RFC 2518Bis (working draft)).
The default implementation fulfills
+
//! these criteria.
//! //! It's up to @[find_file] et al to actually check that the necessary //! locks are held. It can preferably use @[write_access] for that, //! which has a default implementation for checking //! @expr{"DAV:write"@} locks. //! //! @param path //! Normalized path (below the filesystem location) that the lock //! applies to. //! //! @param lock //! The lock to register. //! //! @returns //! Returns @expr{0@} if the lock is successfully installed or if //! locking isn't used. Returns a status mapping if an error //! occurred.
-
+
//!
+
//! @note
+
//! To use the default lock implementation, call @[register_lock]
+
//! from this function.
mapping(string:mixed) lock_file(string path, DAVLock lock, RequestID id) { return 0; } //! Remove @[lock] that currently is locking the resource at @[path].
-
+
//! It's assumed that the lock is registered for exactly that path.
//! //! @param path //! Normalized path (below the filesystem location) that the lock //! applies to. //! //! @param lock //! The lock to unregister. (It must not be changed or destructed.) //!
-
+
//! @param id
+
//! @mixed
+
//! @type RequestID
+
//! The request that attempted to unlock the lock. The function
+
//! should do the normal access checks before unlocking the lock
+
//! in this case.
+
//!
+
//! @type int(0..0)
+
//! The lock is unlocked internally by the server (typically due
+
//! to a timeout) and should be carried out without any access
+
//! checks. The function must succeed and return zero in this
+
//! case.
+
//! @endmixed
+
//!
//! @returns //! Returns a status mapping on any error, zero otherwise.
-
+
//!
+
//! @note
+
//! To use the default lock implementation, call @[unregister_lock]
+
//! from this function.
mapping(string:mixed) unlock_file (string path, DAVLock lock,
-
RequestID
id)
-
{
-
if
(
!sizeof (file_locks) && !sizeof (prefix_locks))
-
return
0
; // Lock system not in use
.
-
TRACE_ENTER(sprintf("unlock_file(%O, lock(%O), X)
.
", path, lock->locktoken
)
,
-
this);
-
mixed auth_user = authenticated_user_
id
(path, id
);
-
path = resource_id (path, id);
-
DAVLock removed_lock;
-
if (lock->recursive) {
-
removed_lock = m_delete(prefix_locks[path], auth_user);
-
if (!sizeof (prefix_locks[path])) m_delete (prefix_locks, path);
-
}
-
else if (file_locks[path]) {
-
removed_lock = m_delete (file_locks[path], auth_user);
-
if (!sizeof (file_locks[path])) m_delete (file_locks, path);
-
}
-
ASSERT_IF_DEBUG (lock /*%O*/ == removed_lock /*%O*/, lock, removed_lock);
-
TRACE_LEAVE("Ok.");
-
return 0;
-
}
+
RequestID
|int
(0..
0
) id);
//! Checks that the conditions specified by the WebDAV @expr{"If"@} //! header are fulfilled on the given path (RFC 2518 9.4). This means //! that locks are checked as necessary using @[check_locks]. //!
-
+
//! WARNING: This function has some design issues and will very likely
+
//! get a different interface. Compatibility is NOT guaranteed.
+
//!
//! @param path //! Path (below the filesystem location) that the lock applies to. //! //! @param recursive //! If @expr{1@} also check write access recursively under @[path]. //! //! @returns //! Returns @expr{0@} (zero) on success, a status mapping on //! failure, or @expr{1@} if @[recursive] is set and write access is //! allowed on this level but maybe not somewhere below. The caller
Roxen.git/server/base_server/module.pike:1132:
TRACE_LEAVE("Failed."); return res || Roxen.http_status(Protocols.HTTP.HTTP_PRECOND_FAILED); } //! Used by some default implementations to check if we may perform a //! write access to @[path]. It should at least call //! @[check_if_header] to check DAV locks. It takes the same arguments //! and has the same return value as that function. //!
+
//! WARNING: This function has some design issues and will very likely
+
//! get a different interface. Compatibility is NOT guaranteed.
+
//!
//! A filesystem module should typically put all needed write access //! checks here and then use this from @[find_file()], //! @[delete_file()] etc. static mapping(string:mixed)|int(0..1) write_access(string relative_path, int(0..1) recursive, RequestID id) { return check_if_header (relative_path, recursive, id); }
Roxen.git/server/base_server/module.pike:1262:
//! Source path below the filesystem location. //! //! @param destination //! Destination path below the filesystem location. //! //! @param behavior //! Specifies how to copy properties. See the @[PropertyBehavior] //! type for details. //! //! @returns
-
//! @expr{0@} (zero)
in
success or an appropriate status mapping for
+
//! @expr{0@} (zero)
on
success or an appropriate status mapping for
//! any error. static mapping(string:mixed) copy_properties(string source, string destination, PropertyBehavior behavior, RequestID id) { SIMPLE_TRACE_ENTER(this, "copy_properties(%O, %O, %O, %O)", source, destination, behavior, id); PropertySet source_properties = query_property_set(source, id); PropertySet destination_properties = query_property_set(destination, id); multiset(string) property_set = source_properties->query_all_properties();