[CMF-checkins] CVS: CMF - DirectoryView.py:1.10 FSObject.py:1.4 utils.py:1.15

tseaver@digicool.com tseaver@digicool.com
Tue, 19 Jun 2001 22:17:27 -0400 (EDT)


Update of /cvs-repository/CMF/CMFCore
In directory korak.digicool.com:/tmp/cvs-serv6233/CMFCore

Modified Files:
	DirectoryView.py FSObject.py utils.py 
Log Message:


  - Hardened DirectoryView against objects which raise exceptions
    during initial reads (typically due to permission problems);
    these objects now capture and log the exception, and create
    a BadFile object which allows browsing the traceback via the
    ZMI (Tracker #317).



--- Updated File DirectoryView.py in package CMF --
--- DirectoryView.py	2001/06/04 02:31:03	1.9
+++ DirectoryView.py	2001/06/20 02:17:27	1.10
@@ -91,49 +91,18 @@
 import os
 from os import path, listdir, stat
 from Acquisition import aq_inner, aq_parent, aq_base
-from string import split, rfind, strip
+from string import split, rfind, strip, join
 from App.Common import package_home
 from OFS.ObjectManager import bad_id
 from OFS.Folder import Folder
 from AccessControl import ClassSecurityInfo
 from CMFCorePermissions import AccessContentsInformation
 import CMFCorePermissions
+from FSObject import BadFile
+from utils import expandpath, minimalpath
 
 __reload_module__ = 0
 
-def normalize(p):
-    return path.abspath(path.normcase(p))
-
-normINSTANCE_HOME = normalize(INSTANCE_HOME)
-normSOFTWARE_HOME = normalize(SOFTWARE_HOME)
-
-separators = (os.sep, os.altsep)
-
-def expandpath(p):
-    # Converts a minimal path to an absolute path.
-    if path.isabs(p):
-        return p
-    abs = path.join(normINSTANCE_HOME, p)
-    if path.exists(abs):
-        return abs
-    return path.join(normSOFTWARE_HOME, p)
-
-def minimalpath(p):
-    # Trims INSTANCE_HOME or SOFTWARE_HOME from a path.
-    p = path.abspath(p)
-    abs = normalize(p)
-    l = len(normINSTANCE_HOME)
-    if abs[:l] != normINSTANCE_HOME:
-        l = len(normSOFTWARE_HOME)
-        if abs[:l] != normSOFTWARE_HOME:
-            # Can't minimize.
-            return p
-    p = p[l:]
-    while p[:1] in separators:
-        p = p[1:]
-    return p
-
-
 class DirectoryInformation:
     data = None
     _v_last_read = 0
@@ -198,12 +167,13 @@
                     register_subdirs=changed)
             except:
                 from zLOG import LOG, ERROR
-                import sys
+                import sys, traceback
                 type,value,tb = sys.exc_info()
-                LOG('DirectoryView',
-                    ERROR,
-                    'Error during prepareContents:',
-                    "\nType:%s\nValue:%s\n" % (type,value))
+                LOG( 'DirectoryView'
+                   , ERROR
+                   , 'Error during prepareContents:'
+                   , traceback.format_exception( type, value, tb )
+                   )
                 self.data = {}
                 self.objects = ()
                     
@@ -265,7 +235,19 @@
                 if t is None:
                     t = registry.getTypeByExtension(ext)
                 if t is not None:
-                    ob = t(name, e_filepath, fullname=entry)
+                    try:
+                        ob = t(name, e_filepath, fullname=entry)
+                    except:
+                        from zLOG import LOG, ERROR
+                        import sys, traceback
+                        typ, val, tb = sys.exc_info()
+                        exc_lines = traceback.format_exception( typ, val, tb )
+                        LOG( 'DirectoryView', ERROR, join( exc_lines, '\n' ) )
+                        ob = BadFile( name
+                                    , e_filepath
+                                    , exc_str=join( exc_lines, '\r\n' )
+                                    , fullname=entry
+                                    )
                     ob_id = ob.getId()
                     data[ob_id] = ob
                     objects.append({'id': ob_id, 'meta_type': ob.meta_type})

--- Updated File FSObject.py in package CMF --
--- FSObject.py	2001/04/24 14:12:13	1.3
+++ FSObject.py	2001/06/20 02:17:27	1.4
@@ -93,7 +93,7 @@
 from OFS.SimpleItem import Item
 from DateTime import DateTime
 
-from DirectoryView import expandpath
+from utils import expandpath
 import CMFCorePermissions
 
 class FSObject(Acquisition.Implicit, Item):
@@ -193,3 +193,86 @@
         return self._filepath
 
 Globals.InitializeClass(FSObject)
+
+class BadFile( FSObject ):
+    """
+        Represent a file which was not readable or parseable
+        as its intended type.
+    """
+    meta_type = 'Bad File'
+    icon = 'p_/broken'
+
+    BAD_FILE_VIEW = """\
+<dtml-var manage_page_header>
+<dtml-var manage_tabs>
+<h2> Bad Filesystem Object: &dtml-getId; </h2>
+
+<h3> File Contents </h3>
+<pre>
+<dtml-var getFileContents>
+</pre>
+
+<h3> Exception </h3>
+<pre>
+<dtml-var getExceptionText>
+</pre>
+<dtml-var manage_page_footer>
+"""
+
+    manage_options=(
+        {'label':'Error', 'action':'manage_showError'},
+        )
+
+    def __init__( self, id, filepath, exc_str=''
+                , fullname=None, properties=None):
+        id = fullname or id # Use the whole filename.
+        self.exc_str = exc_str
+        self.file_contents = ''
+        FSObject.__init__(self, id, filepath, fullname, properties)
+
+    security = ClassSecurityInfo()
+
+    showError = Globals.HTML( BAD_FILE_VIEW )
+    security.declareProtected( CMFCorePermissions.ManagePortal
+                             , 'manage_showError' )
+    def manage_showError( self, REQUEST ):
+        """
+        """
+        return self.showError( self, REQUEST )
+
+    security.declarePrivate( '_readFile' )
+    def _readFile( self, reparse ):
+        """Read the data from the filesystem.
+        
+        Read the file indicated by exandpath(self._filepath), and parse the
+        data if necessary.  'reparse' is set when reading the second
+        time and beyond.
+        """
+        try:
+            fp = expandpath(self._filepath)
+            file = open(fp, 'rb')
+            try:
+                data = self.file_contents = file.read()
+            finally:
+                file.close()
+        except:
+            data = self.file_contents = None #give up
+        return data
+    
+    security.declarePublic( 'getFileContents' )
+    def getFileContents( self ):
+        """
+            Return the contents of the file, if we could read it.
+        """
+        return self.file_contents
+    
+    security.declarePublic( 'getExceptionText' )
+    def getExceptionText( self ):
+        """
+            Return the exception thrown while reading or parsing
+            the file.
+        """
+        return self.exc_str
+
+
+Globals.InitializeClass( BadFile )

--- Updated File utils.py in package CMF --
--- utils.py	2001/06/11 19:11:59	1.14
+++ utils.py	2001/06/20 02:17:27	1.15
@@ -567,7 +567,41 @@
         keylist = map(string.strip, keylist)
         out.extend(filter(operator.truth, keylist))
     return out
-    
+
+#
+#   Directory-handling utilities
+#
+def normalize(p):
+    return path.abspath(path.normcase(p))
+
+normINSTANCE_HOME = normalize(INSTANCE_HOME)
+normSOFTWARE_HOME = normalize(SOFTWARE_HOME)
+
+separators = (os.sep, os.altsep)
+
+def expandpath(p):
+    # Converts a minimal path to an absolute path.
+    if path.isabs(p):
+        return p
+    abs = path.join(normINSTANCE_HOME, p)
+    if path.exists(abs):
+        return abs
+    return path.join(normSOFTWARE_HOME, p)
+
+def minimalpath(p):
+    # Trims INSTANCE_HOME or SOFTWARE_HOME from a path.
+    p = path.abspath(p)
+    abs = normalize(p)
+    l = len(normINSTANCE_HOME)
+    if abs[:l] != normINSTANCE_HOME:
+        l = len(normSOFTWARE_HOME)
+        if abs[:l] != normSOFTWARE_HOME:
+            # Can't minimize.
+            return p
+    p = p[l:]
+    while p[:1] in separators:
+        p = p[1:]
+    return p
 
 if 0:
     # Hopefully we can use this.