Commit b39ae0b4 by willmcgugan@gmail.com

InvalidCharsInPathError

parent bc30657b
...@@ -11,6 +11,7 @@ catch-all exception. ...@@ -11,6 +11,7 @@ catch-all exception.
__all__ = ['FSError', __all__ = ['FSError',
'CreateFailedError', 'CreateFailedError',
'PathError', 'PathError',
'InvalidCharsInPathError',
'OperationFailedError', 'OperationFailedError',
'UnsupportedError', 'UnsupportedError',
'RemoteConnectionError', 'RemoteConnectionError',
...@@ -32,7 +33,7 @@ __all__ = ['FSError', ...@@ -32,7 +33,7 @@ __all__ = ['FSError',
'NoMMapError', 'NoMMapError',
'BackReferenceError', 'BackReferenceError',
'convert_fs_errors', 'convert_fs_errors',
'convert_os_errors' 'convert_os_errors',
] ]
import sys import sys
...@@ -42,10 +43,6 @@ from fs.path import * ...@@ -42,10 +43,6 @@ from fs.path import *
from fs.local_functools import wraps from fs.local_functools import wraps
class InvalidPathError(Exception):
pass
class FSError(Exception): class FSError(Exception):
"""Base exception class for the FS module.""" """Base exception class for the FS module."""
default_message = "Unspecified error" default_message = "Unspecified error"
...@@ -71,7 +68,6 @@ class FSError(Exception): ...@@ -71,7 +68,6 @@ class FSError(Exception):
return (self.__class__,(),self.__dict__.copy(),) return (self.__class__,(),self.__dict__.copy(),)
class CreateFailedError(FSError): class CreateFailedError(FSError):
"""An exception thrown when a FS could not be created""" """An exception thrown when a FS could not be created"""
default_message = "Unable to create filesystem" default_message = "Unable to create filesystem"
...@@ -87,6 +83,10 @@ class PathError(FSError): ...@@ -87,6 +83,10 @@ class PathError(FSError):
super(PathError,self).__init__(**kwds) super(PathError,self).__init__(**kwds)
class InvalidCharsInPathError(PathError):
default_message = "Path contains invalid characters: %(path)s"
class OperationFailedError(FSError): class OperationFailedError(FSError):
"""Base exception class for errors associated with a specific operation.""" """Base exception class for errors associated with a specific operation."""
default_message = "Unable to %(opname)s: unspecified error [%(errno)s - %(details)s]" default_message = "Unable to %(opname)s: unspecified error [%(errno)s - %(details)s]"
......
...@@ -22,8 +22,8 @@ import datetime ...@@ -22,8 +22,8 @@ import datetime
import platform import platform
from fs.base import * from fs.base import *
from fs.errors import *
from fs.path import * from fs.path import *
from fs.errors import *
from fs import _thread_synchronize_default from fs import _thread_synchronize_default
from fs.osfs.xattrs import OSFSXAttrMixin from fs.osfs.xattrs import OSFSXAttrMixin
...@@ -87,6 +87,12 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS): ...@@ -87,6 +87,12 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
'atomic.setcontents' : False, 'atomic.setcontents' : False,
} }
if sys.platform == 'win32':
_invalid_path_chars = '\\:*?"<>|'
else:
_invalid_path_chars = '\0'
_re_invalid_path_chars = re.compile('|'.join(re.escape(c) for c in _invalid_path_chars), re.UNICODE)
def __init__(self, root_path, thread_synchronize=_thread_synchronize_default, encoding=None, create=False, dir_mode=0700, use_long_paths=True): def __init__(self, root_path, thread_synchronize=_thread_synchronize_default, encoding=None, create=False, dir_mode=0700, use_long_paths=True):
""" """
Creates an FS object that represents the OS Filesystem under a given root path Creates an FS object that represents the OS Filesystem under a given root path
...@@ -147,12 +153,18 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS): ...@@ -147,12 +153,18 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
return p return p
return p.decode(self.encoding, 'replace') return p.decode(self.encoding, 'replace')
def _validate_path(self, path):
"""Raise an error if there are any invalid characters in the path"""
if self._re_invalid_path_chars.search(path):
raise InvalidCharsInPathError(path)
def getsyspath(self, path, allow_none=False): def getsyspath(self, path, allow_none=False):
path = relpath(normpath(path)).replace("/", os.sep) path = relpath(normpath(path)).replace("/", os.sep)
path = os.path.join(self.root_path, path) path = os.path.join(self.root_path, path)
if not path.startswith(self.root_path): if not path.startswith(self.root_path):
raise PathError(path, msg="OSFS given path outside root: %(path)s") raise PathError(path, msg="OSFS given path outside root: %(path)s")
path = self._decode_path(path) path = self._decode_path(path)
self._validate_path(path)
return path return path
def unsyspath(self, path): def unsyspath(self, path):
......
from __future__ import unicode_literals
""" """
fs.path fs.path
======= =======
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
""" """
from fs.tests import FSTestCases, ThreadingTestCases from fs.tests import FSTestCases, ThreadingTestCases
from fs.path import *
from fs import errors
import unittest import unittest
...@@ -13,8 +15,6 @@ import sys ...@@ -13,8 +15,6 @@ import sys
import shutil import shutil
import tempfile import tempfile
from fs.path import *
from fs import osfs from fs import osfs
class TestOSFS(unittest.TestCase,FSTestCases,ThreadingTestCases): class TestOSFS(unittest.TestCase,FSTestCases,ThreadingTestCases):
...@@ -30,6 +30,9 @@ class TestOSFS(unittest.TestCase,FSTestCases,ThreadingTestCases): ...@@ -30,6 +30,9 @@ class TestOSFS(unittest.TestCase,FSTestCases,ThreadingTestCases):
def check(self, p): def check(self, p):
return os.path.exists(os.path.join(self.temp_dir, relpath(p))) return os.path.exists(os.path.join(self.temp_dir, relpath(p)))
def test_invalid_chars(self):
self.assertRaises(errors.InvalidCharsInPathError, self.fs.open, 'invalid\0file', 'wb')
class TestSubFS(unittest.TestCase,FSTestCases,ThreadingTestCases): class TestSubFS(unittest.TestCase,FSTestCases,ThreadingTestCases):
......
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