Revision 3436eeb0 pithos/backends/simple.py

b/pithos/backends/simple.py
79 79
        sql = '''create table if not exists hashmaps (
80 80
                    version_id integer, pos integer, block_id text, primary key (version_id, pos))'''
81 81
        self.con.execute(sql)
82
        sql = '''create table if not exists permissions (
83
                    name text, read text, write text, primary key (name))'''
84
        self.con.execute(sql)
82 85
        self.con.commit()
83 86
    
84 87
    def delete_account(self, user, account):
......
227 230
        path, version_id, mtime, size = self._get_objectinfo(account, container, name)
228 231
        self._put_metadata(path, meta, replace)
229 232
    
233
    def get_object_permissions(self, user, account, container, name):
234
        """Return a dictionary with the object permissions."""
235
        
236
        logger.debug("get_object_permissions: %s %s %s", account, container, name)
237
        path = self._get_objectinfo(account, container, name)[0]
238
        return self._get_permissions(path)
239
    
240
    def update_object_permissions(self, user, account, container, name, permissions):
241
        """Update the permissions associated with the object."""
242
        
243
        logger.debug("update_object_permissions: %s %s %s %s", account, container, name, permissions)
244
        path = self._get_objectinfo(account, container, name)[0]
245
        r, w = self._check_permissions(path, permissions)
246
        self._put_permissions(path, r, w)
247
    
230 248
    def get_object_hashmap(self, user, account, container, name, version=None):
231 249
        """Return the object's size and a list with partial hashes."""
232 250
        
......
237 255
        hashmap = [x[0] for x in c.fetchall()]
238 256
        return size, hashmap
239 257
    
240
    def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False):
258
    def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False, permissions={}):
241 259
        """Create/update an object with the specified size and partial hashes."""
242 260
        
243 261
        logger.debug("update_object_hashmap: %s %s %s %s %s", account, container, name, size, hashmap)
244 262
        path = self._get_containerinfo(account, container)[0]
245 263
        path = os.path.join(path, name)
264
        if permissions:
265
            r, w = self._check_permissions(path, permissions)
246 266
        src_version_id, dest_version_id = self._copy_version(path, path, not replace_meta, False)
247 267
        sql = 'update versions set size = ? where version_id = ?'
248 268
        self.con.execute(sql, (size, dest_version_id))
......
253 273
        for k, v in meta.iteritems():
254 274
            sql = 'insert or replace into metadata (version_id, key, value) values (?, ?, ?)'
255 275
            self.con.execute(sql, (dest_version_id, k, v))
276
        if permissions:
277
            sql = 'insert or replace into permissions (name, read, write) values (?, ?, ?)'
278
            self.con.execute(sql, (path, r, w))
256 279
        self.con.commit()
257 280
    
258
    def copy_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, src_version=None):
281
    def copy_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions={}, src_version=None):
259 282
        """Copy an object's data and metadata."""
260 283
        
261
        logger.debug("copy_object: %s %s %s %s %s %s %s %s", account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta, src_version)
284
        logger.debug("copy_object: %s %s %s %s %s %s %s %s %s", account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta, permissions, src_version)
262 285
        self._get_containerinfo(account, src_container)
263 286
        if src_version is None:
264 287
            src_path = self._get_objectinfo(account, src_container, src_name)[0]
......
266 289
            src_path = os.path.join(account, src_container, src_name)
267 290
        dest_path = self._get_containerinfo(account, dest_container)[0]
268 291
        dest_path = os.path.join(dest_path, dest_name)
292
        if permissions:
293
            r, w = self._check_permissions(dest_path, permissions)
269 294
        src_version_id, dest_version_id = self._copy_version(src_path, dest_path, not replace_meta, True, src_version)
270 295
        for k, v in dest_meta.iteritems():
271 296
            sql = 'insert or replace into metadata (version_id, key, value) values (?, ?, ?)'
272 297
            self.con.execute(sql, (dest_version_id, k, v))
298
        if permissions:
299
            sql = 'insert or replace into permissions (name, read, write) values (?, ?, ?)'
300
            self.con.execute(sql, (dest_path, r, w))
273 301
        self.con.commit()
274 302
    
275
    def move_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False):
303
    def move_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions={}):
276 304
        """Move an object's data and metadata."""
277 305
        
278
        logger.debug("move_object: %s %s %s %s %s %s %s", account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta)
279
        self.copy_object(user, account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta, None)
306
        logger.debug("move_object: %s %s %s %s %s %s %s %s", account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta, permissions)
307
        self.copy_object(user, account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta, permissions, None)
280 308
        self.delete_object(user, account, src_container, src_name)
281 309
    
282 310
    def delete_object(self, user, account, container, name):
......
285 313
        logger.debug("delete_object: %s %s %s", account, container, name)
286 314
        path, version_id, mtime, size = self._get_objectinfo(account, container, name)
287 315
        self._put_version(path, 0, 1)
316
        sql = 'delete from permissions where name = ?'
317
        self.con.execute(sql, (path,))
318
        self.con.commit()
288 319
    
289 320
    def list_versions(self, user, account, container, name):
290 321
        """Return a list of all (version, version_timestamp) tuples for an object."""
......
449 480
            self.con.execute(sql, (dest_version_id, k, v))
450 481
        self.con.commit()
451 482
    
483
    def _can_read(self, user, path):
484
        return True
485
    
486
    def _can_write(self, user, path):
487
        return True
488
    
489
    def _check_permissions(self, path, permissions):
490
        # Check for existing permissions.
491
        sql = '''select name from permissions
492
                    where name != ? and (name like ? or ? like name || ?)'''
493
        c = self.con.execute(sql, (path, path + '%', path, '%'))
494
        if c.fetchall() is not None:
495
            raise AttributeError('Permissions already set')
496
        
497
        # Format given permissions set.
498
        r = permissions.get('read', [])
499
        w = permissions.get('write', [])
500
        if True in [False or '*' in x or ',' in x for x in r]:
501
            raise ValueError('Bad characters in read permissions')
502
        if True in [False or '*' in x or ',' in x for x in w]:
503
            raise ValueError('Bad characters in write permissions')
504
        r = ','.join(r)
505
        w = ','.join(w)
506
        if 'public' in permissions:
507
            r = '*'
508
        if 'private' in permissions:
509
            r = ''
510
            w = ''
511
        return r, w
512
    
513
    def _get_permissions(self, path):
514
        sql = 'select read, write from permissions where name = ?'
515
        c = self.con.execute(sql, (path,))
516
        row = c.fetchone()
517
        if not row:
518
            return {}
519
        
520
        r, w = row
521
        if r == '' and w == '':
522
            return {'private': True}
523
        ret = {}
524
        if w != '':
525
            ret['write'] = w.split(',')
526
        if r != '':
527
            if r == '*':
528
                ret['public'] = True
529
            else:
530
                ret['read'] = r.split(',')        
531
        return ret
532
    
533
    def _put_permissions(self, path, r, w):
534
        sql = 'insert or replace into permissions (name, read, write) values (?, ?, ?)'
535
        self.con.execute(sql, (path, r, w))
536
        self.con.commit()
537
    
452 538
    def _list_objects(self, path, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], until=None):
453 539
        cont_prefix = path + '/'
454 540
        if keys and len(keys) > 0:
......
502 588
        self.con.execute(sql, (path,))
503 589
        sql = '''delete from versions where name = ?'''
504 590
        self.con.execute(sql, (path,))
591
        sql = '''delete from permissions where name like ?'''
592
        self.con.execute(sql, (path + '%',)) # Redundant.
505 593
        self.con.commit()

Also available in: Unified diff