/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transport/chroot.py

Merge from bzr.dev, resolving conflicts.

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
from urlparse import urlparse
20
21
 
 
22
from bzrlib import errors, urlutils
21
23
from bzrlib.transport import (
22
 
    pathfilter,
 
24
    get_transport,
 
25
    local,
23
26
    register_transport,
 
27
    Server,
 
28
    Transport,
 
29
    unregister_transport,
24
30
    )
25
 
 
26
 
 
27
 
class ChrootServer(pathfilter.PathFilteringServer):
 
31
from bzrlib.transport.decorator import TransportDecorator, DecoratorServer
 
32
from bzrlib.transport.memory import MemoryTransport
 
33
 
 
34
 
 
35
class ChrootServer(Server):
28
36
    """User space 'chroot' facility.
29
 
 
 
37
    
30
38
    The server's get_url returns the url for a chroot transport mapped to the
31
39
    backing transport. The url is of the form chroot-xxx:/// so parent
32
40
    directories of the backing transport are not visible. The chroot url will
33
41
    not allow '..' sequences to result in requests to the chroot affecting
34
42
    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
43
    """
40
44
 
41
45
    def __init__(self, backing_transport):
42
 
        pathfilter.PathFilteringServer.__init__(self, backing_transport, None)
 
46
        self.backing_transport = backing_transport
43
47
 
44
48
    def _factory(self, url):
 
49
        assert url.startswith(self.scheme)
45
50
        return ChrootTransport(self, url)
46
51
 
47
 
    def start_server(self):
 
52
    def get_url(self):
 
53
        return self.scheme
 
54
 
 
55
    def setUp(self):
48
56
        self.scheme = 'chroot-%d:///' % id(self)
49
57
        register_transport(self.scheme, self._factory)
50
58
 
51
 
 
52
 
class ChrootTransport(pathfilter.PathFilteringTransport):
 
59
    def tearDown(self):
 
60
        unregister_transport(self.scheme, self._factory)
 
61
 
 
62
 
 
63
class ChrootTransport(Transport):
53
64
    """A ChrootTransport.
54
65
 
55
66
    Please see ChrootServer for details.
56
67
    """
57
68
 
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)
 
69
    def __init__(self, server, base):
 
70
        self.server = server
 
71
        if not base.endswith('/'):
 
72
            base += '/'
 
73
        Transport.__init__(self, base)
 
74
        self.base_path = self.base[len(self.server.scheme)-1:]
 
75
        self.scheme = self.server.scheme
 
76
 
 
77
    def _call(self, methodname, relpath, *args):
 
78
        method = getattr(self.server.backing_transport, methodname)
 
79
        return method(self._safe_relpath(relpath), *args)
 
80
 
 
81
    def _safe_relpath(self, relpath):
 
82
        safe_relpath = self._combine_paths(self.base_path, relpath)
 
83
        assert safe_relpath.startswith('/')
 
84
        return safe_relpath[1:]
 
85
 
 
86
    # Transport methods
 
87
    def abspath(self, relpath):
 
88
        return self.scheme + self._safe_relpath(relpath)
 
89
 
 
90
    def append_file(self, relpath, f, mode=None):
 
91
        return self._call('append_file', relpath, f, mode)
 
92
 
 
93
    def clone(self, relpath):
 
94
        return ChrootTransport(self.server, self.abspath(relpath))
 
95
 
 
96
    def delete(self, relpath):
 
97
        return self._call('delete', relpath)
 
98
 
 
99
    def delete_tree(self, relpath):
 
100
        return self._call('delete_tree', relpath)
 
101
 
 
102
    def get(self, relpath):
 
103
        return self._call('get', relpath)
 
104
 
 
105
    def has(self, relpath):
 
106
        return self._call('has', relpath)
 
107
 
 
108
    def iter_files_recursive(self):
 
109
        backing_transport = self.server.backing_transport.clone(
 
110
            self._safe_relpath('.'))
 
111
        return backing_transport.iter_files_recursive()
 
112
 
 
113
    def listable(self):
 
114
        return self.server.backing_transport.listable()
 
115
 
 
116
    def list_dir(self, relpath):
 
117
        return self._call('list_dir', relpath)
 
118
 
 
119
    def lock_read(self, relpath):
 
120
        return self._call('lock_read', relpath)
 
121
 
 
122
    def lock_write(self, relpath):
 
123
        return self._call('lock_write', relpath)
 
124
 
 
125
    def mkdir(self, relpath, mode=None):
 
126
        return self._call('mkdir', relpath, mode)
 
127
 
 
128
    def put_file(self, relpath, f, mode=None):
 
129
        return self._call('put_file', relpath, f, mode)
 
130
 
 
131
    def rename(self, rel_from, rel_to):
 
132
        return self._call('rename', rel_from, self._safe_relpath(rel_to))
 
133
 
 
134
    def rmdir(self, relpath):
 
135
        return self._call('rmdir', relpath)
 
136
 
 
137
    def stat(self, relpath):
 
138
        return self._call('stat', relpath)
 
139
 
 
140
 
 
141
class TestingChrootServer(ChrootServer):
 
142
 
 
143
    def __init__(self):
 
144
        """TestingChrootServer is not usable until setUp is called."""
 
145
 
 
146
    def setUp(self, backing_server=None):
 
147
        """Setup the Chroot on backing_server."""
 
148
        if backing_server is not None:
 
149
            self.backing_transport = get_transport(backing_server.get_url())
 
150
        else:
 
151
            self.backing_transport = get_transport('.')
 
152
        ChrootServer.setUp(self)
62
153
 
63
154
 
64
155
def get_test_permutations():
65
156
    """Return the permutations to be used in testing."""
66
 
    from bzrlib.tests import test_server
67
 
    return [(ChrootTransport, test_server.TestingChrootServer)]
 
157
    return [(ChrootTransport, TestingChrootServer),
 
158
            ]