1
# Copyright (C) 2005 Canonical Ltd
1
# Copyright (C) 2005 by Canonical Ltd
2
2
# -*- coding: utf-8 -*-
4
4
# This program is free software; you can redistribute it and/or modify
5
5
# it under the terms of the GNU General Public License as published by
6
6
# the Free Software Foundation; either version 2 of the License, or
7
7
# (at your option) any later version.
9
9
# This program is distributed in the hope that it will be useful,
10
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
12
# GNU General Public License for more details.
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
19
"""Tests for bzr setting permissions.
28
28
# TODO: jam 20051215 There are no tests for ftp yet, because we have no ftp server
29
# TODO: jam 20051215 Currently the default behavior for 'bzr branch' is just
29
# TODO: jam 20051215 Currently the default behavior for 'bzr branch' is just
30
30
# defined by the local umask. This isn't terrible, is it
31
31
# the truly desired behavior?
36
from cStringIO import StringIO
36
from StringIO import StringIO
39
38
from bzrlib.branch import Branch
40
from bzrlib.bzrdir import BzrDir
41
from bzrlib.tests import TestCaseWithTransport, TestSkipped
39
from bzrlib.lockable_files import LockableFiles
40
from bzrlib.tests import TestCaseInTempDir, TestSkipped
41
from bzrlib.transport import get_transport
42
43
from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
43
44
from bzrlib.transport import get_transport
44
from bzrlib.workingtree import WorkingTree
47
47
def chmod_r(base, file_mode, dir_mode):
48
48
"""Recursively chmod from a base directory"""
49
assert os.path.isdir(base)
49
50
os.chmod(base, dir_mode)
50
51
for root, dirs, files in os.walk(base):
65
66
:param dir_mode: The mode for all directories
66
67
:param include_base: If false, only check the subdirectories
69
assert os.path.isdir(base)
68
70
t = get_transport(".")
70
72
test.assertTransportMode(t, base, dir_mode)
71
73
for root, dirs, files in os.walk(base):
73
p = '/'.join([urllib.quote(x) for x in root.split('/\\') + [d]])
75
p = os.path.join(root, d)
74
76
test.assertTransportMode(t, p, dir_mode)
76
78
p = os.path.join(root, f)
77
p = '/'.join([urllib.quote(x) for x in root.split('/\\') + [f]])
78
79
test.assertTransportMode(t, p, file_mode)
81
class TestPermissions(TestCaseWithTransport):
82
def assertEqualMode(test, mode, mode_test):
83
test.assertEqual(mode, mode_test,
84
'mode mismatch %o != %o' % (mode, mode_test))
87
class TestPermissions(TestCaseInTempDir):
83
89
def test_new_files(self):
84
90
if sys.platform == 'win32':
85
91
raise TestSkipped('chmod has no effect on win32')
87
t = self.make_branch_and_tree('.')
93
b = Branch.initialize(u'.')
89
95
open('a', 'wb').write('foo\n')
90
# ensure check_mode_r works with capital-letter file-ids like TREE_ROOT
99
# Delete them because we are modifying the filesystem underneath them
94
101
chmod_r('.bzr', 0644, 0755)
95
102
check_mode_r(self, '.bzr', 0644, 0755)
97
# although we are modifying the filesystem
98
# underneath the objects, they are not locked, and thus it must
99
# be safe for most operations. But here we want to observe a
100
# mode change in the control bits, which current do not refresh
101
# when a new lock is taken out.
102
t = WorkingTree.open('.')
104
self.assertEqualMode(0755, b.control_files._dir_mode)
105
self.assertEqualMode(0644, b.control_files._file_mode)
106
self.assertEqualMode(0755, b.bzrdir._get_dir_mode())
107
self.assertEqualMode(0644, b.bzrdir._get_file_mode())
106
assertEqualMode(self, 0755, b.control_files._dir_mode)
107
assertEqualMode(self, 0644, b.control_files._file_mode)
109
109
# Modifying a file shouldn't break the permissions
110
110
open('a', 'wb').write('foo2\n')
118
118
t.commit('new b')
119
119
check_mode_r(self, '.bzr', 0644, 0755)
121
122
# Recursively update the modes of all files
122
123
chmod_r('.bzr', 0664, 0775)
123
124
check_mode_r(self, '.bzr', 0664, 0775)
124
t = WorkingTree.open('.')
126
self.assertEqualMode(0775, b.control_files._dir_mode)
127
self.assertEqualMode(0664, b.control_files._file_mode)
128
self.assertEqualMode(0775, b.bzrdir._get_dir_mode())
129
self.assertEqualMode(0664, b.bzrdir._get_file_mode())
127
assertEqualMode(self, 0775, b.control_files._dir_mode)
128
assertEqualMode(self, 0664, b.control_files._file_mode)
131
130
open('a', 'wb').write('foo3\n')
137
136
t.commit('new c')
138
137
check_mode_r(self, '.bzr', 0664, 0775)
140
def test_new_files_group_sticky_bit(self):
141
if sys.platform == 'win32':
142
raise TestSkipped('chmod has no effect on win32')
143
elif sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
144
# OS X (and FreeBSD) create temp dirs with the 'wheel' group, which
145
# users are not likely to be in, and this prevents us from setting
147
os.chown(self.test_dir, os.getuid(), os.getgid())
149
t = self.make_branch_and_tree('.')
152
139
# Test the group sticky bit
153
141
# Recursively update the modes of all files
154
142
chmod_r('.bzr', 0664, 02775)
155
143
check_mode_r(self, '.bzr', 0664, 02775)
156
t = WorkingTree.open('.')
158
self.assertEqualMode(02775, b.control_files._dir_mode)
159
self.assertEqualMode(0664, b.control_files._file_mode)
160
self.assertEqualMode(02775, b.bzrdir._get_dir_mode())
161
self.assertEqualMode(0664, b.bzrdir._get_file_mode())
146
assertEqualMode(self, 02775, b.control_files._dir_mode)
147
assertEqualMode(self, 0664, b.control_files._file_mode)
163
149
open('a', 'wb').write('foo4\n')
169
155
t.commit('new d')
170
156
check_mode_r(self, '.bzr', 0664, 02775)
158
def test_disable_set_mode(self):
159
# TODO: jam 20051215 Ultimately, this test should probably test that
160
# extra chmod calls aren't being made
162
transport = get_transport('.')
163
transport.put('my-lock', StringIO(''))
164
lockable = LockableFiles(transport, 'my-lock')
165
self.assertNotEqual(None, lockable._dir_mode)
166
self.assertNotEqual(None, lockable._file_mode)
168
LockableFiles._set_dir_mode = False
169
transport = get_transport('.')
170
lockable = LockableFiles(transport, 'my-lock')
171
self.assertEqual(None, lockable._dir_mode)
172
self.assertNotEqual(None, lockable._file_mode)
174
LockableFiles._set_file_mode = False
175
transport = get_transport('.')
176
lockable = LockableFiles(transport, 'my-lock')
177
self.assertEqual(None, lockable._dir_mode)
178
self.assertEqual(None, lockable._file_mode)
180
LockableFiles._set_dir_mode = True
181
transport = get_transport('.')
182
lockable = LockableFiles(transport, 'my-lock')
183
self.assertNotEqual(None, lockable._dir_mode)
184
self.assertEqual(None, lockable._file_mode)
186
LockableFiles._set_file_mode = True
187
transport = get_transport('.')
188
lockable = LockableFiles(transport, 'my-lock')
189
self.assertNotEqual(None, lockable._dir_mode)
190
self.assertNotEqual(None, lockable._file_mode)
192
LockableFiles._set_dir_mode = True
193
LockableFiles._set_file_mode = True
195
def test_new_branch(self):
196
if sys.platform == 'win32':
197
raise TestSkipped('chmod has no effect on win32')
198
#FIXME RBC 20060105 should test branch and repository
200
# also, these are BzrBranch format specific things..
202
mode = stat.S_IMODE(os.stat('a').st_mode)
203
b = Branch.initialize('a')
204
assertEqualMode(self, mode, b.control_files._dir_mode)
205
assertEqualMode(self, mode & ~07111, b.control_files._file_mode)
209
b = Branch.initialize('b')
210
assertEqualMode(self, 02777, b.control_files._dir_mode)
211
assertEqualMode(self, 00666, b.control_files._file_mode)
212
check_mode_r(self, 'b/.bzr', 00666, 02777)
216
b = Branch.initialize('c')
217
assertEqualMode(self, 02750, b.control_files._dir_mode)
218
assertEqualMode(self, 00640, b.control_files._file_mode)
219
check_mode_r(self, 'c/.bzr', 00640, 02750)
223
b = Branch.initialize('d')
224
assertEqualMode(self, 0700, b.control_files._dir_mode)
225
assertEqualMode(self, 0600, b.control_files._file_mode)
226
check_mode_r(self, 'd/.bzr', 00600, 0700)
173
229
class TestSftpPermissions(TestCaseWithSFTPServer):
178
234
# Though it would be nice to test that SFTP to a server
179
235
# which does support chmod has the right effect
181
# bodge around for stubsftpserver not letting use connect
183
_t = get_transport(self.get_url())
237
from bzrlib.transport.sftp import SFTPTransport
239
# We don't actually use it directly, we just want to
240
# keep the connection open, since StubSFTPServer only
241
# allows 1 connection
242
_transport = SFTPTransport(self._sftp_url)
185
244
os.mkdir('local')
186
t_local = self.make_branch_and_tree('local')
187
b_local = t_local.branch
245
b_local = Branch.initialize(u'local')
246
t_local = b_local.working_tree()
188
247
open('local/a', 'wb').write('foo\n')
190
249
t_local.commit('foo')
192
251
# Delete them because we are modifying the filesystem underneath them
193
253
chmod_r('local/.bzr', 0644, 0755)
194
254
check_mode_r(self, 'local/.bzr', 0644, 0755)
196
t = WorkingTree.open('local')
198
self.assertEqualMode(0755, b_local.control_files._dir_mode)
199
self.assertEqualMode(0644, b_local.control_files._file_mode)
200
self.assertEqualMode(0755, b_local.bzrdir._get_dir_mode())
201
self.assertEqualMode(0644, b_local.bzrdir._get_file_mode())
256
b_local = Branch.open(u'local')
257
t_local = b_local.working_tree()
258
assertEqualMode(self, 0755, b_local.control_files._dir_mode)
259
assertEqualMode(self, 0644, b_local.control_files._file_mode)
204
sftp_url = self.get_url('sftp')
205
b_sftp = BzrDir.create_branch_and_repo(sftp_url)
262
sftp_url = self.get_remote_url('sftp')
263
b_sftp = Branch.initialize(sftp_url)
207
265
b_sftp.pull(b_local)
210
268
check_mode_r(self, 'sftp/.bzr', 0644, 0755)
212
270
b_sftp = Branch.open(sftp_url)
213
self.assertEqualMode(0755, b_sftp.control_files._dir_mode)
214
self.assertEqualMode(0644, b_sftp.control_files._file_mode)
215
self.assertEqualMode(0755, b_sftp.bzrdir._get_dir_mode())
216
self.assertEqualMode(0644, b_sftp.bzrdir._get_file_mode())
271
assertEqualMode(self, 0755, b_sftp.control_files._dir_mode)
272
assertEqualMode(self, 0644, b_sftp.control_files._file_mode)
218
274
open('local/a', 'wb').write('foo2\n')
219
275
t_local.commit('foo2')
233
289
check_mode_r(self, 'sftp/.bzr', 0664, 0775)
235
291
b_sftp = Branch.open(sftp_url)
236
self.assertEqualMode(0775, b_sftp.control_files._dir_mode)
237
self.assertEqualMode(0664, b_sftp.control_files._file_mode)
238
self.assertEqualMode(0775, b_sftp.bzrdir._get_dir_mode())
239
self.assertEqualMode(0664, b_sftp.bzrdir._get_file_mode())
292
assertEqualMode(self, 0775, b_sftp.control_files._dir_mode)
293
assertEqualMode(self, 0664, b_sftp.control_files._file_mode)
241
295
open('local/a', 'wb').write('foo3\n')
242
296
t_local.commit('foo3')
257
311
original_umask = os.umask(umask)
260
t = get_transport(self.get_url())
314
from bzrlib.transport.sftp import SFTPTransport
315
t = SFTPTransport(self._sftp_url)
261
316
# Direct access should be masked by umask
262
317
t._sftp_open_exclusive('a', mode=0666).write('foo\n')
263
318
self.assertTransportMode(t, 'a', 0666 &~umask)
265
320
# but Transport overrides umask
266
t.put_bytes('b', 'txt', mode=0666)
321
t.put('b', 'txt', mode=0666)
267
322
self.assertTransportMode(t, 'b', 0666)
269
t._get_sftp().mkdir('c', mode=0777)
324
t._sftp.mkdir('c', mode=0777)
270
325
self.assertTransportMode(t, 'c', 0777 &~umask)
272
327
t.mkdir('d', mode=0777)
273
328
self.assertTransportMode(t, 'd', 0777)
275
330
os.umask(original_umask)