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 StringIO import StringIO
36
from bzrlib import urlutils
37
39
from bzrlib.branch import Branch
38
from bzrlib.controldir import ControlDir
40
from bzrlib.bzrdir import BzrDir
41
from bzrlib.lockable_files import LockableFiles, TransportLock
39
42
from bzrlib.tests import TestCaseWithTransport, TestSkipped
40
43
from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
44
from bzrlib.transport import get_transport
41
45
from bzrlib.workingtree import WorkingTree
44
48
def chmod_r(base, file_mode, dir_mode):
45
49
"""Recursively chmod from a base directory"""
50
assert os.path.isdir(base)
46
51
os.chmod(base, dir_mode)
47
52
for root, dirs, files in os.walk(base):
62
67
:param dir_mode: The mode for all directories
63
68
:param include_base: If false, only check the subdirectories
65
t = test.get_transport()
70
assert os.path.isdir(base)
71
t = get_transport(".")
67
73
test.assertTransportMode(t, base, dir_mode)
68
74
for root, dirs, files in os.walk(base):
70
p = '/'.join([urlutils.quote(x) for x in root.split('/\\') + [d]])
76
p = '/'.join([urllib.quote(x) for x in root.split('/\\') + [d]])
71
77
test.assertTransportMode(t, p, dir_mode)
73
79
p = os.path.join(root, f)
74
p = '/'.join([urlutils.quote(x) for x in root.split('/\\') + [f]])
80
p = '/'.join([urllib.quote(x) for x in root.split('/\\') + [f]])
75
81
test.assertTransportMode(t, p, file_mode)
94
100
# although we are modifying the filesystem
95
101
# underneath the objects, they are not locked, and thus it must
96
# be safe for most operations. But here we want to observe a
102
# be safe for most operations. But here we want to observe a
97
103
# mode change in the control bits, which current do not refresh
98
104
# when a new lock is taken out.
99
105
t = WorkingTree.open('.')
101
107
self.assertEqualMode(0755, b.control_files._dir_mode)
102
108
self.assertEqualMode(0644, b.control_files._file_mode)
103
self.assertEqualMode(0755, b.bzrdir._get_dir_mode())
104
self.assertEqualMode(0644, b.bzrdir._get_file_mode())
106
110
# Modifying a file shouldn't break the permissions
107
with open('a', 'wb') as f: f.write('foo2\n')
111
open('a', 'wb').write('foo2\n')
109
113
# The mode should be maintained after commit
110
114
check_mode_r(self, '.bzr', 0644, 0755)
112
116
# Adding a new file should maintain the permissions
113
with open('b', 'wb') as f: f.write('new b\n')
117
open('b', 'wb').write('new b\n')
115
119
t.commit('new b')
116
120
check_mode_r(self, '.bzr', 0644, 0755)
123
127
self.assertEqualMode(0775, b.control_files._dir_mode)
124
128
self.assertEqualMode(0664, b.control_files._file_mode)
125
self.assertEqualMode(0775, b.bzrdir._get_dir_mode())
126
self.assertEqualMode(0664, b.bzrdir._get_file_mode())
128
with open('a', 'wb') as f: f.write('foo3\n')
130
open('a', 'wb').write('foo3\n')
130
132
check_mode_r(self, '.bzr', 0664, 0775)
132
with open('c', 'wb') as f: f.write('new c\n')
134
open('c', 'wb').write('new c\n')
134
136
t.commit('new c')
135
137
check_mode_r(self, '.bzr', 0664, 0775)
137
def test_new_files_group_sticky_bit(self):
138
if sys.platform == 'win32':
139
raise TestSkipped('chmod has no effect on win32')
140
elif sys.platform == 'darwin' or 'freebsd' in sys.platform:
141
# FreeBSD-based platforms create temp dirs with the 'wheel' group,
142
# which users are not likely to be in, and this prevents us from
143
# setting the sgid bit
144
os.chown(self.test_dir, os.getuid(), os.getgid())
146
t = self.make_branch_and_tree('.')
149
139
# Test the group sticky bit
150
140
# Recursively update the modes of all files
151
141
chmod_r('.bzr', 0664, 02775)
155
145
self.assertEqualMode(02775, b.control_files._dir_mode)
156
146
self.assertEqualMode(0664, b.control_files._file_mode)
157
self.assertEqualMode(02775, b.bzrdir._get_dir_mode())
158
self.assertEqualMode(0664, b.bzrdir._get_file_mode())
160
with open('a', 'wb') as f: f.write('foo4\n')
148
open('a', 'wb').write('foo4\n')
162
150
check_mode_r(self, '.bzr', 0664, 02775)
164
with open('d', 'wb') as f: f.write('new d\n')
152
open('d', 'wb').write('new d\n')
166
154
t.commit('new d')
167
155
check_mode_r(self, '.bzr', 0664, 02775)
157
def test_disable_set_mode(self):
158
# TODO: jam 20051215 Ultimately, this test should probably test that
159
# extra chmod calls aren't being made
161
transport = get_transport(self.get_url())
162
transport.put('my-lock', StringIO(''))
163
lockable = LockableFiles(transport, 'my-lock', TransportLock)
164
self.assertNotEqual(None, lockable._dir_mode)
165
self.assertNotEqual(None, lockable._file_mode)
167
LockableFiles._set_dir_mode = False
168
transport = get_transport('.')
169
lockable = LockableFiles(transport, 'my-lock', TransportLock)
170
self.assertEqual(None, lockable._dir_mode)
171
self.assertNotEqual(None, lockable._file_mode)
173
LockableFiles._set_file_mode = False
174
transport = get_transport('.')
175
lockable = LockableFiles(transport, 'my-lock', TransportLock)
176
self.assertEqual(None, lockable._dir_mode)
177
self.assertEqual(None, lockable._file_mode)
179
LockableFiles._set_dir_mode = True
180
transport = get_transport('.')
181
lockable = LockableFiles(transport, 'my-lock', TransportLock)
182
self.assertNotEqual(None, lockable._dir_mode)
183
self.assertEqual(None, lockable._file_mode)
185
LockableFiles._set_file_mode = True
186
transport = get_transport('.')
187
lockable = LockableFiles(transport, 'my-lock', TransportLock)
188
self.assertNotEqual(None, lockable._dir_mode)
189
self.assertNotEqual(None, lockable._file_mode)
191
LockableFiles._set_dir_mode = True
192
LockableFiles._set_file_mode = True
170
195
class TestSftpPermissions(TestCaseWithSFTPServer):
194
219
b_local = t.branch
195
220
self.assertEqualMode(0755, b_local.control_files._dir_mode)
196
221
self.assertEqualMode(0644, b_local.control_files._file_mode)
197
self.assertEqualMode(0755, b_local.bzrdir._get_dir_mode())
198
self.assertEqualMode(0644, b_local.bzrdir._get_file_mode())
201
224
sftp_url = self.get_url('sftp')
202
b_sftp = ControlDir.create_branch_and_repo(sftp_url)
225
b_sftp = BzrDir.create_branch_and_repo(sftp_url)
204
227
b_sftp.pull(b_local)
209
232
b_sftp = Branch.open(sftp_url)
210
233
self.assertEqualMode(0755, b_sftp.control_files._dir_mode)
211
234
self.assertEqualMode(0644, b_sftp.control_files._file_mode)
212
self.assertEqualMode(0755, b_sftp.bzrdir._get_dir_mode())
213
self.assertEqualMode(0644, b_sftp.bzrdir._get_file_mode())
215
with open('local/a', 'wb') as f: f.write('foo2\n')
236
open('local/a', 'wb').write('foo2\n')
216
237
t_local.commit('foo2')
217
238
b_sftp.pull(b_local)
218
239
# The mode should be maintained after commit
219
240
check_mode_r(self, 'sftp/.bzr', 0644, 0755)
221
with open('local/b', 'wb') as f: f.write('new b\n')
242
open('local/b', 'wb').write('new b\n')
223
244
t_local.commit('new b')
224
245
b_sftp.pull(b_local)
232
253
b_sftp = Branch.open(sftp_url)
233
254
self.assertEqualMode(0775, b_sftp.control_files._dir_mode)
234
255
self.assertEqualMode(0664, b_sftp.control_files._file_mode)
235
self.assertEqualMode(0775, b_sftp.bzrdir._get_dir_mode())
236
self.assertEqualMode(0664, b_sftp.bzrdir._get_file_mode())
238
with open('local/a', 'wb') as f: f.write('foo3\n')
257
open('local/a', 'wb').write('foo3\n')
239
258
t_local.commit('foo3')
240
259
b_sftp.pull(b_local)
241
260
check_mode_r(self, 'sftp/.bzr', 0664, 0775)
243
with open('local/c', 'wb') as f: f.write('new c\n')
262
open('local/c', 'wb').write('new c\n')
245
264
t_local.commit('new c')
246
265
b_sftp.pull(b_local)
254
273
original_umask = os.umask(umask)
257
t = self.get_transport()
276
t = get_transport(self.get_url())
258
277
# Direct access should be masked by umask
259
278
t._sftp_open_exclusive('a', mode=0666).write('foo\n')
260
279
self.assertTransportMode(t, 'a', 0666 &~umask)
262
281
# but Transport overrides umask
263
t.put_bytes('b', 'txt', mode=0666)
282
t.put('b', 'txt', mode=0666)
264
283
self.assertTransportMode(t, 'b', 0666)
266
t._get_sftp().mkdir('c', mode=0777)
285
t._sftp.mkdir('c', mode=0777)
267
286
self.assertTransportMode(t, 'c', 0777 &~umask)
269
288
t.mkdir('d', mode=0777)