Commit 03936e1d by btimby

Use explicit exception to detect invalid path (BackReferenceError), see comments on r773

parent 34c78ce2
......@@ -188,6 +188,11 @@ class NoMMapError(ResourceError):
default_message = "Can't get mmap for %(path)s"
class BackReferenceError(FSError, ValueError):
"""Exception raised when too many backrefs exist in a path (ex: '/..', '/docs/../..')."""
default_message = "Too many backrefs in '%(path)s'"
def convert_fs_errors(func):
"""Function wrapper to convert FSError instances into OSError."""
@wraps(func)
......
......@@ -185,12 +185,10 @@ class SFTPServerInterface(paramiko.SFTPServerInterface):
def canonicalize(self, path):
try:
return abspath(normpath(path)).encode(self.encoding)
except ValueError, e:
except BackReferenceError:
# If the client tries to use backrefs to escape root, gently
# nudge them back to /.
if 'too many backrefs' in e.args[0]:
return '/'
raise
return '/'
@report_sftp_errors
def chattr(self, path, attr):
......
......@@ -33,31 +33,34 @@ def normpath(path):
>>> normpath("foo/../../bar")
Traceback (most recent call last)
...
ValueError: too many backrefs in path 'foo/../../bar'
BackReferenceError: Too many backrefs in 'foo/../../bar'
"""
if path in ('', '/'):
return path
path = path.replace('\\', '/')
# An early out if there is no need to normalize this path
if not _requires_normalization(path):
return path.rstrip('/')
components = []
append = components.append
special = ('..', '.', '').__contains__
try:
for component in path.split('/'):
if special(component):
if component == '..':
if component == '..':
components.pop()
else:
append(component)
except IndexError:
raise ValueError("too many backrefs in path '%s'" % path)
# Imported here because errors imports this module (path),
# causing a circular import.
from fs.errors import BackReferenceError
BackReferenceError(details={ 'path': path })
if path[0] == '/':
return '/%s' % '/'.join(components)
return '/'.join(components)
......@@ -77,7 +80,8 @@ def iteratepath(path, numsplits=None):
return path.split('/')
else:
return path.split('/', numsplits)
def recursepath(path, reverse=False):
"""Returns intermediate paths from the root to the given 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