diff --git a/breezy/bzr/inventorytree.py b/breezy/bzr/inventorytree.py index 79ec5fe276..54083daf5c 100644 --- a/breezy/bzr/inventorytree.py +++ b/breezy/bzr/inventorytree.py @@ -671,7 +671,16 @@ def add(self, file_list, recurse=True): if this_ie.kind != 'directory': this_ie = self._convert_to_directory(this_ie, inv_path) + abspath = abspath.encode(osutils._fs_enc) + for subf in sorted(os.listdir(abspath)): + try: + subf = subf.decode(osutils._fs_enc) + except UnicodeDecodeError: + relpath = (directory.encode(osutils._fs_enc) + + b'/' + subf) + raise errors.BadFilenameEncoding(relpath, + osutils._fs_enc) inv_f, _ = osutils.normalized_filename(subf) # here we could use TreeDirectory rather than # string concatenation. diff --git a/breezy/bzr/workingtree.py b/breezy/bzr/workingtree.py index 91149ddf84..d4cc82c5f9 100644 --- a/breezy/bzr/workingtree.py +++ b/breezy/bzr/workingtree.py @@ -1104,7 +1104,15 @@ def list_files(self, include_root=False, from_dir=None, recursive=True): # But do this child first if recursing down if recursive: - new_children = sorted(os.listdir(fap)) + new_children = [] + for subf in os.listdir(fap.encode(osutils._fs_enc)): + try: + new_children.append(subf.decode(osutils._fs_enc)) + except UnicodeDecodeError: + relpath = fp.lstrip('/').encode(osutils._fs_enc) + b'/' + subf + raise errors.BadFilenameEncoding(relpath, + osutils._fs_enc) + new_children.sort() new_children = collections.deque(new_children) stack.append((f_ie.file_id, fp, fap, new_children)) # Break out of inner loop, diff --git a/breezy/git/workingtree.py b/breezy/git/workingtree.py index a87b6c0295..784a190858 100644 --- a/breezy/git/workingtree.py +++ b/breezy/git/workingtree.py @@ -482,7 +482,13 @@ def call_action(filepath, kind): trace.warning('skipping nested tree %r', abs_user_dir) continue - for name in os.listdir(abs_user_dir): + for name in os.listdir(abs_user_dir.encode(osutils._fs_enc)): + try: + name = name.decode(osutils._fs_enc) + except UnicodeDecodeError: + relpath = user_dir.encode(osutils._fs_enc) + b'/' + name + raise errors.BadFilenameEncoding(relpath, + osutils._fs_enc) subp = os.path.join(user_dir, name) if self.is_control_filename(subp) or self.mapping.is_special_file(subp): continue diff --git a/breezy/tests/per_workingtree/test_smart_add.py b/breezy/tests/per_workingtree/test_smart_add.py index 709f0670f4..e458c4389b 100644 --- a/breezy/tests/per_workingtree/test_smart_add.py +++ b/breezy/tests/per_workingtree/test_smart_add.py @@ -377,3 +377,28 @@ def test_inaccessible_implicit(self): # just ignore files that don't fit the normalization # rules, rather than exploding self.assertRaises(errors.InvalidNormalization, self.wt.smart_add, []) + + +class TestIllegalPaths(per_workingtree.TestCaseWithWorkingTree): + + def test_bad_fs_path(self): + if osutils.normalizes_filenames(): + # You *can't* create an illegal filename on OSX. + raise tests.TestNotApplicable('OSX normalizes filenames') + self.requireFeature(features.UTF8Filesystem) + # We require a UTF8 filesystem, because otherwise we would need to get + # tricky to figure out how to create an illegal filename. + # \xb5 is an illegal path because it should be \xc2\xb5 for UTF-8 + tree = self.make_branch_and_tree('tree') + self.build_tree(['tree/subdir/', 'tree/subdir/somefile']) + tree.add(['subdir', 'subdir/somefile']) + + with open(b'tree/subdir/m\xb5', 'wb') as f: + f.write(b'trivial\n') + + with tree.lock_tree_write(): + e = self.assertListRaises(errors.BadFilenameEncoding, + tree.smart_add, ['tree']) + # We should display the relative path + self.assertEqual(b'subdir/m\xb5', e.filename) + self.assertEqual(osutils._fs_enc, e.fs_encoding) diff --git a/doc/en/release-notes/brz-3.0.txt b/doc/en/release-notes/brz-3.0.txt index 6f70d94026..329d9caf3d 100644 --- a/doc/en/release-notes/brz-3.0.txt +++ b/doc/en/release-notes/brz-3.0.txt @@ -171,6 +171,11 @@ Bug Fixes * Support '0' markers in fastimport plugin. (Jelmer Vernooij, #1744615) +* Raise a clearer exception when encountering filenames not in + the current encoding when running 'brz add'. + (Jelmer Vernooij, #715547) + + Documentation *************