~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/chroot.py

  • Committer: John Arbash Meinel
  • Date: 2007-03-14 20:15:52 UTC
  • mto: (2353.4.2 locking)
  • mto: This revision was merged to the branch mainline in revision 2360.
  • Revision ID: john@arbash-meinel.com-20070314201552-bjtfua57456dviep
Update the lock code and test code so that if more than one
lock implementation is available, they will both be tested.

It is quite a bit of overhead, for a case where we are likely to only have 1
real lock implementation per platform, but hey, for now we have 2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""Implementation of Transport that prevents access to locations above a set
18
18
root.
19
19
"""
20
20
 
21
 
from bzrlib.transport import (
22
 
    pathfilter,
23
 
    register_transport,
24
 
    )
25
 
 
26
 
 
27
 
class ChrootServer(pathfilter.PathFilteringServer):
28
 
    """User space 'chroot' facility.
29
 
 
30
 
    The server's get_url returns the url for a chroot transport mapped to the
31
 
    backing transport. The url is of the form chroot-xxx:/// so parent
32
 
    directories of the backing transport are not visible. The chroot url will
33
 
    not allow '..' sequences to result in requests to the chroot affecting
34
 
    directories outside the backing transport.
35
 
 
36
 
    PathFilteringServer does all the path sanitation needed to enforce a
37
 
    chroot, so this is a simple subclass of PathFilteringServer that ignores
38
 
    filter_func.
39
 
    """
40
 
 
41
 
    def __init__(self, backing_transport):
42
 
        pathfilter.PathFilteringServer.__init__(self, backing_transport, None)
43
 
 
44
 
    def _factory(self, url):
45
 
        return ChrootTransport(self, url)
46
 
 
47
 
    def start_server(self):
48
 
        self.scheme = 'chroot-%d:///' % id(self)
49
 
        register_transport(self.scheme, self._factory)
50
 
 
51
 
 
52
 
class ChrootTransport(pathfilter.PathFilteringTransport):
53
 
    """A ChrootTransport.
54
 
 
55
 
    Please see ChrootServer for details.
56
 
    """
57
 
 
58
 
    def _filter(self, relpath):
59
 
        # A simplified version of PathFilteringTransport's _filter that omits
60
 
        # the call to self.server.filter_func.
61
 
        return self._relpath_from_server_root(relpath)
 
21
from bzrlib import errors, urlutils
 
22
from bzrlib.transport.decorator import TransportDecorator, DecoratorServer
 
23
 
 
24
 
 
25
class ChrootTransportDecorator(TransportDecorator):
 
26
    """A decorator that can convert any transport to be chrooted.
 
27
 
 
28
    This is requested via the 'chrooted+' prefix to get_transport().
 
29
    """
 
30
 
 
31
    def __init__(self, url, _decorated=None, chroot=None):
 
32
        super(ChrootTransportDecorator, self).__init__(url,
 
33
                _decorated=_decorated)
 
34
        if chroot is None:
 
35
            self.chroot_url = self._decorated.base
 
36
        else:
 
37
            self.chroot_url = chroot
 
38
 
 
39
    @classmethod
 
40
    def _get_url_prefix(self):
 
41
        """Chroot transport decorators are invoked via 'chroot+'"""
 
42
        return 'chroot+'
 
43
 
 
44
    def _ensure_relpath_is_child(self, relpath):
 
45
        abspath = self.abspath(relpath)
 
46
        chroot_base = self._get_url_prefix() + self.chroot_url
 
47
        real_relpath = urlutils.relative_url(chroot_base, abspath)
 
48
        if real_relpath == '..' or real_relpath.startswith('../'):
 
49
            raise errors.PathNotChild(relpath, self.chroot_url)
 
50
 
 
51
    # decorated methods
 
52
    def append_file(self, relpath, f, mode=None):
 
53
        self._ensure_relpath_is_child(relpath)
 
54
        return TransportDecorator.append_file(self, relpath, f, mode=mode)
 
55
 
 
56
    def append_bytes(self, relpath, bytes, mode=None):
 
57
        self._ensure_relpath_is_child(relpath)
 
58
        return TransportDecorator.append_bytes(self, relpath, bytes, mode=mode)
 
59
 
 
60
    def clone(self, offset=None):
 
61
        self._ensure_relpath_is_child(offset)
 
62
        return TransportDecorator.clone(self, offset)
 
63
 
 
64
    def delete(self, relpath):
 
65
        self._ensure_relpath_is_child(relpath)
 
66
        return TransportDecorator.delete(self, relpath)
 
67
 
 
68
    def delete_tree(self, relpath):
 
69
        self._ensure_relpath_is_child(relpath)
 
70
        return TransportDecorator.delete_tree(self, relpath)
 
71
 
 
72
    def get(self, relpath):
 
73
        self._ensure_relpath_is_child(relpath)
 
74
        return TransportDecorator.get(self, relpath)
 
75
 
 
76
    def get_bytes(self, relpath):
 
77
        self._ensure_relpath_is_child(relpath)
 
78
        return TransportDecorator.get_bytes(self, relpath)
 
79
 
 
80
    def has(self, relpath):
 
81
        self._ensure_relpath_is_child(relpath)
 
82
        return TransportDecorator.has(self, relpath)
 
83
 
 
84
    def list_dir(self, relpath):
 
85
        self._ensure_relpath_is_child(relpath)
 
86
        return TransportDecorator.list_dir(self, relpath)
 
87
 
 
88
    def lock_read(self, relpath):
 
89
        self._ensure_relpath_is_child(relpath)
 
90
        return TransportDecorator.lock_read(self, relpath)
 
91
 
 
92
    def lock_write(self, relpath):
 
93
        self._ensure_relpath_is_child(relpath)
 
94
        return TransportDecorator.lock_write(self, relpath)
 
95
 
 
96
    def mkdir(self, relpath, mode=None):
 
97
        self._ensure_relpath_is_child(relpath)
 
98
        return TransportDecorator.mkdir(self, relpath, mode=mode)
 
99
 
 
100
    def put_bytes(self, relpath, bytes, mode=None):
 
101
        self._ensure_relpath_is_child(relpath)
 
102
        return TransportDecorator.put_bytes(self, relpath, bytes, mode=mode)
 
103
 
 
104
    def put_file(self, relpath, f, mode=None):
 
105
        self._ensure_relpath_is_child(relpath)
 
106
        return TransportDecorator.put_file(self, relpath, f, mode=mode)
 
107
 
 
108
    def rename(self, rel_from, rel_to):
 
109
        self._ensure_relpath_is_child(rel_from)
 
110
        self._ensure_relpath_is_child(rel_to)
 
111
        return TransportDecorator.rename(self, rel_from, rel_to)
 
112
 
 
113
    def rmdir(self, relpath):
 
114
        self._ensure_relpath_is_child(relpath)
 
115
        return TransportDecorator.rmdir(self, relpath)
 
116
 
 
117
    def stat(self, relpath):
 
118
        self._ensure_relpath_is_child(relpath)
 
119
        return TransportDecorator.stat(self, relpath)
 
120
 
 
121
 
 
122
class ChrootServer(DecoratorServer):
 
123
    """Server for the ReadonlyTransportDecorator for testing with."""
 
124
 
 
125
    def get_decorator_class(self):
 
126
        return ChrootTransportDecorator
62
127
 
63
128
 
64
129
def get_test_permutations():
65
130
    """Return the permutations to be used in testing."""
66
 
    from bzrlib.tests import test_server
67
 
    return [(ChrootTransport, test_server.TestingChrootServer)]
 
131
    return [(ChrootTransportDecorator, ChrootServer),
 
132
            ]