[Zope3-checkins] CVS: Zope3/src/zope/server/vfs - __init__.py:1.2 osfilesystem.py:1.2 publisherfilesystem.py:1.2 testfilesystemaccess.py:1.2 usernamepassword.py:1.2
Jim Fulton
jim@zope.com
Wed, 25 Dec 2002 09:15:58 -0500
Update of /cvs-repository/Zope3/src/zope/server/vfs
In directory cvs.zope.org:/tmp/cvs-serv20790/src/zope/server/vfs
Added Files:
__init__.py osfilesystem.py publisherfilesystem.py
testfilesystemaccess.py usernamepassword.py
Log Message:
Grand renaming:
- Renamed most files (especially python modules) to lower case.
- Moved views and interfaces into separate hierarchies within each
project, where each top-level directory under the zope package
is a separate project.
- Moved everything to src from lib/python.
lib/python will eventually go away. I need access to the cvs
repository to make this happen, however.
There are probably some bits that are broken. All tests pass
and zope runs, but I haven't tried everything. There are a number
of cleanups I'll work on tomorrow.
=== Zope3/src/zope/server/vfs/__init__.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/vfs/__init__.py Wed Dec 25 09:15:28 2002
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
=== Zope3/src/zope/server/vfs/osfilesystem.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/vfs/osfilesystem.py Wed Dec 25 09:15:28 2002
@@ -0,0 +1,227 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Filesystem implementation for a real (unix-like) OS filesystem.
+
+$Id$
+"""
+import os
+import re
+import stat
+import datetime
+import fnmatch
+fromts = datetime.datetime.fromtimestamp
+
+from zope.server.interfaces.vfs import IPosixFileSystem
+
+
+class OSFileSystem(object):
+ """Generic OS FileSystem implementation.
+
+ The root of this file system is a string describing the path
+ to the directory used as root.
+ """
+
+ __implements__ = IPosixFileSystem
+
+ copy_bytes = 65536
+
+
+ def __init__ (self, root):
+ self.root = root
+
+ def chmod(self, path, mode):
+ 'See IWriteFileSystem'
+ p = self.translate (path)
+ return os.chmod(p, mode)
+
+
+ def chown(self, path, uid, gid):
+ 'See IWriteFileSystem'
+ p = self.translate (path)
+ return os.chown(p, uid, gid)
+
+
+ def link(self, src, dst):
+ 'See IWriteFileSystem'
+ src = self.translate(src)
+ dst = self.translate(dst)
+ return os.link(src, dst)
+
+
+ def mkfifo(self, path, mode=6*2**6):
+ 'See IWriteFileSystem'
+ return os.mkfifo(path, mode)
+
+
+ def symlink(self, src, dst):
+ 'See IWriteFileSystem'
+ src = self.translate(src)
+ dst = self.translate(dst)
+ return os.symlink(src, dst)
+
+ def exists(self, path):
+ 'See IReadFileSystem'
+ p = self.translate(path)
+ return os.path.exists(p)
+
+
+ def isdir(self, path):
+ 'See IReadFileSystem'
+ p = self.translate(path)
+ return os.path.isdir(p)
+
+
+ def isfile(self, path):
+ 'See IReadFileSystem'
+ p = self.translate(path)
+ return os.path.isfile(p)
+
+
+ def listdir(self, path, with_stats=0, pattern='*'):
+ 'See IReadFileSystem'
+ p = self.translate(path)
+ # list the directory's files
+ ld = os.listdir(p)
+ # filter them using the pattern
+ ld = filter(lambda f, p=pattern, fnm=fnmatch.fnmatch: fnm(f, p), ld)
+ # sort them alphabetically
+ ld.sort()
+ if not with_stats:
+ result = ld
+ else:
+ result = []
+ for file in ld:
+ path = os.path.join(p, file)
+ stat = safe_stat(path)
+ if stat is not None:
+ result.append((file, stat))
+ return result
+
+
+ def readfile(self, path, mode, outstream, start=0, end=-1):
+ 'See IReadFileSystem'
+ p = self.translate(path)
+ instream = open(p, mode)
+ if start:
+ instream.seek(start)
+ pos = start
+ while end < 0 or pos < end:
+ toread = self.copy_bytes
+ if end >= 0:
+ toread = min(toread, end - pos)
+ data = instream.read(toread)
+ if not data:
+ break
+ pos += len(data)
+ outstream.write(data)
+
+
+ def stat(self, path):
+ 'See IReadFileSystem'
+ p = self.translate(path)
+ stat = os.stat(p)
+ return stat[0:6], fromts(stat[7]), fromts(stat[8]), fromts(stat[9])
+
+ def mkdir(self, path, mode=6*2**6):
+ 'See IWriteFileSystem'
+ p = self.translate(path)
+ return os.mkdir(p, mode)
+
+
+ def remove(self, path):
+ 'See IWriteFileSystem'
+ p = self.translate (path)
+ return os.remove(p)
+
+
+ def rmdir(self, path):
+ 'See IWriteFileSystem'
+ p = self.translate (path)
+ return os.rmdir(p)
+
+
+ def rename(self, old, new):
+ 'See IWriteFileSystem'
+ old = self.translate(old)
+ new = self.translate(new)
+ return os.rename(old, new)
+
+
+ def writefile(self, path, mode, instream, start=0):
+ 'See IWriteFileSystem'
+ p = self.translate(path)
+ outstream = open(p, mode)
+ if start:
+ outstream.seek(start)
+ while 1:
+ data = instream.read(self.copy_bytes)
+ if not data:
+ break
+ outstream.write(data)
+
+ def check_writable(self, path):
+ 'See IWriteFileSystem'
+ p = self.translate(path)
+ if os.path.exists(p):
+ remove = 0
+ else:
+ remove = 1
+ f = open(p, 'a') # append mode
+ f.close()
+ if remove:
+ os.remove(p)
+
+ # utility methods
+
+ def normalize(self, path):
+ # watch for the ever-sneaky '/+' path element
+ # XXX It is unclear why "/+" is dangerous. It is definitely
+ # unexpected.
+ path = re.sub('/+', '/', path)
+ path = os.path.normpath(path)
+ if path.startswith('..'):
+ # Someone is trying to get lower than the permitted root.
+ # We just ignore it.
+ path = os.sep
+ return path
+
+
+ def translate(self, path):
+ """We need to join together three separate path components,
+ and do it safely. <real_root>/<path>
+ use the operating system's path separator.
+
+ We need to be extremly careful to include the cases where a hacker
+ could attempt to a directory below root!
+ """
+ # Normalize the directory
+ path = self.normalize(path)
+ # Prepare for joining with root
+ while path.startswith(os.sep):
+ path = path[1:]
+ # Join path with root
+ return os.path.join(self.root, path)
+
+
+ def __repr__(self):
+ return '<OSFileSystem, root=%s>' % self.root
+
+
+
+def safe_stat(path):
+ try:
+ stat = os.stat(path)
+ return stat[:7] + (fromts(stat[7]), fromts(stat[8]), fromts(stat[9]))
+ except OSError:
+ return None
=== Zope3/src/zope/server/vfs/publisherfilesystem.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/vfs/publisherfilesystem.py Wed Dec 25 09:15:28 2002
@@ -0,0 +1,180 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import re
+import stat
+import time
+import posixpath
+
+from cStringIO import StringIO
+
+from zope.server.interfaces.vfs import IReadFileSystem
+from zope.server.interfaces.vfs import IWriteFileSystem
+
+from zope.publisher.publish import publish
+
+
+
+class NoOutput:
+ """An output stream lookalike that warns you if you try to
+ dump anything into it."""
+
+ def write(self, data):
+ raise RuntimeError, "Not a writable stream"
+
+ def flush(self):
+ pass
+
+ close = flush
+
+
+
+class PublisherFileSystem:
+ """Generic Publisher FileSystem implementation.
+ """
+
+ __implements__ = IReadFileSystem, IWriteFileSystem
+
+ def __init__ (self, credentials, request_factory):
+ self.credentials = credentials
+ self.request_factory = request_factory
+
+
+ def _execute(self, path, command, env=None):
+ if env is None:
+ env = {}
+
+ env['command'] = command
+ env['path'] = path
+ env['credentials'] = self.credentials
+ # NoOutput avoids creating a black hole.
+ request = self.request_factory(StringIO(''), NoOutput(), env)
+ # Note that publish() calls close() on request, which deletes the
+ # response from the request, so that we need to keep track of it.
+ response = request.response
+ publish(request)
+ return response.getResult()
+
+ def exists(self, path):
+ 'See IReadFileSystem'
+ path = self.translate(path)
+ if path == '/':
+ return 1
+ path, file = posixpath.split(path)
+ env = {'name': file}
+ return self._execute(path, 'exists', env)
+
+
+ def isdir(self, path):
+ 'See IReadFileSystem'
+ path = self.translate(path)
+ return self._execute(path, 'isdir')
+
+
+ def isfile(self, path):
+ 'See IReadFileSystem'
+ path = self.translate(path)
+ return self._execute(path, 'isfile')
+
+
+ def listdir(self, path, with_stats=0, pattern='*'):
+ 'See IReadFileSystem'
+ path = self.translate(path)
+ env = {'with_stats' : with_stats,
+ 'pattern' : pattern}
+ return self._execute(path, 'listdir', env)
+
+
+ def readfile(self, path, mode, outstream, start=0, end=-1):
+ 'See IReadFileSystem'
+ path = self.translate(path)
+ env = {'mode' : mode,
+ 'outstream' : outstream,
+ 'start' : start,
+ 'end' : end}
+ return self._execute(path, 'read', env)
+
+
+ def stat(self, path):
+ 'See IReadFileSystem'
+ path = self.translate(path)
+ return self._execute(path, 'stat')
+
+ def mkdir(self, path, mode=777):
+ 'See IWriteFileSystem'
+ path = self.translate(path)
+ path, dir = posixpath.split(path)
+ env = {'name': dir}
+ return self._execute(path, 'mkdir', env)
+
+
+ def remove(self, path):
+ 'See IWriteFileSystem'
+ path = self.translate(path)
+ path, name = posixpath.split(path)
+ env = {'name': name}
+ return self._execute(path, 'remove', env)
+
+
+ def rmdir(self, path):
+ 'See IWriteFileSystem'
+ path = self.translate(path)
+ path, dir = posixpath.split(path)
+ env = {'name': dir}
+ return self._execute(path, 'rmdir', env)
+
+
+ def rename(self, old, new):
+ 'See IWriteFileSystem'
+ old = self.translate(old)
+ new = self.translate(new)
+ path0, old = posixpath.split(old)
+ path1, new = posixpath.split(new)
+ assert path0 == path1
+ env = {'old' : old,
+ 'new' : new}
+ return self._execute(path0, 'rename', env)
+
+ def writefile(self, path, mode, instream, start=0):
+ 'See IWriteFileSystem'
+ path = self.translate(path)
+ path, name = posixpath.split(path)
+ env = {'name' : name,
+ 'mode' : mode,
+ 'instream' : instream,
+ 'start' : start}
+ return self._execute(path, 'writefile', env)
+
+
+ def check_writable(self, path):
+ 'See IWriteFileSystem'
+ path = self.translate(path)
+ path, name = posixpath.split(path)
+ env = {'name' : name}
+ return self._execute(path, 'check_writable', env)
+
+ # utility methods
+
+ def translate (self, path):
+ # Normalize
+ path = posixpath.normpath(path)
+ if path.startswith('..'):
+ # Someone is trying to get lower than the permitted root.
+ # We just ignore it.
+ path = '/'
+ return path
=== Zope3/src/zope/server/vfs/testfilesystemaccess.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/vfs/testfilesystemaccess.py Wed Dec 25 09:15:28 2002
@@ -0,0 +1,44 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Implementation of IFilesystemAccess intended only for testing.
+
+$Id$
+"""
+
+from zope.server.interfaces.vfs import IFilesystemAccess
+from zope.server.interfaces.vfs import IUsernamePassword
+from zope.exceptions import Unauthorized
+
+
+class TestFilesystemAccess:
+
+ __implements__ = IFilesystemAccess
+
+ passwords = {'foo': 'bar'}
+
+ def __init__(self, fs):
+ self.fs = fs
+
+ def authenticate(self, credentials):
+ if not IUsernamePassword.isImplementedBy(credentials):
+ raise Unauthorized
+ name = credentials.getUserName()
+ if not (name in self.passwords):
+ raise Unauthorized
+ if credentials.getPassword() != self.passwords[name]:
+ raise Unauthorized
+
+ def open(self, credentials):
+ self.authenticate(credentials)
+ return self.fs
=== Zope3/src/zope/server/vfs/usernamepassword.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:15:58 2002
+++ Zope3/src/zope/server/vfs/usernamepassword.py Wed Dec 25 09:15:28 2002
@@ -0,0 +1,34 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.server.interfaces.vfs import IUsernamePassword
+
+
+class UsernamePassword:
+
+ __implements__ = IUsernamePassword
+
+ def __init__(self, username, password):
+ self.username = username
+ self.password = password
+
+ def getUserName(self):
+ return self.username
+
+ def getPassword(self):
+ return self.password