merged with trunk
[odoo/odoo.git] / addons / document_ftp / ftpserver / abstracted_fs.py
old mode 100644 (file)
new mode 100755 (executable)
index 5e7c8c1..7580a88
@@ -1,9 +1,8 @@
 # -*- encoding: utf-8 -*-
+
 import os
 import time
 from tarfile import filemode
-import StringIO
-import base64
 import logging
 import errno
 
@@ -12,12 +11,10 @@ import fnmatch
 
 import pooler
 import netsvc
-import os
+
 from service import security
 from osv import osv
-#from document.nodes import node_res_dir, node_res_obj
 from document.nodes import get_node_context
-import stat
 
 def _get_month_name(month):
     month=int(month)
@@ -76,8 +73,8 @@ class abstracted_fs(object):
                     cr.execute("SELECT 1 FROM pg_class WHERE relkind = 'r' AND relname = 'ir_module_module'")
                     if not cr.fetchone():
                         continue
-    
-                    cr.execute("SELECT id FROM ir_module_module WHERE name = 'document_ftp' AND state IN ('installed', 'to upgrade') ")
+
+                    cr.execute("SELECT id FROM ir_module_module WHERE name = 'document_ftp' AND state IN ('installed', 'to install', 'to upgrade') ")
                     res = cr.fetchone()
                     if res and len(res):
                         self.db_name_list.append(db_name)
@@ -87,8 +84,6 @@ class abstracted_fs(object):
             finally:
                 if cr is not None:
                     cr.close()
-                #if db is not None:
-                #    pooler.close_db(db_name)        
         return self.db_name_list
 
     def ftpnorm(self, ftppath):
@@ -117,7 +112,7 @@ class abstracted_fs(object):
     def ftp2fs(self, path_orig, data):
         raise DeprecationWarning()
 
-    def fs2ftp(self, node):        
+    def fs2ftp(self, node):
         """ Return the string path of a node, in ftp form
         """
         res='/'
@@ -125,7 +120,7 @@ class abstracted_fs(object):
             paths = node.full_path()
             res = '/' + node.context.dbname + '/' +  \
                 _to_decode(os.path.join(*paths))
-            
+
         return res
 
     def validpath(self, path):
@@ -141,7 +136,7 @@ class abstracted_fs(object):
         """ Create a children file-node under node, open it
             @return open node_descriptor of the created node
         """
-        objname = _to_unicode(objname) 
+        objname = _to_unicode(objname)
         cr , node, rem = datacr
         try:
             child = node.child(cr, objname)
@@ -151,19 +146,23 @@ class abstracted_fs(object):
 
                 ret = child.open_data(cr, mode)
                 cr.commit()
+                assert ret, "Cannot create descriptor for %r: %r" % (child, ret)
                 return ret
         except EnvironmentError:
             raise
-        except Exception,e:
+        except Exception:
             self._log.exception('Cannot locate item %s at node %s', objname, repr(node))
             pass
 
         try:
             child = node.create_child(cr, objname, data=None)
             ret = child.open_data(cr, mode)
+            assert ret, "cannot create descriptor for %r" % child
             cr.commit()
             return ret
-        except Exception,e:
+        except EnvironmentError:
+            raise
+        except Exception:
             self._log.exception('Cannot create item %s at node %s', objname, repr(node))
             raise OSError(1, 'Operation not permited.')
 
@@ -175,7 +174,7 @@ class abstracted_fs(object):
         try:
             res = node.open_data(cr, mode)
             cr.commit()
-        except TypeError, e:
+        except TypeError:
             raise IOError(errno.EINVAL, "No data")
         return res
 
@@ -186,12 +185,11 @@ class abstracted_fs(object):
         name.  Unlike mkstemp it returns an object with a file-like
         interface.
         """
-        raise NotImplementedError
+        raise NotImplementedError # TODO
 
         text = not 'b' in mode
         # for unique file , maintain version if duplicate file
         if dir:
-           # TODO
             cr = dir.cr
             uid = dir.uid
             pool = pooler.get_pool(node.context.dbname)
@@ -201,7 +199,6 @@ class abstracted_fs(object):
             if len(res):
                 pre = prefix.split('.')
                 prefix=pre[0] + '.v'+str(len(res))+'.'+pre[1]
-            #prefix = prefix + '.'
         return self.create(dir,suffix+prefix,text)
 
 
@@ -211,7 +208,7 @@ class abstracted_fs(object):
         if (not datacr) or datacr == (None, None, None):
             self.cwd = '/'
             self.cwd_node = None
-            return None        
+            return None
         if not datacr[1]:
             raise OSError(1, 'Operation not permitted')
         if datacr[1].type not in  ('collection','database'):
@@ -226,13 +223,13 @@ class abstracted_fs(object):
         cr, node, rem = datacr or (None, None, None)
         if not node:
             raise OSError(1, 'Operation not permited.')
-        
+
         try:
             basename =_to_unicode(basename)
             cdir = node.create_child_collection(cr, basename)
             self._log.debug("Created child dir: %r", cdir)
             cr.commit()
-        except Exception,e:
+        except Exception:
             self._log.exception('Cannot create dir "%s" at node %s', basename, repr(node))
             raise OSError(1, 'Operation not permited.')
 
@@ -243,15 +240,15 @@ class abstracted_fs(object):
 
     def get_cr(self, pathname):
         raise DeprecationWarning()
-    
+
     def get_crdata(self, line, mode='file'):
         """ Get database cursor, node and remainder data, for commands
-        
+
         This is the helper function that will prepare the arguments for
         any of the subsequent commands.
         It returns a tuple in the form of:
         @code        ( cr, node, rem_path=None )
-        
+
         @param line An absolute or relative ftp path, as passed to the cmd.
         @param mode A word describing the mode of operation, so that this
                     function behaves properly in the different commands.
@@ -285,14 +282,14 @@ class abstracted_fs(object):
 
         if os.path.isabs(path):
             # we have to start from root, again
-            while p_parts[0] == '':
+            while p_parts and p_parts[0] == '':
                 p_parts = p_parts[1:]
             # self._log.debug("Path parts: %r ", p_parts)
             if not p_parts:
                 raise IOError(errno.EPERM, 'Cannot perform operation at root dir')
             dbname = p_parts[0]
             if dbname not in self.db_list():
-                raise IOError(errno.ENOENT,'Invalid database path')
+                raise IOError(errno.ENOENT,'Invalid database path: %s' % dbname)
             try:
                 db = pooler.get_db(dbname)
             except Exception:
@@ -308,7 +305,6 @@ class abstracted_fs(object):
                 raise OSError(2, 'Authentification Required.')
             n = get_node_context(cr, uid, {})
             node = n.get_uri(cr, p_parts[1:])
-            # self._log.debug("get_crdata(abs): %r" % ( (cr, node, rem_path),))
             return (cr, node, rem_path)
         else:
             # we never reach here if cwd_node is not set
@@ -322,7 +318,6 @@ class abstracted_fs(object):
             if node is False and mode not in ('???'):
                 cr.close()
                 raise IOError(errno.ENOENT, 'Path does not exist')
-            # self._log.debug("get_crdata(rel): %r" % ( (cr, node, rem_path),))
             return (cr, node, rem_path)
 
     def get_node_cr_uid(self, node):
@@ -331,15 +326,15 @@ class abstracted_fs(object):
         assert node
         db = pooler.get_db(node.context.dbname)
         return db.cursor(), node.context.uid
-        
+
     def get_node_cr(self, node):
         """ Get the cursor for the database of a node
-        
-        The cursor is the only thing that a node will not store 
+
+        The cursor is the only thing that a node will not store
         persistenly, so we have to obtain a new one for each call.
         """
         return self.get_node_cr_uid(node)[0]
-        
+
     def listdir(self, datacr):
         """List the content of a directory."""
         class false_node(object):
@@ -350,7 +345,7 @@ class abstracted_fs(object):
             uuser = 'root'
             ugroup = 'root'
             type = 'database'
-            
+
             def __init__(self, db):
                 self.path = db
 
@@ -370,7 +365,6 @@ class abstracted_fs(object):
         """Remove the specified directory."""
         cr, node, rem = datacr
         assert node
-        cr = self.get_node_cr(node)
         node.rmcol(cr)
         cr.commit()
 
@@ -392,7 +386,7 @@ class abstracted_fs(object):
     def rename(self, src, datacr):
         """ Renaming operation, the effect depends on the src:
             * A file: read, create and remove
-            * A directory: change the parent and reassign childs to ressource
+            * A directory: change the parent and reassign children to ressource
         """
         cr = datacr[0]
         try:
@@ -401,7 +395,9 @@ class abstracted_fs(object):
             # API shouldn't wait for us to write the object
             assert (ret is True) or (ret is False)
             cr.commit()
-        except Exception,err:
+        except EnvironmentError:
+            raise
+        except Exception:
             self._log.exception('Cannot rename "%s" to "%s" at "%s"', src, datacr[2], datacr[1])
             raise OSError(1,'Operation not permited.')
 
@@ -432,7 +428,7 @@ class abstracted_fs(object):
     def getsize(self, datacr):
         """Return the size of the specified file in bytes."""
         if not (datacr and datacr[1]):
-            return 0L
+            raise IOError(errno.ENOENT, "No such file or directory")
         if datacr[1].type in ('file', 'content'):
             return datacr[1].get_data_len(datacr[0]) or 0L
         return 0L
@@ -441,7 +437,7 @@ class abstracted_fs(object):
     def getmtime(self, datacr):
         """Return the last modified time as a number of seconds since
         the epoch."""
-        
+
         node = datacr[1]
         if node.write_date or node.create_date:
             dt = (node.write_date or node.create_date)[:19]
@@ -487,12 +483,11 @@ class abstracted_fs(object):
     def get_list_dir(self, datacr):
         """"Return an iterator object that yields a directory listing
         in a form suitable for LIST command.
-        """        
+        """
         if not datacr:
             return None
         elif self.isdir(datacr[1]):
             listing = self.listdir(datacr)
-            #listing.sort()
             return self.format_list(datacr[0], datacr[1], listing)
         # if path is a file or a symlink we return information about it
         elif self.isfile(datacr[1]):
@@ -560,11 +555,11 @@ class abstracted_fs(object):
                 mtime = mname+' '+time.strftime("%d %H:%M", st_mtime)
             except ValueError:
                 mname=_get_month_name(time.strftime("%m"))
-                mtime = mname+' '+time.strftime("%d %H:%M")            
+                mtime = mname+' '+time.strftime("%d %H:%M")
             fpath = node.path
             if isinstance(fpath, (list, tuple)):
                 fpath = fpath[-1]
-            # formatting is matched with proftpd ls output            
+            # formatting is matched with proftpd ls output
             path=_to_decode(fpath)
             yield "%s %3s %-8s %-8s %8s %s %s\r\n" %(perms, nlinks, uname, gname,
                                                      size, mtime, path)
@@ -607,7 +602,7 @@ class abstracted_fs(object):
             # type + perm
             if self.isdir(node):
                 if 'type' in facts:
-                    type = 'type=dir;'                    
+                    type = 'type=dir;'
                 if 'perm' in facts:
                     perm = 'perm=%s;' %permdir
             else: