Roxen.git / server / base_server / module.pike

version» Context lines:

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();