bzr revid: hmo@tinyerp.com-20100712074657-wiqjddnycxzq2qz5
This commit is contained in:
Harry (OpenERP)
2010-07-12 13:16:57 +05:30
4 changed files with 237 additions and 18 deletions
+16
View File
@@ -198,6 +198,22 @@ class document_directory(osv.osv):
return nodes.get_node_context(cr, uid, context).get_uri(cr, uri)
def get_dir_permissions(self, cr, uid, ids ):
"""Check what permission user 'uid' has on directory 'id'
"""
assert len(ids) == 1
id = ids[0]
cr.execute( "SELECT count(dg.item_id) AS needs, count(ug.uid) AS has " \
" FROM document_directory_group_rel dg " \
" LEFT OUTER JOIN res_groups_users_rel ug " \
" ON (dg.group_id = ug.gid AND ug.uid = %s) " \
" WHERE dg.item_id = %s ", (uid, id))
needs, has = cr.fetchone()
if needs and not has:
return 1 # still allow to descend into.
else:
return 15
def _locate_child(self, cr, uid, root_id, uri,nparent, ncontext):
""" try to locate the node in uri,
+83 -6
View File
@@ -98,15 +98,51 @@ class nodefd_file(nodes.node_descriptor):
def __init__(self, parent, path, mode):
nodes.node_descriptor.__init__(self, parent)
self.__file = open(path, mode)
if mode in ('w', 'w+', 'r+'):
self._need_index = True
else:
self._need_index = False
for attr in ('closed', 'read', 'write', 'seek', 'tell'):
setattr(self,attr, getattr(self.__file, attr))
def close(self):
# TODO: locking in init, close()
fname = self.__file.name
self.__file.close()
if self._need_index:
par = self._get_parent()
cr = pooler.get_db(par.context.dbname).cursor()
icont = ''
mime = ''
filename = par.path
if isinstance(filename, (tuple, list)):
filename = '/'.join(filename)
try:
mime, icont = cntIndex.doIndex(None, filename=filename,
content_type=None, realfname=fname)
except Exception:
logging.getLogger('document.storage').debug('Cannot index file:', exc_info=True)
pass
try:
icont_u = ustr(icont)
except UnicodeError:
icont_u = ''
try:
cr.execute('UPDATE ir_attachment SET index_content = %s, file_type = %s WHERE id = %s',
(icont_u, mime, par.file_id))
par.content_length = filesize
par.content_type = mime
cr.commit()
cr.close()
except Exception:
logging.getLogger('document.storage').debug('Cannot save file indexed content:', exc_info=True)
class nodefd_db(StringIO, nodes.node_descriptor):
""" A descriptor to db data
"""
@@ -140,9 +176,30 @@ class nodefd_db(StringIO, nodes.node_descriptor):
try:
if self.mode in ('w', 'w+', 'r+'):
data = self.getvalue()
icont = ''
mime = ''
filename = par.path
if isinstance(filename, (tuple, list)):
filename = '/'.join(filename)
try:
mime, icont = cntIndex.doIndex(data, filename=filename,
content_type=None, realfname=None)
except Exception:
logging.getLogger('document.storage').debug('Cannot index file:', exc_info=True)
pass
try:
icont_u = ustr(icont)
except UnicodeError:
icont_u = ''
out = psycopg2.Binary(data)
cr.execute("UPDATE ir_attachment SET db_datas = %s, file_size=%s WHERE id = %s",
(out, len(data), par.file_id))
cr.execute("UPDATE ir_attachment " \
"SET db_datas = %s, file_size=%s, " \
" index_content= %s, file_type=%s " \
" WHERE id = %s",
(out, len(data), icont_u, mime, par.file_id))
elif self.mode == 'a':
data = self.getvalue()
out = psycopg2.Binary(data)
@@ -191,9 +248,29 @@ class nodefd_db64(StringIO, nodes.node_descriptor):
cr = pooler.get_db(par.context.dbname).cursor()
try:
if self.mode in ('w', 'w+', 'r+'):
out = self.getvalue()
cr.execute('UPDATE ir_attachment SET db_datas = %s::bytea, file_size=%s WHERE id = %s',
(base64.encodestring(out), len(out), par.file_id))
data = self.getvalue()
icont = ''
mime = ''
filename = par.path
if isinstance(filename, (tuple, list)):
filename = '/'.join(filename)
try:
mime, icont = cntIndex.doIndex(data, filename=filename,
content_type=None, realfname=None)
except Exception:
logging.getLogger('document.storage').debug('Cannot index file:', exc_info=True)
pass
try:
icont_u = ustr(icont)
except UnicodeError:
icont_u = ''
cr.execute('UPDATE ir_attachment SET db_datas = %s::bytea, file_size=%s, ' \
'index_content = %s, file_type = %s ' \
'WHERE id = %s',
(base64.encodestring(out), len(out), icont_u, mime, par.file_id))
elif self.mode == 'a':
out = self.getvalue()
# Yes, we're obviously using the wrong representation for storing our
+134 -8
View File
@@ -163,6 +163,7 @@ class node_class(object):
self.context = context
self.type=self.our_type
self.parent = parent
self.uidperms = 5 # computed permissions for our uid, in unix bits
self.mimetype = 'application/octet-stream'
self.create_date = None
self.write_date = None
@@ -316,6 +317,33 @@ class node_class(object):
def get_domain(self, cr, filters):
return []
def check_perms(self, perms):
""" Check the permissions of the current node.
@param perms either an integers of the bits to check, or
a string with the permission letters
Permissions of nodes are (in a unix way):
1, x : allow descend into dir
2, w : allow write into file, or modification to dir
4, r : allow read of file, or listing of dir contents
8, u : allow remove (unlink)
"""
if isinstance(perms, str):
pe2 = 0
chars = { 'x': 1, 'w': 2, 'r': 4, 'u': 8 }
for c in perms:
pe2 = pe2 | chars[c]
perms = pe2
elif isinstance(perms, int):
if perms < 0 or perms > 15:
raise ValueError("Invalid permission bits")
else:
raise ValueError("Invalid permission attribute")
return ((self.uidperms & perms) == perms)
class node_database(node_class):
""" A node representing the database directory
@@ -324,6 +352,7 @@ class node_database(node_class):
def __init__(self, path=[], parent=False, context=None):
super(node_database,self).__init__(path, parent, context)
self.unixperms = 040750
self.uidperms = 5
def children(self, cr, domain=None):
res = self._child_get(cr, domain=domain) + self._file_get(cr)
@@ -346,6 +375,13 @@ class node_database(node_class):
where = [('parent_id','=',parent_id)]
if name:
where.append(('name','=',name))
is_allowed = self.check_perms(1)
else:
is_allowed = self.check_perms(5)
if not is_allowed:
raise IOError(errno.EPERM, "Permission into directory denied")
if not domain:
domain = []
@@ -374,6 +410,16 @@ class node_database(node_class):
def _get_ttag(self,cr):
return 'db-%s' % cr.dbname
def mkdosname(company_name, default='noname'):
""" convert a string to a dos-like name"""
if not company_name:
return default
badchars = ' !@#$%^`~*()+={}[];:\'"/?.<>'
n = ''
for c in company_name[:8]:
n += (c in badchars and '_') or c
return n
class node_dir(node_database):
our_type = 'collection'
@@ -390,6 +436,9 @@ class node_dir(node_database):
self.write_date = dirr and (dirr.write_date or dirr.create_date) or False
self.content_length = 0
self.unixperms = 040750
self.uuser = (dirr.user_id and dirr.user_id.login) or 'nobody'
self.ugroup = mkdosname(dirr.company_id and dirr.company_id.name, default='nogroup')
self.uidperms = dirr.get_dir_permissions()
if dctx:
self.dctx.update(dctx)
dc2 = self.context.context
@@ -417,14 +466,18 @@ class node_dir(node_database):
return self.dir_id == other.dir_id
def get_data(self, cr):
res = ''
for child in self.children(cr):
res += child.get_data(cr)
return res
#res = ''
#for child in self.children(cr):
# res += child.get_data(cr)
return None
def _file_get(self, cr, nodename=False):
res = super(node_dir,self)._file_get(cr, nodename)
is_allowed = self.check_perms(nodename and 1 or 5)
if not is_allowed:
raise IOError(errno.EPERM, "Permission into directory denied")
cntobj = self.context._dirobj.pool.get('document.directory.content')
uid = self.context.uid
ctx = self.context.context.copy()
@@ -437,7 +490,7 @@ class node_dir(node_database):
res.extend(res3)
return res
def _child_get(self, cr, name=None, domain=None):
return super(node_dir,self)._child_get(cr, name, self.dir_id, domain=domain)
@@ -447,6 +500,9 @@ class node_dir(node_database):
res = False
if not directory:
raise OSError(2, 'Not such file or directory.')
if not self.check_perms('u'):
raise IOError(errno.EPERM,"Permission denied")
if directory._table_name=='document.directory':
if self.children(cr):
raise OSError(39, 'Directory not empty.')
@@ -457,6 +513,9 @@ class node_dir(node_database):
def create_child_collection(self, cr, objname):
object2 = False
if not self.check_perms(2):
raise IOError(errno.EPERM,"Permission denied")
dirobj = self.context._dirobj
uid = self.context.uid
ctx = self.context.context.copy()
@@ -480,6 +539,9 @@ class node_dir(node_database):
""" API function to create a child file object and node
Return the node_* created
"""
if not self.check_perms(2):
raise IOError(errno.EPERM,"Permission denied")
dirobj = self.context._dirobj
uid = self.context.uid
ctx = self.context.context.copy()
@@ -523,6 +585,9 @@ class node_dir(node_database):
if ndir_node and (ndir_node.context != self.context):
raise NotImplementedError("Cannot move directories between contexts")
if (not self.check_perms('u')) or (not ndir_node.check_perms('w')):
raise IOError(errno.EPERM,"Permission denied")
dir_obj = self.context._dirobj
if not fil_obj:
dbro = dir_obj.browse(cr, self.context.uid, self.dir_id, context=self.context.context)
@@ -577,6 +642,9 @@ class node_res_dir(node_class):
self.write_date = dirr.write_date or dirr.create_date
self.content_length = 0
self.unixperms = 040750
self.uuser = (dirr.user_id and dirr.user_id.login) or 'nobody'
self.ugroup = mkdosname(dirr.company_id and dirr.company_id.name, default='nogroup')
self.uidperms = dirr.get_dir_permissions()
self.res_model = dirr.ressource_type_id and dirr.ressource_type_id.model or False
self.resm_id = dirr.ressource_id
self.namefield = dirr.resource_field.name or 'name'
@@ -643,6 +711,12 @@ class node_res_dir(node_class):
if name:
where.append((self.namefield,'=',name))
is_allowed = self.check_perms(1)
else:
is_allowed = self.check_perms(5)
if not is_allowed:
raise IOError(errno.EPERM,"Permission denied")
# print "Where clause for %s" % self.res_model, where
if self.ressource_tree:
@@ -687,6 +761,9 @@ class node_res_obj(node_class):
self.write_date = parent.write_date
self.content_length = 0
self.unixperms = 040750
self.uidperms = parent.uidperms & 0x15
self.uuser = parent.uuser
self.ugroup = parent.ugroup
self.res_model = res_model
self.domain = parent.domain
self.displayname = path
@@ -737,6 +814,10 @@ class node_res_obj(node_class):
def _file_get(self,cr, nodename=False):
res = []
is_allowed = self.check_perms((nodename and 1) or 5)
if not is_allowed:
raise IOError(errno.EPERM,"Permission denied")
cntobj = self.context._dirobj.pool.get('document.directory.content')
uid = self.context.uid
ctx = self.context.context.copy()
@@ -784,6 +865,11 @@ class node_res_obj(node_class):
def _child_get(self, cr, name=None, domain=None):
dirobj = self.context._dirobj
is_allowed = self.check_perms((name and 1) or 5)
if not is_allowed:
raise IOError(errno.EPERM,"Permission denied")
uid = self.context.uid
ctx = self.context.context.copy()
ctx.update(self.dctx)
@@ -847,6 +933,10 @@ class node_res_obj(node_class):
def create_child_collection(self, cr, objname):
dirobj = self.context._dirobj
is_allowed = self.check_perms(2)
if not is_allowed:
raise IOError(errno.EPERM,"Permission denied")
uid = self.context.uid
ctx = self.context.context.copy()
ctx.update(self.dctx)
@@ -874,6 +964,10 @@ class node_res_obj(node_class):
""" API function to create a child file object and node
Return the node_* created
"""
is_allowed = self.check_perms(2)
if not is_allowed:
raise IOError(errno.EPERM,"Permission denied")
dirobj = self.context._dirobj
uid = self.context.uid
ctx = self.context.context.copy()
@@ -910,6 +1004,16 @@ class node_file(node_class):
self.write_date = fil.write_date or fil.create_date
self.content_length = fil.file_size
self.displayname = fil.name
self.uidperms = 14
if parent:
if not parent.check_perms('x'):
self.uidperms = 0
elif not parent.check_perms('w'):
self.uidperms = 4
self.uuser = (fil.user_id and fil.user_id.login) or 'nobody'
self.ugroup = mkdosname(fil.company_id and fil.company_id.name, default='nogroup')
# This only propagates the problem to get_data. Better
# fix those files to point to the root dir.
@@ -934,6 +1038,9 @@ class node_file(node_class):
def open_data(self, cr, mode):
stor = self.storage_id
assert stor, "No storage for file #%s" % self.file_id
if not self.check_perms(4):
raise IOError(errno.EPERM, "Permission denied")
# If storage is not set properly, we are just screwed here, don't
# try to get it from default.
stobj = self.context._dirobj.pool.get('document.storage')
@@ -941,6 +1048,8 @@ class node_file(node_class):
def rm(self, cr):
uid = self.context.uid
if not self.check_perms(8):
raise IOError(errno.EPERM, "Permission denied")
document_obj = self.context._dirobj.pool.get('ir.attachment')
if self.type in ('collection','database'):
return False
@@ -985,6 +1094,9 @@ class node_file(node_class):
# this is where storage kicks in..
stor = self.storage_id
assert stor, "No storage for file #%s" % self.file_id
if not self.check_perms(4):
raise IOError(errno.EPERM, "Permission denied")
# If storage is not set properly, we are just screwed here, don't
# try to get it from default.
stobj = self.context._dirobj.pool.get('document.storage')
@@ -1005,6 +1117,9 @@ class node_file(node_class):
# this is where storage kicks in..
stor = self.storage_id
assert stor, "No storage for file #%s" % self.file_id
if not self.check_perms(2):
raise IOError(errno.EPERM, "Permission denied")
stobj = self.context._dirobj.pool.get('document.storage')
return stobj.set_data(cr, self.context.uid,stor, self, data, self.context.context, fil_obj)
@@ -1015,6 +1130,9 @@ class node_file(node_class):
if ndir_node.context != self.context:
raise NotImplementedError("Cannot move files between contexts")
if (not self.check_perms(8)) and ndir_node.check_perms(2):
raise IOError(errno.EPERM, "Permission denied")
doc_obj = self.context._dirobj.pool.get('ir.attachment')
if not fil_obj:
dbro = doc_obj.browse(cr, self.context.uid, self.file_id, context=self.context.context)
@@ -1030,9 +1148,6 @@ class node_file(node_class):
self.parent = self.context.get_dir_node(cr, dbro.parent_id.id)
assert self.parent
# TODO: test if parent is writable.
ret = {}
if self.parent != ndir_node:
if not (isinstance(self.parent, node_dir) and isinstance(ndir_node, node_dir)):
@@ -1076,6 +1191,11 @@ class node_content(node_class):
self.write_date = False
self.content_length = False
self.unixperms = 0640
if parent:
self.uidperms = parent.uidperms & 14
self.uuser = parent.uuser
self.ugroup = parent.ugroup
self.extension = cnt.extension
self.report_id = cnt.report_id and cnt.report_id.id
#self.mimetype = cnt.extension.
@@ -1103,6 +1223,9 @@ class node_content(node_class):
def get_data(self, cr, fil_obj = None):
cntobj = self.context._dirobj.pool.get('document.directory.content')
if not self.check_perms(4):
raise IOError(errno.EPERM, "Permission denied")
ctx = self.context.context.copy()
ctx.update(self.dctx)
data = cntobj.process_read(cr, self.context.uid, self, ctx)
@@ -1117,6 +1240,9 @@ class node_content(node_class):
def set_data(self, cr, data, fil_obj = None):
cntobj = self.context._dirobj.pool.get('document.directory.content')
if not self.check_perms(2):
raise IOError(errno.EPERM, "Permission denied")
ctx = self.context.context.copy()
ctx.update(self.dctx)
return cntobj.process_write(cr, self.context.uid, self, data, ctx)
@@ -539,8 +539,8 @@ class abstracted_fs(object):
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:
@@ -637,9 +637,9 @@ class abstracted_fs(object):
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