Commit 839a1f68 by rfkelly0

fix a locking bug in MountFS.getsize

parent 654209fd
#!/usr/bin/env python #!/usr/bin/env python
from base import * from fs.base import *
from objecttree import ObjectTree from fs.objecttree import ObjectTree
from memoryfs import MemoryFS
class DirMount(object): class DirMount(object):
...@@ -53,204 +52,159 @@ class MountFS(FS): ...@@ -53,204 +52,159 @@ class MountFS(FS):
return self, head_path, tail_path return self, head_path, tail_path
@synchronize
def desc(self, path): def desc(self, path):
self._lock.acquire() fs, mount_path, delegate_path = self._delegate(path)
try: if fs is self:
fs, mount_path, delegate_path = self._delegate(path) if fs.isdir(path):
if fs is self: return "Mount dir"
if fs.isdir(path): else:
return "Mount dir" return "Mounted file"
else: return "Mounted dir, maps to path %s on %s" % (delegate_path, str(fs))
return "Mounted file"
return "Mounted dir, maps to path %s on %s" % (delegate_path, str(fs))
finally:
self._lock.release()
@synchronize
def isdir(self, path): def isdir(self, path):
self._lock.acquire() fs, mount_path, delegate_path = self._delegate(path)
try: if fs is None:
fs, mount_path, delegate_path = self._delegate(path) raise ResourceNotFoundError(path)
if fs is None:
raise ResourceNotFoundError(path)
if fs is self: if fs is self:
object = self.mount_tree.get(path, None) object = self.mount_tree.get(path, None)
return isinstance(object, dict) return isinstance(object, dict)
else: else:
return fs.isdir(delegate_path) return fs.isdir(delegate_path)
finally:
self._lock.release()
@synchronize
def isfile(self, path): def isfile(self, path):
fs, mount_path, delegate_path = self._delegate(path)
if fs is None:
return ResourceNotFoundError(path)
self._lock.acquire() if fs is self:
try: object = self.mount_tree.get(path, None)
fs, mount_path, delegate_path = self._delegate(path) return type(object) is MountFS.FileMount
if fs is None: else:
return ResourceNotFoundError(path) return fs.isfile(delegate_path)
if fs is self:
object = self.mount_tree.get(path, None)
return type(object) is MountFS.FileMount
else:
return fs.isfile(delegate_path)
finally:
self._lock.release()
@synchronize
def listdir(self, path="/", wildcard=None, full=False, absolute=False, dirs_only=False, files_only=False): def listdir(self, path="/", wildcard=None, full=False, absolute=False, dirs_only=False, files_only=False):
path = normpath(path)
fs, mount_path, delegate_path = self._delegate(path)
if fs is None:
raise ResourceNotFoundError(path)
if fs is self:
if files_only:
return []
paths = self.mount_tree[path].keys()
return self._listdir_helper(path,
paths,
wildcard,
full,
absolute,
dirs_only,
files_only)
else:
paths = fs.listdir(delegate_path,
wildcard=wildcard,
full=False,
absolute=False,
dirs_only=dirs_only,
files_only=files_only)
if full or absolute:
if full:
path = abspath(normpath(path))
else:
path = relpath(normpath(path))
paths = [pathjoin(path, p) for p in paths]
self._lock.acquire() return paths
try:
path = normpath(path)
fs, mount_path, delegate_path = self._delegate(path)
if fs is None:
raise ResourceNotFoundError(path)
if fs is self:
if files_only:
return []
paths = self.mount_tree[path].keys()
return self._listdir_helper(path,
paths,
wildcard,
full,
absolute,
dirs_only,
files_only)
else:
paths = fs.listdir(delegate_path,
wildcard=wildcard,
full=False,
absolute=False,
dirs_only=dirs_only,
files_only=files_only)
if full or absolute:
if full:
path = abspath(normpath(path))
else:
path = relpath(normpath(path))
paths = [pathjoin(path, p) for p in paths]
return paths
finally:
self._lock.release()
@synchronize
def makedir(self, path, recursive=False, allow_recreate=False): def makedir(self, path, recursive=False, allow_recreate=False):
path = normpath(path) path = normpath(path)
self._lock.acquire() fs, mount_path, delegate_path = self._delegate(path)
try: if fs is self:
fs, mount_path, delegate_path = self._delegate(path) raise UnsupportedError("make directory", msg="Can only makedir for mounted paths" )
if fs is self: return fs.makedir(delegate_path, recursive=recursive, allow_recreate=allow_recreate)
raise UnsupportedError("make directory", msg="Can only makedir for mounted paths" )
return fs.makedir(delegate_path, recursive=recursive, allow_recreate=allow_recreate)
finally:
self._lock.release()
@synchronize
def open(self, path, mode="r", **kwargs): def open(self, path, mode="r", **kwargs):
path = normpath(path)
object = self.mount_tree.get(path, None)
if type(object) is MountFS.FileMount:
callable = object.open_callable
return callable(path, mode, **kwargs)
self._lock.acquire() fs, mount_path, delegate_path = self._delegate(path)
try:
path = normpath(path)
object = self.mount_tree.get(path, None)
if type(object) is MountFS.FileMount:
callable = object.open_callable
return callable(path, mode, **kwargs)
fs, mount_path, delegate_path = self._delegate(path)
if fs is None: if fs is None:
raise ResourceNotFoundError(path) raise ResourceNotFoundError(path)
return fs.open(delegate_path, mode, **kwargs) return fs.open(delegate_path, mode, **kwargs)
finally:
self._lock.release()
@synchronize
def exists(self, path): def exists(self, path):
path = normpath(path)
self._lock.acquire() fs, mount_path, delegate_path = self._delegate(path)
try: if fs is None:
return False
path = normpath(path) if fs is self:
fs, mount_path, delegate_path = self._delegate(path) return path in self.mount_tree
return fs.exists(delegate_path)
if fs is None:
return False @synchronize
if fs is self:
return path in self.mount_tree
return fs.exists(delegate_path)
finally:
self._lock.release()
def remove(self, path): def remove(self, path):
self._lock.acquire() path = normpath(path)
try: fs, mount_path, delegate_path = self._delegate(path)
path = normpath(path) if fs is None:
fs, mount_path, delegate_path = self._delegate(path) raise ResourceNotFoundError(path)
if fs is None: if fs is self:
raise ResourceNotFoundError(path) raise UnsupportedError("remove file", msg="Can only remove paths within a mounted dir")
if fs is self: return fs.remove(delegate_path)
raise UnsupportedError("remove file", msg="Can only remove paths within a mounted dir")
return fs.remove(delegate_path) @synchronize
finally:
self._lock.release()
def removedir(self, path, recursive=False, force=False): def removedir(self, path, recursive=False, force=False):
path = normpath(path)
fs, mount_path, delegate_path = self._delegate(path)
self._lock.acquire() if fs is None or fs is self:
try: raise ResourceInvalidError(path, msg="Can not removedir for an un-mounted path")
path = normpath(path)
fs, mount_path, delegate_path = self._delegate(path)
if fs is None or fs is self:
raise ResourceInvalidError(path, msg="Can not removedir for an un-mounted path")
if not force and not fs.isdirempty(delegate_path):
raise DirectoryNotEmptyError("Directory is not empty: %(path)s")
return fs.removedir(delegate_path, recursive, force) if not force and not fs.isdirempty(delegate_path):
raise DirectoryNotEmptyError("Directory is not empty: %(path)s")
finally: return fs.removedir(delegate_path, recursive, force)
self._lock.release()
@synchronize
def rename(self, src, dst): def rename(self, src, dst):
if not issamedir(src, dst): if not issamedir(src, dst):
raise ValueError("Destination path must the same directory (use the move method for moving to a different directory)") raise ValueError("Destination path must the same directory (use the move method for moving to a different directory)")
fs1, mount_path1, delegate_path1 = self._delegate(src)
fs2, mount_path2, delegate_path2 = self._delegate(dst)
self._lock.acquire() if fs1 is not fs2:
try: raise OperationFailedError("rename resource", path=src)
fs1, mount_path1, delegate_path1 = self._delegate(src)
fs2, mount_path2, delegate_path2 = self._delegate(dst)
if fs1 is not fs2:
raise OperationFailedError("rename resource", path=src)
if fs1 is not self: if fs1 is not self:
return fs1.rename(delegate_path1, delegate_path2) return fs1.rename(delegate_path1, delegate_path2)
path_src = normpath(src) path_src = normpath(src)
path_dst = normpath(dst) path_dst = normpath(dst)
object = self.mount_tree.get(path_src, None) object = self.mount_tree.get(path_src, None)
object2 = self.mount_tree.get(path_dst, None) object2 = self.mount_tree.get(path_dst, None)
if object1 is None: if object1 is None:
raise ResourceNotFoundError(src) raise ResourceNotFoundError(src)
# TODO! # TODO!
raise UnsupportedError("rename resource", path=src)
raise UnsupportedError("rename resource", path=src)
finally:
self._lock.release()
@synchronize
def mountdir(self, path, fs): def mountdir(self, path, fs):
"""Mounts a directory on a given path. """Mounts a directory on a given path.
...@@ -258,60 +212,46 @@ class MountFS(FS): ...@@ -258,60 +212,46 @@ class MountFS(FS):
fs -- A filesystem object to mount fs -- A filesystem object to mount
""" """
self._lock.acquire() path = normpath(path)
try: self.mount_tree[path] = MountFS.DirMount(path, fs)
path = normpath(path)
self.mount_tree[path] = MountFS.DirMount(path, fs)
finally:
self._lock.release()
mount = mountdir mount = mountdir
@synchronize
def mountfile(self, path, open_callable=None, info_callable=None): def mountfile(self, path, open_callable=None, info_callable=None):
self._lock.acquire() path = normpath(path)
try: self.mount_tree[path] = MountFS.FileMount(path, callable, info_callable)
path = normpath(path)
self.mount_tree[path] = MountFS.FileMount(path, callable, info_callable)
finally:
self._lock.release()
@synchronize
def getinfo(self, path): def getinfo(self, path):
path = normpath(path)
self._lock.acquire() fs, mount_path, delegate_path = self._delegate(path)
try:
path = normpath(path)
fs, mount_path, delegate_path = self._delegate(path)
if fs is None: if fs is None:
raise ResourceNotFoundError(path) raise ResourceNotFoundError(path)
if fs is self: if fs is self:
if self.isfile(path): if self.isfile(path):
return self.mount_tree[path].info_callable(path) return self.mount_tree[path].info_callable(path)
return {} return {}
return fs.getinfo(delegate_path) return fs.getinfo(delegate_path)
finally:
self._lock.release()
@synchronize
def getsize(self, path): def getsize(self, path):
self._lock.acquire() path = normpath(path)
try: fs, mount_path, delegate_path = self._delegate(path)
path = normpath(path)
fs, mount_path, delegate_path = self._delegate(path)
if fs is None: if fs is None:
raise ResourceNotFoundError(path) raise ResourceNotFoundError(path)
if fs is self: if fs is self:
object = self.mount_tree.get(path, None) object = self.mount_tree.get(path, None)
if object is None or isinstance(object, dict): if object is None or isinstance(object, dict):
raise ResourceNotFoundError(path) raise ResourceNotFoundError(path)
size = self.mount_tree[path].info_callable(path).get("size", None) size = self.mount_tree[path].info_callable(path).get("size", None)
return size return size
return fs.getinfo(delegate_path).get("size", None) return fs.getinfo(delegate_path).get("size", None)
except:
self._lock.release()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment