[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IFileSystem.py:1.1.2.1 ListProducer.py:1.1.2.1 MSDOSFileSystem.py:1.1.2.1 MergedFileSystem.py:1.1.2.1 OSFileSystem.py:1.1.2.1 UnixFileSystem.py:1.1.2.1 ZODBFileSystem.py:1.1.2.1 __init__.py:1.1.2.1
Stephan Richter
srichter@cbu.edu
Tue, 2 Apr 2002 00:08:09 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS
In directory cvs.zope.org:/tmp/cvs-serv6290/lib/python/Zope/Server/VFS
Added Files:
Tag: Zope3-Server-Branch
IFileSystem.py ListProducer.py MSDOSFileSystem.py
MergedFileSystem.py OSFileSystem.py UnixFileSystem.py
ZODBFileSystem.py __init__.py
Log Message:
Issue 53: Comment
- Created a bunch of interfaces that let us know what is going on.
- Split, updated and zopefied the Logger code.
- Reorganized dir structure in Zope.Server
- HTTP component split up in files (HTTP server works)
- Inserted Shane's skeleton FTP code (since I like his better than mine)
- Took a first cut at the Virtual File System (VFS) by copying and updating
medusa'a old filesys.py code.
=== Added File Zope3/lib/python/Zope/Server/VFS/IFileSystem.py ===
##############################################################################
#
# 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: IFileSystem.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""
from Interface import Interface
class IFileSystem(Interface):
"""We want to provide a complete wrapper around any and all
filesystem operations.
Opening files for reading, and listing directories, should
return a producer.
"""
def current_directory():
"""Return a string representing the current directory."""
def listdir(path, long=0):
"""Return a listing of the directory at 'path' The empty string
indicates the current directory. If 'long' is set, instead
return a list of (name, stat_info) tuples
"""
def open(path, mode):
"""Return an open file object.
"""
def stat(path):
"""Return the equivalent of os.stat() on the given path.
"""
def isdir(path):
"""Does the path represent a directory?
"""
def isfile(path):
"""Does the path represent a plain file?
"""
def cwd(path):
"""Change the working directory.
"""
def cdup():
"""Change to the parent of the current directory.
"""
def longify(path):
"""Return a 'long' representation of the filename
[for the output of the LIST command]
"""
=== Added File Zope3/lib/python/Zope/Server/VFS/ListProducer.py ===
##############################################################################
#
# 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: ListProducer.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""
class ListProducer:
"""Produces a string, representing a list of files. Note that not all
files will be displayed at once.
"""
def __init__ (self, file_list, long, longify, batch_size=50):
self.file_list = file_list
self.long = long
self.longify = longify
self.batch_size = int(batch_size)
self.done = 0
def ready(self):
if len(self.file_list):
return 1
else:
if not self.done:
self.done = 1
return 0
def more (self):
# Check whether we have elements in the first place
if not self.file_list:
return ''
else:
# Now determine how many files to display
batch_size = self.batch_size
if batch_size > len(self.file_list):
batch_size = len(self.file_list)
# get the set we want
batch = self.file_list[:batch_size]
# Do we want to have fancy long output?
if self.long:
batch = map(self.longify, batch)
# Remove the displayed files from the list.
self.file_list = self.file_list[self.batch_size:]
return '\r\n'.join(batch) + '\r\n'
=== Added File Zope3/lib/python/Zope/Server/VFS/MSDOSFileSystem.py ===
##############################################################################
#
# 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: MSDOSFileSystem.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""
from OSFileSystem import OSFileSystem
class MSDOSFileSystem(OSFileSystem):
"""This is a generic MS-DOS-like FileSystem. It mimics MS-DOS' output.
"""
__implements__ = OFFileSystem.__implements__
def longify(self, (path, stat_info)):
return msdos_longify(path, stat_info)
def msdos_longify(file, stat_info):
"""This matches the output of NT's ftp server (when in MSDOS mode)
exactly.
"""
if stat.S_ISDIR (stat_info[stat.ST_MODE]):
dir = '<DIR>'
else:
dir = ' '
date = msdos_date (stat_info[stat.ST_MTIME])
return '%s %s %8d %s' % (date, dir, stat_info[stat.ST_SIZE], file)
def msdos_date(t):
try:
info = time.gmtime(t)
except:
info = time.gmtime(0)
# year, month, day, hour, minute, second, ...
if info[3] > 11:
merid = 'PM'
info[3] = info[3] - 12
else:
merid = 'AM'
return '%02d-%02d-%02d %02d:%02d%s' % (
info[1], info[2], info[0]%100, info[3], info[4], merid )
=== Added File Zope3/lib/python/Zope/Server/VFS/MergedFileSystem.py ===
##############################################################################
#
# 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: MergedFileSystem.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""
class MergedFileSystem:
"""A merged filesystem will let you plug other filesystems
together. We really need the equivalent of a 'mount'
capability - this seems to be the most general idea. So you'd
use a 'mount' method to place another filesystem somewhere in
the hierarchy.
Note: this is most likely how I will handle ~user directories
with the http server.
"""
def __init__ (self, *fsys):
pass
=== Added File Zope3/lib/python/Zope/Server/VFS/OSFileSystem.py ===
##############################################################################
#
# 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: OSFileSystem.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""
import os, re
import stat
import time
from IFileSystem import IFileSystem
class OSFileSystem:
"""Generic OS FileSystem implementation.
"""
__implements__ = IFileSystem
path_module = os.path
# set this to zero if you want to disable pathname globbing.
# [we currently don't glob, anyway]
do_globbing = 1
def __init__ (self, root, wd='/'):
self.root = root
self.wd = wd
############################################################
# Implementation methods for interface
# Zope.Server.VFS.IFileSystem
def current_directory(self):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
return self.wd
def listdir(self, path, long=0):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
p = self.translate (path)
# I think we should glob, but limit it to the current
# directory only.
ld = os.listdir(p)
if not long:
return list_producer (ld, 0, None)
else:
old_dir = os.getcwd()
try:
os.chdir (p)
# if os.stat fails we ignore that file.
result = filter(None, map(safe_stat, ld))
finally:
os.chdir (old_dir)
return list_producer (result, 1, self.longify)
def open(self, path, mode):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
p = self.translate (path)
return open (p, mode)
# XXX: implement a cache w/timeout for stat()
def stat(self, path):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
p = self.translate(path)
return os.stat (p)
def isdir(self, path):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
p = self.normalize (self.path_module.join (self.wd, path))
return self.path_module.isdir (self.translate(p))
def isfile(self, path):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
p = self.normalize (self.path_module.join (self.wd, path))
return self.path_module.isfile (self.translate(p))
def cwd(self, path):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
p = self.normalize (self.path_module.join (self.wd, path))
translated_path = self.translate(p)
if not self.path_module.isdir (translated_path):
return 0
else:
old_dir = os.getcwd()
# temporarily change to that directory, in order
# to see if we have permission to do so.
try:
can = 0
try:
os.chdir (translated_path)
can = 1
self.wd = p
except:
pass
finally:
if can:
os.chdir (old_dir)
return can
def cdup(self):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
return self.cwd('..')
def longify(self, path):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
return unix_longify (path, stat_info)
#
############################################################
def unlink (self, path):
p = self.translate (path)
return os.unlink (p)
def mkdir (self, path):
p = self.translate (path)
return os.mkdir (p)
def rmdir (self, path):
p = self.translate (path)
return os.rmdir (p)
# utility methods
def normalize (self, path):
# watch for the ever-sneaky '/+' path element
path = re.sub('/+', '/', path)
p = self.path_module.normpath (path)
# remove 'dangling' cdup's.
if len(p) > 2 and p[:3] == '/..':
p = '/'
return p
def translate (self, path):
"""We need to join together three separate path components,
and do it safely. <real_root>/<current_directory>/<path>
use the operating system's path separator.
"""
path = os.sep.join('/'.split(path))
p = self.normalize(self.path_module.join(self.wd, path))
p = self.normalize(self.path_module.join(self.root, p[1:]))
return p
def __repr__ (self):
return '<Unix-Style FS Root:%s CWD:%s>' % (self.root, self.wd)
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
mode_table = {
'0':'---',
'1':'--x',
'2':'-w-',
'3':'-wx',
'4':'r--',
'5':'r-x',
'6':'rw-',
'7':'rwx'
}
def unix_longify (file, stat_info):
# for now, only pay attention to the lower bits
mode = ('%o' % stat_info[stat.ST_MODE])[-3:]
mode = ''.join(map (lambda x: mode_table[x], mode))
if stat.S_ISDIR (stat_info[stat.ST_MODE]):
dirchar = 'd'
else:
dirchar = '-'
date = ls_date (long(time.time()), stat_info[stat.ST_MTIME])
return '%s%s %3d %-8s %-8s %8d %s %s' % (
dirchar,
mode,
stat_info[stat.ST_NLINK],
stat_info[stat.ST_UID],
stat_info[stat.ST_GID],
stat_info[stat.ST_SIZE],
date,
file
)
def ls_date (now, t):
"""Emulate the unix 'ls' command's date field. it has two formats
- if the date is more than 180 days in the past, then it's like
this: Oct 19 1995 otherwise, it looks like this: Oct 19 17:33
"""
try:
info = time.gmtime(t)
except:
info = time.gmtime(0)
# 15,600,000 == 86,400 * 180
if (now - t) > 15600000:
return '%s %2d %d' % (
months[info[1]-1],
info[2],
info[0]
)
else:
return '%s %2d %02d:%02d' % (
months[info[1]-1],
info[2],
info[3],
info[4]
)
def safe_stat (path):
try:
return (path, os.stat (path))
except:
return None
=== Added File Zope3/lib/python/Zope/Server/VFS/UnixFileSystem.py ===
##############################################################################
#
# 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: UnixFileSystem.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""
import os
from OSFileSystem import OSFileSystem
class UnixFileSystem(OSFileSystem):
"""Generic Unix File System."""
__implements__ = OFFileSystem.__implements__
class SchizophrenicUnixFileSystem(OSFileSystem):
"""This File System always wants to be called with a specific user in mind.
"""
__implements__ = OFFileSystem.__implements__
# Get process information
PROCESS_UID = os.getuid()
PROCESS_EUID = os.geteuid()
PROCESS_GID = os.getgid()
PROCESS_EGID = os.getegid()
def __init__ (self, root, wd='/', persona=(None, None)):
super(SchizophrenicUnixFileSystem, self).__init__(root, wd)
self.persona = persona
def become_persona (self):
if self.persona is not (None, None):
uid, gid = self.persona
# the order of these is important!
os.setegid(gid)
os.seteuid(uid)
def become_nobody (self):
if self.persona is not (None, None):
os.seteuid(self.PROCESS_UID)
os.setegid(self.PROCESS_GID)
############################################################
# Implementation methods for interface
# Zope.Server.VFS.IFileSystem
def cwd (self, path):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
try:
self.become_persona()
return super(SchizophrenicUnixFileSystem, self).cwd(path)
finally:
self.become_nobody()
def cdup (self, path):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
try:
self.become_persona()
return super(SchizophrenicUnixFileSystem, self).cdup()
finally:
self.become_nobody()
def open (self, filename, mode):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
try:
self.become_persona()
return super(SchizophrenicUnixFileSystem, self).open(filename,
mode)
finally:
self.become_nobody()
def listdir (self, path, long=0):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
try:
self.become_persona()
return super(SchizophrenicUnixFileSystem, self).listdir(path, long)
finally:
self.become_nobody()
#
############################################################
=== Added File Zope3/lib/python/Zope/Server/VFS/ZODBFileSystem.py ===
##############################################################################
#
# 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: ZODBFileSystem.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""
import os, re
import stat
import time
from IFileSystem import IFileSystem
from ListProducer import ListProducer
from Zope.App.Traversing.ITraverser import ITraverser
from Zope.ComponentArchitecture import getAdapter
from Zope.App.OFS.Container.IContainer import IContainer
from Zope.ContextWrapper import wrapper
class ZODBFileSystem:
"""Generic OS FileSystem implementation.
"""
__implements__ = IFileSystem
def __init__ (self, publication, init_path='/'):
self._publication = publication
self._current = publication.traverse(init_path)
############################################################
# Implementation methods for interface
# Zope.Server.VFS.IFileSystem
def current_directory(self):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
traverser = getAdapter(self._current, ITraverser)
return '/' + '/'.join(traverser.getPhysicalPath())
def listdir(self, path, long=0):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
path = self.translate(path)
object = self._publication.traverse(path)
# XXX: Should check whether object is a Container
if not long:
list = object.objectIds()
return ListProducer(list, 0, None)
else:
list = object.objectItems()
return ListProducer(result, 1, self.longify)
def open(self, path, mode):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
p = self.translate (path)
return open (p, mode)
def stat(self, path):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
p = self.translate(path)
object = self._publication.traverse(path)
return object
def isdir(self, path):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
path = self.normalize('/'.join (self.current_directory(), path))
object = self._publication.traverse(path)
return IContainer.isImplementedBy(object)
def isfile(self, path):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
path = self.normalize('/'.join (self.current_directory(), path))
object = self._publication.traverse(path)
return not IContainer.isImplementedBy(object)
def cwd(self, path):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
path = self.normalize('/'.join (self.wd, path))
path = self.translate(path)
try:
self._current = self._publication.traverse(path)
return 1
except:
return 0
def cdup(self):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
parent = wrapper.getContext(self._current)
if parent is not None:
self._current = parent
return 1
else:
return 0
def longify(self, object):
'See Zope.Server.VFS.IFileSystem.IFileSystem'
return unix_longify (path, stat_info)
#
############################################################
def unlink (self, path):
""" """
pass
def mkdir (self, path):
""" """
pass
def rmdir (self, path):
""" """
pass
# utility methods
def normalize (self, path):
# watch for the ever-sneaky '/+' path element
path = re.sub('/+', '/', path)
p = self.path_module.normpath (path)
# remove 'dangling' cdup's.
if len(p) > 2 and p[:3] == '/..':
p = '/'
return p
def translate (self, path):
"""We need to join together three separate path components,
and do it safely. <real_root>/<current_directory>/<path>
use the operating system's path separator.
"""
path = os.sep.join('/'.split(path))
p = self.normalize(self.path_module.join(self.wd, path))
p = self.normalize(self.path_module.join(self.root, p[1:]))
return p
def __repr__ (self):
return '<Unix-Style FS Root:%s CWD:%s>' % (self.root, self.wd)
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
mode_table = {
'0':'---',
'1':'--x',
'2':'-w-',
'3':'-wx',
'4':'r--',
'5':'r-x',
'6':'rw-',
'7':'rwx'
}
def unix_longify (file, stat_info):
# for now, only pay attention to the lower bits
mode = ('%o' % stat_info[stat.ST_MODE])[-3:]
mode = ''.join(map (lambda x: mode_table[x], mode))
if stat.S_ISDIR (stat_info[stat.ST_MODE]):
dirchar = 'd'
else:
dirchar = '-'
date = ls_date (long(time.time()), stat_info[stat.ST_MTIME])
return '%s%s %3d %-8s %-8s %8d %s %s' % (
dirchar,
mode,
stat_info[stat.ST_NLINK],
stat_info[stat.ST_UID],
stat_info[stat.ST_GID],
stat_info[stat.ST_SIZE],
date,
file
)
def ls_date (now, t):
"""Emulate the unix 'ls' command's date field. it has two formats
- if the date is more than 180 days in the past, then it's like
this: Oct 19 1995 otherwise, it looks like this: Oct 19 17:33
"""
try:
info = time.gmtime(t)
except:
info = time.gmtime(0)
# 15,600,000 == 86,400 * 180
if (now - t) > 15600000:
return '%s %2d %d' % (
months[info[1]-1],
info[2],
info[0]
)
else:
return '%s %2d %02d:%02d' % (
months[info[1]-1],
info[2],
info[3],
info[4]
)
def safe_stat (path):
try:
return (path, os.stat (path))
except:
return None
=== Added File Zope3/lib/python/Zope/Server/VFS/__init__.py ===
##############################################################################
#
# 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: __init__.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""