From 5a726e1f413b9602d2b0e42fb185cf4c9b23bb79 Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Wed, 11 Apr 2018 19:08:10 +0200 Subject: [PATCH] Raise in os.remove() and os.stat() if file path ends with separator - fixes #376 - fixes #377 --- pyfakefs/fake_filesystem.py | 15 +++++++++++++++ tests/fake_os_test.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/pyfakefs/fake_filesystem.py b/pyfakefs/fake_filesystem.py index c09e34db..7c6eb59f 100644 --- a/pyfakefs/fake_filesystem.py +++ b/pyfakefs/fake_filesystem.py @@ -1064,12 +1064,23 @@ def stat(self, entry_path, follow_symlinks=True): try: file_object = self.resolve( entry_path, follow_symlinks, allow_fd=True) + self.raise_for_filepath_ending_with_separator(entry_path, + file_object) + return file_object.stat_result.copy() except IOError as io_error: winerror = (io_error.winerror if hasattr(io_error, 'winerror') else io_error.errno) self.raise_os_error(io_error.errno, entry_path, winerror=winerror) + def raise_for_filepath_ending_with_separator(self, entry_path, + file_object): + if (self.ends_with_path_separator(entry_path) and + S_ISREG(file_object.st_mode)): + error_nr = (errno.EINVAL if self.is_windows_fs + else errno.ENOTDIR) + self.raise_os_error(error_nr, entry_path) + def chmod(self, path, mode, follow_symlinks=True): """Change the permissions of a file as encoded in integer mode. @@ -1588,6 +1599,8 @@ def _is_root_path(self, file_path): def ends_with_path_separator(self, file_path): """Return True if ``file_path`` ends with a valid path separator.""" + if is_int_type(file_path): + return False file_path = make_string_path(file_path) return (file_path and (file_path.endswith(self._path_separator(file_path)) or @@ -2716,6 +2729,8 @@ def remove(self, path): else: error = errno.ENOTDIR self.raise_os_error(error, norm_path) + else: + self.raise_for_filepath_ending_with_separator(path, obj) try: self.remove_object(norm_path) diff --git a/tests/fake_os_test.py b/tests/fake_os_test.py index a37767d6..4fad76bb 100644 --- a/tests/fake_os_test.py +++ b/tests/fake_os_test.py @@ -472,6 +472,36 @@ def test_open_raises_with_trailing_separator_windows(self): self.check_windows_only() self.check_open_raises_with_trailing_separator(errno.EINVAL) + def check_stat_with_trailing_separator(self, error_nr): + # regression test for #376 + file_path = self.make_path('foo') + self.create_file(file_path) + self.assert_raises_os_error(error_nr, self.os.stat, + file_path + self.os.sep) + + def test_stat_with_trailing_separator_posix(self): + self.check_posix_only() + self.check_stat_with_trailing_separator(errno.ENOTDIR) + + def test_stat_with_trailing_separator_windows(self): + self.check_windows_only() + self.check_stat_with_trailing_separator(errno.EINVAL) + + def check_remove_with_trailing_separator(self, error_nr): + # regression test for #377 + file_path = self.make_path('foo') + self.create_file(file_path) + self.assert_raises_os_error(error_nr, self.os.remove, + file_path + self.os.sep) + + def test_remove_with_trailing_separator_posix(self): + self.check_posix_only() + self.check_remove_with_trailing_separator(errno.ENOTDIR) + + def test_remove_with_trailing_separator_windows(self): + self.check_windows_only() + self.check_remove_with_trailing_separator(errno.EINVAL) + def test_readlink(self): self.skip_if_symlink_not_supported() link_path = self.make_path('foo', 'bar', 'baz')