1"""
2fs.wrapfs.readonlyfs
3====================
4
5An FS wrapper class for blocking operations that would modify the FS.
6
7"""
8
9from fs.base import NoDefaultMeta
10from fs.wrapfs import WrapFS
11from fs.errors import UnsupportedError, NoSysPathError
12
13
14class ReadOnlyFS(WrapFS):
15    """ Makes a FS object read only. Any operation that could potentially modify
16    the underlying file system will throw an UnsupportedError
17
18    Note that this isn't a secure sandbox, untrusted code could work around the
19    read-only restrictions by getting the base class. Its main purpose is to
20    provide a degree of safety if you want to protect an FS object from
21    accidental modification.
22
23    """
24
25    def getmeta(self, meta_name, default=NoDefaultMeta):
26        if meta_name == 'read_only':
27            return True
28        return self.wrapped_fs.getmeta(meta_name, default)
29
30    def hasmeta(self, meta_name):
31        if meta_name == 'read_only':
32            return True
33        return self.wrapped_fs.hasmeta(meta_name)
34
35    def getsyspath(self, path, allow_none=False):
36        """ Doesn't technically modify the filesystem but could be used to work
37        around read-only restrictions. """
38        if allow_none:
39            return None
40        raise NoSysPathError(path)
41
42    def open(self, path, mode='r', buffering=-1, encoding=None, errors=None, newline=None, line_buffering=False, **kwargs):
43        """ Only permit read access """
44        if 'w' in mode or 'a' in mode or '+' in mode:
45            raise UnsupportedError('write')
46        return super(ReadOnlyFS, self).open(path,
47                                            mode=mode,
48                                            buffering=buffering,
49                                            encoding=encoding,
50                                            errors=errors,
51                                            newline=newline,
52                                            line_buffering=line_buffering,
53                                            **kwargs)
54
55    def _no_can_do(self, *args, **kwargs):
56        """ Replacement method for methods that can modify the file system """
57        raise UnsupportedError('write')
58
59    move = _no_can_do
60    movedir = _no_can_do
61    copy = _no_can_do
62    copydir = _no_can_do
63    makedir = _no_can_do
64    rename = _no_can_do
65    setxattr = _no_can_do
66    delxattr = _no_can_do
67    remove = _no_can_do
68    removedir = _no_can_do
69    settimes = _no_can_do
70    setcontents = _no_can_do
71    createfile = _no_can_do
72