def delete(self, token): """Delete lock. Returns True on success. False, if token does not exist, or is expired. """ self._lock.acquire_write() try: lock = self._dict.get(token) _logger.debug("delete {}".format(lock_string(lock))) if lock is None: return False # Remove url to lock mapping key = "URL2TOKEN:{}".format(lock.get("root")) if key in self._dict: # _logger.debug(" delete token {} from url {}".format(token, lock.get("root"))) tokList = self._dict[key] if len(tokList) > 1: # Note: shelve dictionary returns copies, so we must # reassign values: tokList.remove(token) self._dict[key] = tokList else: del self._dict[key] # Remove the lock del self._dict[token] self._flush() finally: self._lock.release() return True
def get(self, token): """Return a lock dictionary for a token. If the lock does not exist or is expired, None is returned. token: lock token Returns: Lock dictionary or <None> Side effect: if lock is expired, it will be purged and None is returned. """ self._lock.acquire_read() try: lock = self._dict.get(token) if lock is None: # Lock not found: purge dangling URL2TOKEN entries _logger.debug("Lock purged dangling: {}".format(token)) self.delete(token) return None expire = float(lock["expire"]) if expire >= 0 and expire < time.time(): _logger.debug( "Lock timed-out({}): {}".format(expire, lock_string(lock)) ) self.delete(token) return None return lock finally: self._lock.release()
def delete(self, token): """Delete lock. See wsgidav.lock_storage.LockStorageDict.delete() """ lock = self.get(token) logging.debug("delete %s" % lock_string(lock)) return self._deleteLock(lock)
def create(self, path, lock): """Create a direct lock for a resource path. path: Normalized path (utf8 encoded string, no trailing '/') lock: lock dictionary, without a token entry Returns: New unique lock token.: <lock **Note:** the lock dictionary may be modified on return: - lock['root'] is ignored and set to the normalized <path> - lock['timeout'] may be normalized and shorter than requested - lock['token'] is added """ # We expect only a lock definition, not an existing lock assert lock.get("token") is None assert lock.get("expire") is None, "Use timeout instead of expire" assert path and "/" in path # Normalize root: /foo/bar org_path = path path = normalize_lock_root(path) lock["root"] = path # Normalize timeout from ttl to expire-date timeout = float(lock.get("timeout")) if timeout is None: timeout = LockStorageRedis.LOCK_TIME_OUT_DEFAULT elif timeout < 0 or timeout > LockStorageRedis.LOCK_TIME_OUT_MAX: timeout = LockStorageRedis.LOCK_TIME_OUT_MAX lock["timeout"] = timeout lock["expire"] = time.time() + timeout validate_lock(lock) token = generate_lock_token() lock["token"] = token # Store lock self._redis.set( self._redis_lock_prefix.format(token), pickle.dumps(lock), ex=int(timeout) ) # Store locked path reference key = self._redis_url2token_prefix.format(path) if not self._redis.exists(key): self._redis.lpush(key, token) else: self._redis.lpush(key, token) self._flush() _logger.debug( "LockStorageRedis.set({!r}): {}".format(org_path, lock_string(lock)) ) return lock
def delete(self, token): """Delete lock. Returns True on success. False, if token does not exist, or is expired. """ lock = self._redis.get(self._redis_lock_prefix.format(token)) if lock is None: return False lock = pickle.loads(lock) _logger.debug("delete {}".format(lock_string(lock))) # Remove url to lock mapping key = self._redis_url2token_prefix.format(lock.get("root")) self._redis.lrem(key, 1, token) self._redis.delete(self._redis_lock_prefix.format(token)) self._flush() return True
def get(self, token): """Return a lock dictionary for a token. See wsgidav.lock_storage.LockStorageDict.get() """ lock = cached_lock.get(token) if lock is None: # Lock not found: purge dangling root-path entries _logger.debug("Lock purged dangling: %s" % token) self._deleteLock(lock) return None expire = float(lock["expire"]) if expire >= 0 and expire < time.time(): _logger.debug("Lock timed-out(%s): %s" % (expire, lock_string(lock))) self._deleteLock(lock) return None return lock
def get(self, token): """Return a lock dictionary for a token. If the lock does not exist or is expired, None is returned. token: lock token Returns: Lock dictionary or <None> Side effect: if lock is expired, it will be purged and None is returned. """ lock = self._redis.get(self._redis_lock_prefix.format(token)) if lock is None: # Lock not found: purge dangling URL2TOKEN entries _logger.debug("Lock purged dangling: {}".format(token)) self.delete(token) return None lock = pickle.loads(lock) expire = float(lock["expire"]) if 0 <= expire < time.time(): _logger.debug("Lock timed-out({}): {}".format(expire, lock_string(lock))) self.delete(token) return None return lock
def create(self, path, lock): """Create a direct lock for a resource path. path: Normalized path (utf8 encoded string, no trailing '/') lock: lock dictionary, without a token entry Returns: New unique lock token.: <lock **Note:** the lock dictionary may be modified on return: - lock['root'] is ignored and set to the normalized <path> - lock['timeout'] may be normalized and shorter than requested - lock['token'] is added """ self._lock.acquire_write() try: # We expect only a lock definition, not an existing lock assert lock.get("token") is None assert lock.get("expire") is None, "Use timeout instead of expire" assert path and "/" in path # Normalize root: /foo/bar org_path = path path = normalize_lock_root(path) lock["root"] = path # Normalize timeout from ttl to expire-date timeout = float(lock.get("timeout")) if timeout is None: timeout = LockStorageDict.LOCK_TIME_OUT_DEFAULT elif timeout < 0 or timeout > LockStorageDict.LOCK_TIME_OUT_MAX: timeout = LockStorageDict.LOCK_TIME_OUT_MAX lock["timeout"] = timeout lock["expire"] = time.time() + timeout validate_lock(lock) token = generate_lock_token() lock["token"] = token # Store lock self._dict[token] = lock # Store locked path reference key = "URL2TOKEN:{}".format(path) if key not in self._dict: self._dict[key] = [token] else: # Note: Shelve dictionary returns copies, so we must reassign # values: tokList = self._dict[key] tokList.append(token) self._dict[key] = tokList self._flush() _logger.debug( "LockStorageDict.set({!r}): {}".format(org_path, lock_string(lock)) ) return lock finally: self._lock.release()
def test(): logging.info("test.test()") logging.getLogger().setLevel(logging.DEBUG) # Test data_fs.py data_fs.initfs() assert data_fs.isdir("/") rootpath = "/run_test" if data_fs.exists(rootpath): logging.info("removing " + rootpath) data_fs.rmtree(rootpath) assert not data_fs.exists(rootpath) data_fs.mkdir(rootpath) assert data_fs.isdir(rootpath) data = b"file content" data_fs.mkdir(rootpath + "/dir1") assert data_fs.isdir(rootpath + "/dir1") f1 = data_fs.btopen(rootpath + "/dir1/file1.txt", "w") f1.write(data) f1.close() assert data_fs.isfile(rootpath + "/dir1/file1.txt") # data_fs.unlink(rootpath+"/dir1/file1.txt") # assert not data_fs.isfile(rootpath+"/dir1/file1.txt") print("*** data_fs tests passed ***") # Test providers provider = BTFSResourceProvider() lockman = LockManager(LockStorageMemcache()) provider.set_lock_manager(lockman) environ = {"wsgidav.provider": provider} environ["wsgidav.auth.user_name"] = "test" environ["wsgidav.auth.roles"] = ["editor"] resRoot = provider.get_resource_inst(rootpath + "/", environ) resRoot.create_collection("folder1") assert data_fs.isdir(rootpath + "/folder1") assert not data_fs.isfile(rootpath + "/folder1") resChild = provider.get_resource_inst(rootpath + "/folder1", environ) assert resChild resFile = resChild.create_empty_resource("file_empty.txt") assert resFile assert not data_fs.isdir(rootpath + "/folder1/file_empty.txt") assert data_fs.isfile(rootpath + "/folder1/file_empty.txt") # write data = b"x" * 1024 res = resChild.create_empty_resource("file2.txt") f = res.begin_write() f.write(data) f.close() # copy res = provider.get_resource_inst(rootpath + "/folder1/file2.txt", environ) res.copy_move_single(rootpath + "/folder1/file2_copy.txt", False) res = provider.get_resource_inst(rootpath + "/folder1/file2_copy.txt", environ) f = res.get_content() assert data == f.read() f.close() print("*** provider tests passed ***") lock = provider.lock_manager.acquire( rootpath + "/folder1", "write", "exclusive", "infinity", b"test_owner", timeout=100, principal="martin", token_list=[], ) assert lock["root"] == rootpath + "/folder1" lock = provider.lock_manager.get_lock(lock["token"]) print(lock_string(lock)) assert lock["root"] == rootpath + "/folder1" locklist = provider.lock_manager.get_indirect_url_lock_list( rootpath + "/folder1/file2.txt") print(locklist) assert len(locklist) == 1 print("*** lock tests passed ***")