# -*- encoding: utf-8 -*-
+
import os
import time
from tarfile import filemode
-import StringIO
-import base64
import logging
import errno
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)
elif month==11:return 'Nov'
elif month==12:return 'Dec'
-def _to_unicode(s):
- try:
- return s.decode('utf-8')
- except UnicodeError:
- try:
- return s.decode('latin')
- except UnicodeError:
- try:
- return s.encode('ascii')
- except UnicodeError:
- return s
-
-def _to_decode(s):
- try:
- return s.encode('utf-8')
- except UnicodeError:
- try:
- return s.encode('latin')
- except UnicodeError:
- try:
- return s.decode('ascii')
- except UnicodeError:
- return s
+from ftpserver import _to_decode, _to_unicode
+
class abstracted_fs(object):
"""A class used to interact with the file system, providing a high
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='installed' ")
+
+ 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)
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):
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='/'
paths = node.full_path()
res = '/' + node.context.dbname + '/' + \
_to_decode(os.path.join(*paths))
-
+
return res
def validpath(self, path):
""" 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)
raise OSError(1, 'Operation not permited.')
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)
- return child.open_data(cr, mode)
- except Exception,e:
+ ret = child.open_data(cr, mode)
+ assert ret, "cannot create descriptor for %r" % child
+ cr.commit()
+ return ret
+ except EnvironmentError:
+ raise
+ except Exception:
self._log.exception('Cannot create item %s at node %s', objname, repr(node))
raise OSError(1, 'Operation not permited.')
raise OSError(1, 'Operation not permited.')
# Reading operation
cr, node, rem = datacr
- res = node.open_data(cr, mode)
+ try:
+ res = node.open_data(cr, mode)
+ cr.commit()
+ except TypeError:
+ raise IOError(errno.EINVAL, "No data")
return res
# ok, but need test more
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)
if len(res):
pre = prefix.split('.')
prefix=pre[0] + '.v'+str(len(res))+'.'+pre[1]
- #prefix = prefix + '.'
return self.create(dir,suffix+prefix,text)
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'):
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.')
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.
if not os.path.isabs(path):
path = os.path.join(self.root, path)
- if path == '/' and mode in ('list', 'cwd'):
- return (None, None, None )
+ if path == '/' and mode in ('list', 'cwd'):
+ return (None, None, None )
- path = os.path.normpath(path) # again, for '/db/../ss'
+ path = _to_unicode(os.path.normpath(path)) # again, for '/db/../ss'
if path == '.': path = ''
if os.path.isabs(path) and self.cwd_node is not None \
if os.path.isabs(path):
# we have to start from root, again
- p_parts = p_parts[1:]
+ 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():
- return None
+ raise IOError(errno.ENOENT,'Invalid database path: %s' % dbname)
try:
db = pooler.get_db(dbname)
except Exception:
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):
uuser = 'root'
ugroup = 'root'
type = 'database'
-
+
def __init__(self, db):
self.path = db
"""Remove the specified directory."""
cr, node, rem = datacr
assert node
- cr = self.get_node_cr(node)
node.rmcol(cr)
cr.commit()
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:
# API shouldn't wait for us to write the object
assert (ret is True) or (ret is False)
cr.commit()
- except Exception,err:
- self._log.exception('Cannot rename "%s" to "%s" at "%s"', src, dst_basename, dst_basedir)
+ 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.')
def stat(self, node):
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].content_length or 0L
+ return datacr[1].get_data_len(datacr[0]) or 0L
return 0L
# Ok
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]
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]):
perms = filemode(node.unixperms) # permissions
nlinks = 1
size = node.content_length or 0L
- uname = node.uuser
- gname = node.ugroup
+ uname = _to_decode(node.uuser)
+ gname = _to_decode(node.ugroup)
# stat.st_mtime could fail (-1) if last mtime is too old
# in which case we return the local time as last mtime
try:
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)
# 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:
if 'unix.mode' in facts:
mode = 'unix.mode=%s;' %oct(node.unixperms & 0777)
if 'unix.uid' in facts:
- uid = 'unix.uid=%s;' % node.uuser
+ uid = 'unix.uid=%s;' % _to_decode(node.uuser)
if 'unix.gid' in facts:
- gid = 'unix.gid=%s;' % node.ugroup
+ gid = 'unix.gid=%s;' % _to_decode(node.ugroup)
# We provide unique fact (see RFC-3659, chapter 7.5.2) on
# posix platforms only; we get it by mixing st_dev and
# st_ino values which should be enough for granting an