/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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""Implementation of Transport that prevents access to locations above a set
 
18
root.
 
19
"""
 
20
from urlparse import urlparse
 
21
 
 
22
from bzrlib import errors, urlutils
 
23
from bzrlib.osutils import pathjoin
 
24
from bzrlib.transport.decorator import TransportDecorator, DecoratorServer
 
25
 
 
26
 
 
27
class ChrootTransportDecorator(TransportDecorator):
 
28
    """A decorator that can convert any transport to be chrooted.
 
29
 
 
30
    This is requested via the 'chroot+' prefix to get_transport().
 
31
    """
 
32
 
 
33
    def __init__(self, url, _decorated=None, chroot=None):
 
34
        super(ChrootTransportDecorator, self).__init__(url,
 
35
                _decorated=_decorated)
 
36
        if chroot is None:
 
37
            self.chroot_url = self._decorated.base
 
38
        else:
 
39
            self.chroot_url = chroot
 
40
        self.chroot_relative = '/' + self._decorated.base[len(self.chroot_url):]
 
41
 
 
42
    @classmethod
 
43
    def _get_url_prefix(self):
 
44
        """Chroot transport decorators are invoked via 'chroot+'"""
 
45
        return 'chroot+'
 
46
 
 
47
    def _ensure_relpath_is_child(self, relpath):
 
48
        abspath = self.abspath(relpath)
 
49
        chroot_base = self._get_url_prefix() + self.chroot_url
 
50
        real_relpath = urlutils.relative_url(chroot_base, abspath)
 
51
        if real_relpath == '..' or real_relpath.startswith('../'):
 
52
            raise errors.PathNotChild(relpath, self.chroot_url)
 
53
 
 
54
    # decorated methods
 
55
    def append_file(self, relpath, f, mode=None):
 
56
        self._ensure_relpath_is_child(relpath)
 
57
        return TransportDecorator.append_file(self, relpath, f, mode=mode)
 
58
 
 
59
    def append_bytes(self, relpath, bytes, mode=None):
 
60
        self._ensure_relpath_is_child(relpath)
 
61
        return TransportDecorator.append_bytes(self, relpath, bytes, mode=mode)
 
62
 
 
63
    def clone(self, offset=None):
 
64
        if offset is None: return self
 
65
        # the new URL we want to clone to is
 
66
        # self.chroot_url + an adjusted self.chroot_relative, with the leading
 
67
        # / removed.
 
68
        newrelative = pathjoin(self.chroot_relative, offset)
 
69
        newabs = self.chroot_url + newrelative[1:]
 
70
        # now split to get a abspath without scheme
 
71
        parsed = urlparse(newabs)
 
72
        decorated_clone = self._decorated.clone(parsed[2])
 
73
        return ChrootTransportDecorator(self._get_url_prefix() + newabs,
 
74
            decorated_clone, self.chroot_url)
 
75
 
 
76
    def delete(self, relpath):
 
77
        self._ensure_relpath_is_child(relpath)
 
78
        return TransportDecorator.delete(self, relpath)
 
79
 
 
80
    def delete_tree(self, relpath):
 
81
        self._ensure_relpath_is_child(relpath)
 
82
        return TransportDecorator.delete_tree(self, relpath)
 
83
 
 
84
    def get(self, relpath):
 
85
        self._ensure_relpath_is_child(relpath)
 
86
        return TransportDecorator.get(self, relpath)
 
87
 
 
88
    def get_bytes(self, relpath):
 
89
        self._ensure_relpath_is_child(relpath)
 
90
        return TransportDecorator.get_bytes(self, relpath)
 
91
 
 
92
    def has(self, relpath):
 
93
        self._ensure_relpath_is_child(relpath)
 
94
        return TransportDecorator.has(self, relpath)
 
95
 
 
96
    def list_dir(self, relpath):
 
97
        self._ensure_relpath_is_child(relpath)
 
98
        return TransportDecorator.list_dir(self, relpath)
 
99
 
 
100
    def lock_read(self, relpath):
 
101
        self._ensure_relpath_is_child(relpath)
 
102
        return TransportDecorator.lock_read(self, relpath)
 
103
 
 
104
    def lock_write(self, relpath):
 
105
        self._ensure_relpath_is_child(relpath)
 
106
        return TransportDecorator.lock_write(self, relpath)
 
107
 
 
108
    def mkdir(self, relpath, mode=None):
 
109
        self._ensure_relpath_is_child(relpath)
 
110
        return TransportDecorator.mkdir(self, relpath, mode=mode)
 
111
 
 
112
    def put_bytes(self, relpath, bytes, mode=None):
 
113
        self._ensure_relpath_is_child(relpath)
 
114
        return TransportDecorator.put_bytes(self, relpath, bytes, mode=mode)
 
115
 
 
116
    def put_file(self, relpath, f, mode=None):
 
117
        self._ensure_relpath_is_child(relpath)
 
118
        return TransportDecorator.put_file(self, relpath, f, mode=mode)
 
119
 
 
120
    def rename(self, rel_from, rel_to):
 
121
        self._ensure_relpath_is_child(rel_from)
 
122
        self._ensure_relpath_is_child(rel_to)
 
123
        return TransportDecorator.rename(self, rel_from, rel_to)
 
124
 
 
125
    def rmdir(self, relpath):
 
126
        self._ensure_relpath_is_child(relpath)
 
127
        return TransportDecorator.rmdir(self, relpath)
 
128
 
 
129
    def stat(self, relpath):
 
130
        self._ensure_relpath_is_child(relpath)
 
131
        return TransportDecorator.stat(self, relpath)
 
132
 
 
133
 
 
134
class ChrootServer(DecoratorServer):
 
135
    """Server for the ReadonlyTransportDecorator for testing with."""
 
136
 
 
137
    def get_decorator_class(self):
 
138
        return ChrootTransportDecorator
 
139
 
 
140
 
 
141
def get_test_permutations():
 
142
    """Return the permutations to be used in testing."""
 
143
    return [(ChrootTransportDecorator, ChrootServer),
 
144
            ]