Commit 07499b3e by rfkelly0

Fix various DAVFS issues from issue #40

  * don't close the socket when handing off to RemoteFileBuffer
  * remove redundant check for "w" mode in the 404 case
  * properly close the socket in the isdir() case
  * add readline() method to RemoteFileBuffer
parent 803816d3
......@@ -271,16 +271,16 @@ class DAVFS(FS):
raise_generic_error(resp,"setcontents",path)
def open(self,path,mode="r"):
# Truncate the file if requested
mode = mode.replace("b","").replace("t","")
# Truncate the file if requested
contents = ""
if "w" in mode:
self.setcontents(path,contents)
else:
contents = self._request(path,"GET")
if contents.status == 404:
# Create the file if it's missing
if "w" not in mode and "a" not in mode:
# Create the file if it's missing in append mode.
if "a" not in mode:
contents.close()
raise ResourceNotFoundError(path)
contents = ""
......@@ -292,7 +292,9 @@ class DAVFS(FS):
contents.close()
raise_generic_error(contents,"open",path)
elif self.isdir(path):
contents.close()
raise ResourceInvalidError(path)
# For streaming reads, return the socket contents directly.
if mode == "r-":
contents.size = contents.getheader("Content-Length",None)
if contents.size is not None:
......@@ -301,11 +303,9 @@ class DAVFS(FS):
except ValueError:
contents.size = None
return contents
try:
return RemoteFileBuffer(self,path,mode,contents)
finally:
if hasattr(contents,"close"):
contents.close()
# For everything else, use a RemoteFileBuffer.
# This will take care of closing the socket when it's done.
return RemoteFileBuffer(self,path,mode,contents)
def exists(self,path):
response = self._request(path,"PROPFIND","",{"Depth":"0"})
......
......@@ -240,6 +240,8 @@ def convert_os_errors(func):
raise StorageSpaceError(opname,path=path,details=e),None,tb
if e.errno == errno.EPERM:
raise PermissionDeniedError(opname,path=path,details=e),None,tb
if e.errno == errno.ENONET:
raise RemoteConnectionError(opname,path=path,details=e),None,tb
if e.errno == errno.EACCES:
if sys.platform == "win32":
if e.args[0] and e.args[0] == 32:
......
......@@ -170,7 +170,17 @@ def handle_fs_errors(func):
def timeout_protect(func):
"""Method decorator to enable timeout protection during call."""
"""Method decorator to enable timeout protection during call.
During long-running operations, Dokan requires that the DokanResetTimeout
function be called periodically to indicate the progress is still being
made. Unfortunately we don't have an facility for the underlying FS
to make these calls for us, so we have to hack around it.
The idea is to use a single background thread to monitor all active Dokan
method calls, checking that they haven't deadlocked and resetting the
appropriate timeout.
"""
@wraps(func)
def wrapper(self,*args):
info = args[-1]
......
......@@ -158,6 +158,11 @@ class RemoteFileBuffer(object):
# TODO: implement this with on-demand loading.
self._fillbuffer()
return self.file.__iter__()
def readline(self):
# TODO: implement this with on-demand loading.
self._fillbuffer()
return self.file.readline()
def _read(self, length=None):
"""Read data from the remote file into the local buffer."""
......
......@@ -210,6 +210,7 @@ class S3FS(FS):
if not self.isdir(dirname(path)):
raise ParentDirectoryMissingError(path)
k = self._sync_set_contents(s3path,"")
# TODO: support streaming reads
return RemoteFileBuffer(self,path,mode,k)
def exists(self,path):
......
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