# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) <jborean93@gmail.com> # MIT License (see LICENSE or https://opensource.org/licenses/MIT) from __future__ import division import ntpath import os import pytest import re import shutil import stat import sys from smbclient import ( listdir, makedirs, mkdir, open_file, readlink, remove, rmdir, stat as smbclient_stat, symlink, utime, ) from smbclient._io import ( set_info, SMBFileTransaction, SMBRawIO, ) from smbclient.path import ( exists, islink, samefile, ) from smbclient.shutil import ( copy, copy2, copyfile, copymode, copystat, copytree, rmtree, ) from smbprotocol.exceptions import ( SMBOSError, ) from smbprotocol.file_info import ( FileBasicInformation, ) from smbprotocol.open import ( CreateOptions, FileAttributes, FilePipePrinterAccessMask, ) def _set_file_attributes(path, attributes): with SMBRawIO(path, mode='rb', create_options=CreateOptions.FILE_OPEN_REPARSE_POINT, desired_access=FilePipePrinterAccessMask.FILE_WRITE_ATTRIBUTES) as fd: with SMBFileTransaction(fd) as transaction: basic_info = FileBasicInformation() basic_info['file_attributes'] = attributes set_info(transaction, basic_info) def test_copy(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"content") actual = copy(src_filename, dst_filename) assert actual == dst_filename with open_file(dst_filename) as fd: assert fd.read() == u"content" src_stat = smbclient_stat(src_filename) actual = smbclient_stat(dst_filename) assert actual.st_atime != src_stat.st_atime assert actual.st_mtime != src_stat.st_mtime assert actual.st_ctime != src_stat.st_ctime assert actual.st_chgtime != src_stat.st_chgtime assert actual.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == FileAttributes.FILE_ATTRIBUTE_READONLY def test_copy_with_dir_as_target(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\directory" % smb_share mkdir(dst_filename) with open_file(src_filename, mode='w') as fd: fd.write(u"content") actual = copy(src_filename, dst_filename) assert actual == ntpath.join(dst_filename, "source.txt") with open_file("%s\\source.txt" % dst_filename) as fd: assert fd.read() == u"content" src_stat = smbclient_stat(src_filename) actual = smbclient_stat("%s\\source.txt" % dst_filename) assert actual.st_atime != src_stat.st_atime assert actual.st_mtime != src_stat.st_mtime assert actual.st_ctime != src_stat.st_ctime assert actual.st_chgtime != src_stat.st_chgtime assert actual.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 def test_copy_raises_when_source_and_target_identical_remote(smb_share): filename = "%s\\file.txt" % smb_share with open_file(filename, mode='w') as fd: fd.write(u"content") expected = "are the same file" with pytest.raises(Exception, match=re.escape(expected)): copy(filename, filename) def test_copy_raises_when_source_and_target_identical_local(tmpdir): test_dir = tmpdir.mkdir('test').strpath filename = os.path.join(test_dir, 'file.txt') with open(filename, mode='w') as fd: fd.write(u"content") expected = "are the same file" with pytest.raises(Exception, match=re.escape(expected)): copy(filename, filename) @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="Samba does not update timestamps") def test_copy2(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"content") utime(src_filename, times=(1024, 1024)) actual = copy2(src_filename, dst_filename) assert actual == dst_filename with open_file(dst_filename) as fd: assert fd.read() == u"content" src_stat = smbclient_stat(src_filename) actual = smbclient_stat(dst_filename) assert actual.st_atime == 1024 assert actual.st_mtime == 1024 assert actual.st_ctime != src_stat.st_ctime assert actual.st_chgtime != src_stat.st_chgtime assert actual.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == FileAttributes.FILE_ATTRIBUTE_READONLY @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="Samba does not update timestamps") def test_copy2_with_dir_as_target(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\directory" % smb_share mkdir(dst_filename) with open_file(src_filename, mode='w') as fd: fd.write(u"content") utime(src_filename, times=(1024, 1024)) actual = copy2(src_filename, dst_filename) assert actual == ntpath.join(dst_filename, "source.txt") with open_file("%s\\source.txt" % dst_filename) as fd: assert fd.read() == u"content" src_stat = smbclient_stat(src_filename) actual = smbclient_stat("%s\\source.txt" % dst_filename) assert actual.st_atime == 1024 assert actual.st_mtime == 1024 assert actual.st_ctime != src_stat.st_ctime assert actual.st_chgtime != src_stat.st_chgtime assert actual.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 def test_copy2_raises_when_source_and_target_identical_remote(smb_share): filename = "%s\\file.txt" % smb_share with open_file(filename, mode='w') as fd: fd.write(u"content") expected = "are the same file" with pytest.raises(Exception, match=re.escape(expected)): copy2(filename, filename) def test_copy2_raises_when_source_and_target_identical_local(tmpdir): test_dir = tmpdir.mkdir('test').strpath filename = os.path.join(test_dir, 'file.txt') with open(filename, mode='w') as fd: fd.write(u"content") expected = "are the same file" with pytest.raises(Exception, match=re.escape(expected)): copy2(filename, filename) def test_copyfile_identical(smb_share): filename = "%s\\file.txt" % smb_share with open_file(filename, mode='w') as fd: fd.write(u"content") expected = "are the same file" with pytest.raises(Exception, match=re.escape(expected)): copyfile(filename, filename) def test_copyfile_remote_to_remote(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w') as fd: fd.write(u"content") actual = copyfile(src_filename, dst_filename) assert actual == dst_filename with open_file(dst_filename) as fd: assert fd.read() == u"content" def test_copyfile_remote_to_remote_existing(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w') as fd: fd.write(u"content") with open_file(dst_filename, mode='w') as fd: fd.write(u"something different") actual = copyfile(src_filename, dst_filename) assert actual == dst_filename with open_file(dst_filename) as fd: assert fd.read() == u"content" def test_copyfile_local_to_remote(smb_share, tmpdir): test_dir = tmpdir.mkdir("test") src_filename = "%s\\source.txt" % test_dir dst_filename = "%s\\target.txt" % smb_share with open(src_filename, mode='w') as fd: fd.write(u"content") actual = copyfile(src_filename, dst_filename) assert actual == dst_filename with open_file(dst_filename) as fd: assert fd.read() == u"content" def test_copyfile_remote_to_local(smb_share, tmpdir): test_dir = tmpdir.mkdir("test") src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % test_dir with open_file(src_filename, mode='w') as fd: fd.write(u"content") actual = copyfile(src_filename, dst_filename) assert actual == dst_filename with open(dst_filename) as fd: assert fd.read() == u"content" def test_copyfile_local_to_local(tmpdir): test_dir = tmpdir.mkdir("test") src_filename = "%s\\source.txt" % test_dir dst_filename = "%s\\target.txt" % test_dir with open(src_filename, mode='w') as fd: fd.write(u"content") actual = copyfile(src_filename, dst_filename) assert actual == dst_filename with open(dst_filename) as fd: assert fd.read() == u"content" def test_copyfile_fail_src_is_dir(smb_share): src_filename = "%s\\source" % smb_share dst_filename = "%s\\target.txt" % smb_share mkdir(src_filename) expected = "[NtStatus 0xc00000ba] Is a directory: " with pytest.raises(OSError, match=re.escape(expected)): copyfile(src_filename, dst_filename) def test_copyfile_fail_dst_is_dir(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target" % smb_share with open_file(src_filename, mode='w') as fd: fd.write(u"content") mkdir(dst_filename) expected = "[NtStatus 0xc00000ba] Is a directory: " with pytest.raises(OSError, match=re.escape(expected)): copyfile(src_filename, dst_filename) @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_copyfile_symlink_follow(smb_share): src_filename = "%s\\source.txt" % smb_share src_link = "%s\\source-link.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w') as fd: fd.write(u"content") symlink(src_filename, src_link) actual = copyfile(src_link, dst_filename) assert actual == dst_filename with open_file(dst_filename, mode='r') as fd: assert fd.read() == u"content" assert not islink(dst_filename) @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_copyfile_symlink_dont_follow(smb_share): src_filename = "%s\\source.txt" % smb_share src_link = "%s\\source-link.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w') as fd: fd.write(u"content") symlink(src_filename, src_link) actual = copyfile(src_link, dst_filename, follow_symlinks=False) assert actual == dst_filename with open_file(dst_filename, mode='r') as fd: assert fd.read() == u"content" assert islink(dst_filename) assert readlink(dst_filename) == ntpath.normpath(src_filename) @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_copyfile_symlink_across_boundary_fail(smb_share): src_filename = "%s\\link" % smb_share symlink("%s\\missing" % smb_share, src_filename) expected = "Cannot copy a symlink on different roots." with pytest.raises(ValueError, match=re.escape(expected)): copyfile(src_filename, "/tmp", follow_symlinks=False) def test_copymode_of_file(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"content") with open_file(dst_filename, mode='w') as fd: fd.write(u"content") copymode(src_filename, dst_filename) actual = smbclient_stat(dst_filename).st_file_attributes assert actual & FileAttributes.FILE_ATTRIBUTE_READONLY == FileAttributes.FILE_ATTRIBUTE_READONLY remove(src_filename) with open_file(src_filename, mode='w') as fd: fd.write(u"content") copymode(src_filename, dst_filename) actual = smbclient_stat(dst_filename).st_file_attributes assert actual & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 def test_copymode_of_file_with_no_attributes(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"content") with open_file(dst_filename, mode='w') as fd: fd.write(u"content") copymode(src_filename, dst_filename) actual = smbclient_stat(dst_filename).st_file_attributes assert actual & FileAttributes.FILE_ATTRIBUTE_READONLY == FileAttributes.FILE_ATTRIBUTE_READONLY remove(src_filename) with open_file(src_filename, mode='w') as fd: fd.write(u"content") # Remove the Archive attribute on the dest file to simulate the file having only just READONLY. _set_file_attributes(dst_filename, FileAttributes.FILE_ATTRIBUTE_READONLY) copymode(src_filename, dst_filename) actual = smbclient_stat(dst_filename).st_file_attributes assert actual == FileAttributes.FILE_ATTRIBUTE_NORMAL def test_copymode_of_dir(smb_share): src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\target" % smb_share with open_file(src_dirname, mode='xb', file_type='dir', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY, buffering=0): pass mkdir(dst_dirname) copymode(src_dirname, dst_dirname) actual = smbclient_stat(dst_dirname).st_file_attributes assert actual & FileAttributes.FILE_ATTRIBUTE_READONLY == FileAttributes.FILE_ATTRIBUTE_READONLY rmdir(src_dirname) mkdir(src_dirname) copymode(src_dirname, dst_dirname) actual = smbclient_stat(dst_dirname).st_file_attributes assert actual & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 def test_copymode_local_to_remote(smb_share, tmpdir): test_dir = tmpdir.mkdir("test") src_filename = "%s\\source.txt" % test_dir dst_filename = "%s\\target.txt" % smb_share with open(src_filename, mode='w') as fd: fd.write(u"content") os.chmod(src_filename, stat.S_IREAD) with open_file(dst_filename, mode='w') as fd: fd.write(u"content") copymode(src_filename, dst_filename) actual = smbclient_stat(dst_filename).st_file_attributes assert actual & FileAttributes.FILE_ATTRIBUTE_READONLY == FileAttributes.FILE_ATTRIBUTE_READONLY os.chmod(src_filename, stat.S_IWRITE) # Needed when running on Windows as os.remove will fail to remove. os.remove(src_filename) with open(src_filename, mode='w') as fd: fd.write(u"content") copymode(src_filename, dst_filename) actual = smbclient_stat(dst_filename).st_file_attributes assert actual & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 def test_copymode_remote_to_local(smb_share, tmpdir): test_dir = tmpdir.mkdir("test") src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % test_dir with open_file(src_filename, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"content") with open(dst_filename, mode='w') as fd: fd.write(u"content") copymode(src_filename, dst_filename) actual = os.stat(dst_filename).st_mode assert stat.S_IMODE(actual) & stat.S_IWRITE == 0 remove(src_filename) with open_file(src_filename, mode='w') as fd: fd.write(u"content") copymode(src_filename, dst_filename) actual = os.stat(dst_filename).st_mode assert stat.S_IMODE(actual) & stat.S_IWRITE == stat.S_IWRITE def test_copymode_local_to_local(tmpdir): test_dir = tmpdir.mkdir("test") src_filename = "%s\\source.txt" % test_dir dst_filename = "%s\\target.txt" % test_dir with open(src_filename, mode='w') as fd: fd.write(u"content") os.chmod(src_filename, stat.S_IREAD) with open(dst_filename, mode='w') as fd: fd.write(u"content") copymode(src_filename, dst_filename) actual = os.stat(dst_filename).st_mode assert stat.S_IMODE(actual) & stat.S_IWRITE == 0 os.chmod(src_filename, stat.S_IWRITE) # Needed when running on Windows as os.remove will fail to remove. os.remove(src_filename) with open(src_filename, mode='w') as fd: fd.write(u"content") copymode(src_filename, dst_filename) actual = os.stat(dst_filename).st_mode assert stat.S_IMODE(actual) & stat.S_IWRITE == stat.S_IWRITE @pytest.mark.skipif(os.name == 'nt', reason="Windows and local symlinks fall flat with local paths.") def test_copymode_local_to_local_symlink_follow(tmpdir): test_dir = tmpdir.mkdir('test') src_filename = "%s\\source.txt" % test_dir dst_filename = "%s\\target.txt" % test_dir with open(src_filename, mode='w') as fd: fd.write(u"content") os.chmod(src_filename, stat.S_IREAD) with open(dst_filename, mode='w') as fd: fd.write(u"content") src_link = "%s\\source-link.txt" % test_dir dst_link = "%s\\target-link.txt" % test_dir os.symlink(src_filename, src_link) os.symlink(dst_filename, dst_link) copymode(src_link, dst_link) actual_file = os.stat(dst_filename).st_mode assert stat.S_IMODE(actual_file) & stat.S_IWRITE == 0 actual_link = os.lstat(dst_link).st_mode assert stat.S_IMODE(actual_link) & stat.S_IWRITE == stat.S_IWRITE os.chmod(src_filename, stat.S_IWRITE) # Needed when running on Windows as os.remove will fail to remove. os.remove(src_filename) with open(src_filename, mode='w') as fd: fd.write(u"content") copymode(src_link, dst_link) actual_file = os.stat(dst_filename).st_mode assert stat.S_IMODE(actual_file) & stat.S_IWRITE == stat.S_IWRITE actual_link = os.lstat(dst_link).st_mode assert stat.S_IMODE(actual_link) & stat.S_IWRITE == stat.S_IWRITE @pytest.mark.skipif((os.name == 'nt' and sys.version_info[0] < 3) or (sys.version_info[0] == 3 and sys.version_info[1] == 5), reason="Python 3.5 errors out on os.chmod(follow_symlinks=False)") def test_copymode_local_to_local_symlink_dont_follow(tmpdir): test_dir = tmpdir.mkdir('test') src_filename = "%s\\source.txt" % test_dir dst_filename = "%s\\target.txt" % test_dir with open(src_filename, mode='w') as fd: fd.write(u"content") os.chmod(src_filename, stat.S_IREAD) with open(dst_filename, mode='w') as fd: fd.write(u"content") src_link = "%s\\source-link.txt" % test_dir dst_link = "%s\\target-link.txt" % test_dir os.symlink(src_filename, src_link) os.symlink(dst_filename, dst_link) expected = "chmod: follow_symlinks unavailable on this platform" with pytest.raises(NotImplementedError, match=re.escape(expected)): copymode(src_link, dst_link, follow_symlinks=False) def test_copymode_missing_src(smb_share): with pytest.raises(OSError): copymode("%s\\missing.txt", smb_share) def test_copymode_missing_dst(smb_share): with pytest.raises(OSError): copymode(smb_share, "%s\\missing.txt" % smb_share) @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_copymode_symlink_follow(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"content") with open_file(dst_filename, mode='w') as fd: fd.write(u"content") src_link = "%s\\source-link.txt" % smb_share dst_link = "%s\\target-link.txt" % smb_share symlink(src_filename, src_link) symlink(dst_filename, dst_link) copymode(src_link, dst_link) actual_file = smbclient_stat(dst_link).st_file_attributes assert actual_file & FileAttributes.FILE_ATTRIBUTE_READONLY == FileAttributes.FILE_ATTRIBUTE_READONLY actual_link = smbclient_stat(dst_link, follow_symlinks=False).st_file_attributes assert actual_link & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 remove(src_filename) with open_file(src_filename, mode='w') as fd: fd.write(u"content") copymode(src_link, dst_link) actual_file = smbclient_stat(dst_link).st_file_attributes assert actual_file & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 actual_link = smbclient_stat(dst_link, follow_symlinks=False).st_file_attributes assert actual_link & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_copymode_symlink_dont_follow(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w') as fd: fd.write(u"content") with open_file(dst_filename, mode='w') as fd: fd.write(u"content") src_link = "%s\\source-link.txt" % smb_share dst_link = "%s\\target-link.txt" % smb_share symlink(src_filename, src_link) symlink(dst_filename, dst_link) copymode(src_link, dst_link, follow_symlinks=False) actual_file = smbclient_stat(dst_filename).st_file_attributes assert actual_file & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 actual_link = smbclient_stat(dst_link, follow_symlinks=False).st_file_attributes assert actual_link & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 remove(src_filename) _set_file_attributes(src_link, FileAttributes.FILE_ATTRIBUTE_READONLY) copymode(src_link, dst_link, follow_symlinks=False) actual_file = smbclient_stat(dst_link).st_file_attributes assert actual_file & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 actual_link = smbclient_stat(dst_link, follow_symlinks=False).st_file_attributes assert actual_link & FileAttributes.FILE_ATTRIBUTE_READONLY == FileAttributes.FILE_ATTRIBUTE_READONLY @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="Samba does not update timestamps") def test_copystat_of_file(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"content") utime(src_filename, (1024, 1024)) with open_file(dst_filename, mode='w') as fd: fd.write(u"content") copystat(src_filename, dst_filename) actual = smbclient_stat(dst_filename) assert actual.st_atime == 1024 assert actual.st_mtime == 1024 assert actual.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == FileAttributes.FILE_ATTRIBUTE_READONLY @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="Samba does not update timestamps") def test_copystat_of_dir(smb_share): src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\target" % smb_share with open_file(src_dirname, mode='xb', file_type='dir', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY, buffering=0): pass utime(src_dirname, (-1024, -1024)) # Test out dates earlier than EPOCH. mkdir(dst_dirname) copystat(src_dirname, dst_dirname) actual = smbclient_stat(dst_dirname) assert actual.st_atime == -1024 assert actual.st_mtime == -1024 assert actual.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == FileAttributes.FILE_ATTRIBUTE_READONLY @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="Samba does not update timestamps") def test_copystat_local_to_remote(smb_share, tmpdir): test_dir = tmpdir.mkdir("test") src_filename = "%s\\source.txt" % test_dir dst_filename = "%s\\target.txt" % smb_share with open(src_filename, mode='w') as fd: fd.write(u"content") os.chmod(src_filename, stat.S_IREAD) os.utime(src_filename, (1024, 1024)) with open_file(dst_filename, mode='w') as fd: fd.write(u"content") copystat(src_filename, dst_filename) actual = smbclient_stat(dst_filename) assert actual.st_atime == 1024 assert actual.st_mtime == 1024 assert actual.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == FileAttributes.FILE_ATTRIBUTE_READONLY @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="Samba does not update timestamps") def test_copystat_remote_to_local(smb_share, tmpdir): test_dir = tmpdir.mkdir("test") src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % test_dir with open_file(src_filename, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"content") utime(src_filename, times=(1024, 1024)) with open(dst_filename, mode='w') as fd: fd.write(u"content") copystat(src_filename, dst_filename) actual = os.stat(dst_filename) assert actual.st_atime == 1024 assert actual.st_mtime == 1024 assert stat.S_IMODE(actual.st_mode) & stat.S_IWRITE == 0 def test_copystat_local_to_local(tmpdir): test_dir = tmpdir.mkdir("test") src_filename = "%s\\source.txt" % test_dir dst_filename = "%s\\target.txt" % test_dir with open(src_filename, mode='w') as fd: fd.write(u"content") os.chmod(src_filename, stat.S_IREAD) os.utime(src_filename, (1024, 1024)) with open(dst_filename, mode='w') as fd: fd.write(u"content") copystat(src_filename, dst_filename) actual = os.stat(dst_filename) assert actual.st_atime == 1024 assert actual.st_mtime == 1024 assert stat.S_IMODE(actual.st_mode) & stat.S_IWRITE == 0 @pytest.mark.skipif(os.name == 'nt', reason="Windows and local symlinks fall flat with local paths.") def test_copystat_local_to_local_symlink_follow(tmpdir): test_dir = tmpdir.mkdir('test') src_filename = "%s\\source.txt" % test_dir dst_filename = "%s\\target.txt" % test_dir with open(src_filename, mode='w') as fd: fd.write(u"content") os.chmod(src_filename, stat.S_IREAD) os.utime(src_filename, (1024, 1024)) with open(dst_filename, mode='w') as fd: fd.write(u"content") src_link = "%s\\source-link.txt" % test_dir dst_link = "%s\\target-link.txt" % test_dir os.symlink(src_filename, src_link) os.symlink(dst_filename, dst_link) copystat(src_link, dst_link) actual_file = os.stat(dst_filename) assert actual_file.st_atime == 1024 assert actual_file.st_mtime == 1024 assert stat.S_IMODE(actual_file.st_mode) & stat.S_IWRITE == 0 actual_link = os.lstat(dst_link) assert actual_link.st_atime != 1024 assert actual_link.st_mtime != 1024 assert stat.S_IMODE(actual_link.st_mode) & stat.S_IWRITE == stat.S_IWRITE @pytest.mark.skipif((os.name == 'nt' and sys.version_info[0] < 3) or (sys.version_info[0] == 3 and sys.version_info[1] == 5), reason="Python 3.5 errors out on os.chmod(follow_symlinks=False)") def test_copystat_local_to_local_symlink_dont_follow_fail(tmpdir): test_dir = tmpdir.mkdir('test') src_filename = "%s\\source.txt" % test_dir dst_filename = "%s\\target.txt" % test_dir with open(src_filename, mode='w') as fd: fd.write(u"content") os.chmod(src_filename, stat.S_IREAD) with open(dst_filename, mode='w') as fd: fd.write(u"content") src_link = "%s\\source-link.txt" % test_dir dst_link = "%s\\target-link.txt" % test_dir os.symlink(src_filename, src_link) os.symlink(dst_filename, dst_link) expected = "follow_symlinks unavailable on this platform" with pytest.raises(NotImplementedError, match=re.escape(expected)): copystat(src_link, dst_link, follow_symlinks=False) @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_copystat_symlink_follow(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"content") utime(src_filename, times=(1024, 1024)) with open_file(dst_filename, mode='w') as fd: fd.write(u"content") src_link = "%s\\source-link.txt" % smb_share dst_link = "%s\\target-link.txt" % smb_share symlink(src_filename, src_link) symlink(dst_filename, dst_link) copystat(src_link, dst_link) actual_file = smbclient_stat(dst_link) assert actual_file.st_atime == 1024 assert actual_file.st_mtime == 1024 assert actual_file.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == \ FileAttributes.FILE_ATTRIBUTE_READONLY actual_link = smbclient_stat(dst_link, follow_symlinks=False) assert actual_link.st_atime != 1024 assert actual_link.st_mtime != 1024 assert actual_link.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_copystat_symlink_dont_follow(smb_share): src_filename = "%s\\source.txt" % smb_share dst_filename = "%s\\target.txt" % smb_share with open_file(src_filename, mode='w') as fd: fd.write(u"content") with open_file(dst_filename, mode='w') as fd: fd.write(u"content") src_link = "%s\\source-link.txt" % smb_share dst_link = "%s\\target-link.txt" % smb_share symlink(src_filename, src_link) symlink(dst_filename, dst_link) _set_file_attributes(src_link, FileAttributes.FILE_ATTRIBUTE_READONLY) utime(src_link, times=(1024, 1024), follow_symlinks=False) copystat(src_link, dst_link, follow_symlinks=False) actual_file = smbclient_stat(dst_link) assert actual_file.st_atime != 1024 assert actual_file.st_mtime != 1024 assert actual_file.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 actual_link = smbclient_stat(dst_link, follow_symlinks=False) assert actual_link.st_atime == 1024 assert actual_link.st_mtime == 1024 assert actual_link.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == \ FileAttributes.FILE_ATTRIBUTE_READONLY def test_copystat_missing_src(smb_share): with pytest.raises(OSError): copystat("%s\\missing.txt", smb_share) def test_copystat_missing_dst(smb_share): with pytest.raises(OSError): copystat(smb_share, "%s\\missing.txt" % smb_share) def test_copytree_missing_src_fail(smb_share): expected = "[NtStatus 0xc0000034] No such file or directory: " with pytest.raises(OSError, match=re.escape(expected)): copytree("%s\\missing" % smb_share, smb_share) def test_copytree_missing_dst(smb_share): src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\sub-folder\\target" % smb_share makedirs("%s\\dir1\\subdir1\\subdir2" % src_dirname) _set_file_attributes("%s\\dir1\\subdir1" % src_dirname, FileAttributes.FILE_ATTRIBUTE_READONLY) utime("%s\\dir1\\subdir1\\subdir2" % src_dirname, times=(1024, 1024)) with open_file("%s\\file1.txt" % src_dirname, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"file1.txt") with open_file("%s\\dir1\\file2.txt" % src_dirname, mode='w') as fd: fd.write(u"file2.txt") utime("%s\\dir1\\file2.txt" % src_dirname, times=(1024, 1024)) with open_file("%s\\dir1\\subdir1\\file3.txt" % src_dirname, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"file3.txt") actual = copytree(src_dirname, dst_dirname) assert actual == dst_dirname assert sorted(list(listdir(dst_dirname))) == ["dir1", "file1.txt"] assert sorted(list(listdir("%s\\dir1" % dst_dirname))) == ["file2.txt", "subdir1"] assert sorted(list(listdir("%s\\dir1\\subdir1" % dst_dirname))) == ["file3.txt", "subdir2"] assert sorted(list(listdir("%s\\dir1\\subdir1\\subdir2" % dst_dirname))) == [] with open_file("%s\\file1.txt" % dst_dirname) as fd: assert fd.read() == u"file1.txt" with open_file("%s\\dir1\\file2.txt" % dst_dirname) as fd: assert fd.read() == u"file2.txt" with open_file("%s\\dir1\\subdir1\\file3.txt" % dst_dirname) as fd: assert fd.read() == u"file3.txt" file1_stat = smbclient_stat("%s\\file1.txt" % dst_dirname) assert file1_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == \ FileAttributes.FILE_ATTRIBUTE_READONLY file2_stat = smbclient_stat("%s\\dir1\\file2.txt" % dst_dirname) assert file2_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 file3_stat = smbclient_stat("%s\\dir1\\subdir1\\file3.txt" % dst_dirname) assert file3_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == \ FileAttributes.FILE_ATTRIBUTE_READONLY dir1_stat = smbclient_stat("%s\\dir1" % dst_dirname) assert dir1_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 subdir1_stat = smbclient_stat("%s\\dir1\\subdir1" % dst_dirname) assert subdir1_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == \ FileAttributes.FILE_ATTRIBUTE_READONLY subdir2_stat = smbclient_stat("%s\\dir1\\subdir1\\subdir2" % dst_dirname) assert subdir2_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 # Samba server's cannot set the datetime so only run this if the server is supported. if os.name == 'nt' or os.environ.get('SMB_FORCE', False): assert file1_stat.st_atime != 1024 assert file1_stat.st_mtime != 1024 assert file2_stat.st_atime == 1024 assert file2_stat.st_mtime == 1024 assert file3_stat.st_atime != 1024 assert file3_stat.st_mtime != 1024 assert dir1_stat.st_atime != 1024 assert dir1_stat.st_mtime != 1024 assert subdir1_stat.st_atime != 1024 assert subdir1_stat.st_mtime != 1024 assert subdir2_stat.st_atime == 1024 assert subdir2_stat.st_mtime == 1024 def test_copytree_existing_dst_fail(smb_share): src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\target" % smb_share mkdir(src_dirname) mkdir(dst_dirname) expected = "[NtStatus 0xc0000035] File exists: " with pytest.raises(OSError, match=re.escape(expected)): copytree(src_dirname, dst_dirname) def test_copytree_existing_dst_ignore(smb_share): src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\target" % smb_share mkdir(src_dirname) with open_file("%s\\file1.txt" % src_dirname, mode='w') as fd: fd.write(u"file1.txt") with open_file("%s\\file2.txt" % src_dirname, mode='w') as fd: fd.write(u"file2.txt") with open_file("%s\\file3.txt" % src_dirname, mode='w') as fd: fd.write(u"file3.txt") actual = copytree(src_dirname, dst_dirname) assert actual == dst_dirname _set_file_attributes("%s\\file1.txt" % src_dirname, FileAttributes.FILE_ATTRIBUTE_NORMAL) remove("%s\\file2.txt" % dst_dirname) _set_file_attributes("%s\\file3.txt" % src_dirname, FileAttributes.FILE_ATTRIBUTE_READONLY) actual = copytree(src_dirname, dst_dirname, dirs_exist_ok=True) assert actual == dst_dirname file1_stat = smbclient_stat("%s\\file1.txt" % dst_dirname) assert file1_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 file2_stat = smbclient_stat("%s\\file2.txt" % dst_dirname) assert file2_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 file3_stat = smbclient_stat("%s\\file3.txt" % dst_dirname) assert file3_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == \ FileAttributes.FILE_ATTRIBUTE_READONLY def test_copytree_with_ignore(smb_share): def ignore(name, children): if name.endswith(u'source'): assert sorted(children) == ['dir1', 'file1.txt'] return ['file1.txt'] elif name.endswith(u'subdir1'): assert sorted(children) == ['file3.txt', 'subdir2'] return ['subdir2'] else: assert sorted(children) == ['file2.txt', 'subdir1'] return [] src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\target" % smb_share makedirs("%s\\dir1\\subdir1\\subdir2" % src_dirname) with open_file("%s\\file1.txt" % src_dirname, mode='w') as fd: fd.write(u"file1.txt") with open_file("%s\\dir1\\file2.txt" % src_dirname, mode='w') as fd: fd.write(u"file2.txt") with open_file("%s\\dir1\\subdir1\\file3.txt" % src_dirname, mode='w') as fd: fd.write(u"file3.txt") actual = copytree(src_dirname, dst_dirname, ignore=ignore) assert actual == dst_dirname assert sorted(list(listdir(dst_dirname))) == ["dir1"] assert sorted(list(listdir("%s\\dir1" % dst_dirname))) == ["file2.txt", "subdir1"] assert sorted(list(listdir("%s\\dir1\\subdir1" % dst_dirname))) == ["file3.txt"] with open_file("%s\\dir1\\file2.txt" % dst_dirname) as fd: assert fd.read() == u"file2.txt" with open_file("%s\\dir1\\subdir1\\file3.txt" % dst_dirname) as fd: assert fd.read() == u"file3.txt" @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="Samba does not update timestamps") def test_copytree_with_copy(smb_share): src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\sub-folder\\target" % smb_share makedirs("%s\\dir1\\subdir1\\subdir2" % src_dirname) _set_file_attributes("%s\\dir1\\subdir1" % src_dirname, FileAttributes.FILE_ATTRIBUTE_READONLY) utime("%s\\dir1\\subdir1\\subdir2" % src_dirname, times=(1024, 1024)) with open_file("%s\\file1.txt" % src_dirname, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"file1.txt") with open_file("%s\\dir1\\file2.txt" % src_dirname, mode='w') as fd: fd.write(u"file2.txt") utime("%s\\dir1\\file2.txt" % src_dirname, times=(1024, 1024)) with open_file("%s\\dir1\\subdir1\\file3.txt" % src_dirname, mode='w', file_attributes=FileAttributes.FILE_ATTRIBUTE_READONLY) as fd: fd.write(u"file3.txt") actual = copytree(src_dirname, dst_dirname, copy_function=copy) assert actual == dst_dirname assert sorted(list(listdir(dst_dirname))) == ["dir1", "file1.txt"] assert sorted(list(listdir("%s\\dir1" % dst_dirname))) == ["file2.txt", "subdir1"] assert sorted(list(listdir("%s\\dir1\\subdir1" % dst_dirname))) == ["file3.txt", "subdir2"] assert sorted(list(listdir("%s\\dir1\\subdir1\\subdir2" % dst_dirname))) == [] with open_file("%s\\file1.txt" % dst_dirname) as fd: assert fd.read() == u"file1.txt" with open_file("%s\\dir1\\file2.txt" % dst_dirname) as fd: assert fd.read() == u"file2.txt" with open_file("%s\\dir1\\subdir1\\file3.txt" % dst_dirname) as fd: assert fd.read() == u"file3.txt" file1_stat = smbclient_stat("%s\\file1.txt" % dst_dirname) assert file1_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == \ FileAttributes.FILE_ATTRIBUTE_READONLY assert file1_stat.st_atime != 1024 assert file1_stat.st_mtime != 1024 file2_stat = smbclient_stat("%s\\dir1\\file2.txt" % dst_dirname) assert file2_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 assert file2_stat.st_atime != 1024 assert file2_stat.st_mtime != 1024 file3_stat = smbclient_stat("%s\\dir1\\subdir1\\file3.txt" % dst_dirname) assert file3_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == \ FileAttributes.FILE_ATTRIBUTE_READONLY assert file3_stat.st_atime != 1024 assert file3_stat.st_mtime != 1024 dir1_stat = smbclient_stat("%s\\dir1" % dst_dirname) assert dir1_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 assert dir1_stat.st_atime != 1024 assert dir1_stat.st_mtime != 1024 subdir1_stat = smbclient_stat("%s\\dir1\\subdir1" % dst_dirname) assert subdir1_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == \ FileAttributes.FILE_ATTRIBUTE_READONLY assert subdir1_stat.st_atime != 1024 assert subdir1_stat.st_mtime != 1024 subdir2_stat = smbclient_stat("%s\\dir1\\subdir1\\subdir2" % dst_dirname) assert subdir2_stat.st_file_attributes & FileAttributes.FILE_ATTRIBUTE_READONLY == 0 # While files are copied with copy(), the directories are still copied with copystat() assert subdir2_stat.st_atime == 1024 assert subdir2_stat.st_mtime == 1024 def test_copytree_with_errors_raises(smb_share): src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\target" % smb_share makedirs("%s\\dir1" % src_dirname) with open_file("%s\\file1.txt" % src_dirname, mode='w') as fd: fd.write(u"file1.txt") with open_file("%s\\dir1\\file2.txt" % src_dirname, mode='w') as fd: fd.write(u"file2.txt") actual = copytree(src_dirname, dst_dirname) assert actual == dst_dirname # Doing this will force a failure as we cannot run copyfile against a target with this flag (access is denied). _set_file_attributes("%s\\file1.txt" % dst_dirname, FileAttributes.FILE_ATTRIBUTE_READONLY) _set_file_attributes("%s\\dir1\\file2.txt" % dst_dirname, FileAttributes.FILE_ATTRIBUTE_READONLY) with pytest.raises(shutil.Error) as actual: copytree(src_dirname, dst_dirname, dirs_exist_ok=True) assert len(actual.value.args[0]) == 2 err1 = actual.value.args[0][0] assert err1[0] == "%s\\dir1\\file2.txt" % src_dirname assert err1[1] == "%s\\dir1\\file2.txt" % dst_dirname assert "STATUS_ACCESS_DENIED" in err1[2] err2 = actual.value.args[0][1] assert err2[0] == "%s\\file1.txt" % src_dirname assert err2[1] == "%s\\file1.txt" % dst_dirname assert "STATUS_ACCESS_DENIED" in err2[2] @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_copytree_with_symlink_and_not_flag(smb_share): src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\target" % smb_share makedirs("%s\\dir" % src_dirname) symlink("%s\\dir" % src_dirname, "%s\\link" % src_dirname) with open_file("%s\\file.txt" % src_dirname, mode='w') as fd: fd.write(u"1") symlink("%s\\file.txt" % src_dirname, "%s\\link.txt" % src_dirname) with open_file("%s\\dir\\file.txt" % src_dirname, mode='w') as fd: fd.write(u"2") actual = copytree(src_dirname, dst_dirname) assert actual == dst_dirname assert not islink("%s\\link.txt" % dst_dirname) with open_file("%s\\link.txt" % dst_dirname) as fd: assert fd.read() == u"1" assert not samefile("%s\\link.txt" % dst_dirname, "%s\\file.txt" % src_dirname) assert not samefile("%s\\link.txt" % dst_dirname, "%s\\file.txt" % dst_dirname) assert not islink("%s\\link" % dst_dirname) with open_file("%s\\link\\file.txt" % dst_dirname) as fd: assert fd.read() == u"2" assert not samefile("%s\\link\\file.txt" % dst_dirname, "%s\\dir\\file.txt" % src_dirname) assert not samefile("%s\\link\\file.txt" % dst_dirname, "%s\\dir\\file.txt" % dst_dirname) @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_copytree_with_symlink_and_flag(smb_share): src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\target" % smb_share makedirs("%s\\dir" % src_dirname) symlink("%s\\dir" % src_dirname, "%s\\link" % src_dirname) with open_file("%s\\file.txt" % src_dirname, mode='w') as fd: fd.write(u"content") symlink("%s\\file.txt" % src_dirname, "%s\\link.txt" % src_dirname) with open_file("%s\\dir\\file.txt" % src_dirname, mode='w') as fd: fd.write(u"content") actual = copytree(src_dirname, dst_dirname, symlinks=True) assert actual == dst_dirname assert islink("%s\\link" % dst_dirname) assert ntpath.normpath(readlink("%s\\link" % dst_dirname)) == ntpath.normpath("%s\\dir" % src_dirname) assert samefile("%s\\link\\file.txt" % dst_dirname, "%s\\dir\\file.txt" % src_dirname) assert not samefile("%s\\link\\file.txt" % dst_dirname, "%s\\dir\\file.txt" % dst_dirname) assert islink("%s\\link.txt" % dst_dirname) assert ntpath.normpath(readlink("%s\\link.txt" % dst_dirname)) == ntpath.normpath("%s\\file.txt" % src_dirname) assert samefile("%s\\link.txt" % dst_dirname, "%s\\file.txt" % src_dirname) assert not samefile("%s\\link.txt" % dst_dirname, "%s\\file.txt" % dst_dirname) @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_copytree_with_broken_symlink_fail(smb_share): src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\target" % smb_share mkdir(src_dirname) symlink("%s\\dir" % src_dirname, "%s\\link" % src_dirname, target_is_directory=True) symlink("%s\\file.txt" % src_dirname, "%s\\link.txt" % src_dirname) with pytest.raises(shutil.Error) as actual: copytree(src_dirname, dst_dirname) assert len(actual.value.args[0]) == 2 err1 = actual.value.args[0][0] err2 = actual.value.args[0][1] assert err1[0] == "%s\\link" % src_dirname assert err1[1] == "%s\\link" % dst_dirname assert "No such file or directory" in err1[2] assert err2[0] == "%s\\link.txt" % src_dirname assert err2[1] == "%s\\link.txt" % dst_dirname assert "No such file or directory" in err2[2] @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_copytree_with_broken_symlink_ignore(smb_share): src_dirname = "%s\\source" % smb_share dst_dirname = "%s\\target" % smb_share makedirs("%s\\other-dir" % src_dirname) symlink("%s\\dir" % src_dirname, "%s\\link" % src_dirname, target_is_directory=True) symlink("%s\\file.txt" % src_dirname, "%s\\link.txt" % src_dirname) actual = copytree(src_dirname, dst_dirname, ignore_dangling_symlinks=True) assert actual == dst_dirname assert listdir(dst_dirname) == ["other-dir"] def test_rmtree(smb_share): mkdir("%s\\dir2" % smb_share) mkdir("%s\\dir2\\dir3" % smb_share) with open_file("%s\\dir2\\dir3\\file1" % smb_share, mode='w') as fd: fd.write(u"content") with open_file("%s\\dir2\\file2" % smb_share, mode='w') as fd: fd.write(u"content") if os.name == "nt" or os.environ.get('SMB_FORCE', False): # File symlink symlink("%s\\dir2\\file2" % smb_share, "%s\\dir2\\file3" % smb_share) symlink("missing", "%s\\dir2\\file3-broken" % smb_share) # Dir symlink symlink("%s\\dir2\\dir3" % smb_share, "%s\\dir2\\dir-link" % smb_share) symlink("missing", "%s\\dir2\\dir-link-broken" % smb_share, target_is_directory=True) assert exists("%s\\dir2" % smb_share) is True rmtree("%s\\dir2" % smb_share) assert exists("%s\\dir2" % smb_share) is False def test_rmtree_non_existing(smb_share): dir_name = "%s\\dir2" % smb_share expected = "[NtStatus 0xc0000034] No such file or directory: " with pytest.raises(OSError, match=re.escape(expected)): rmtree(dir_name) rmtree(dir_name, ignore_errors=True) callback_args = [] def callback(*args): callback_args.append(args) rmtree(dir_name, onerror=callback) assert len(callback_args) == 2 assert callback_args[0][0].__name__ == 'scandir' assert callback_args[0][1] == dir_name assert isinstance(callback_args[0][2][1], SMBOSError) assert callback_args[1][0].__name__ == 'rmdir' assert callback_args[1][1] == dir_name assert isinstance(callback_args[1][2][1], SMBOSError) def test_rmtree_as_file(smb_share): filename = "%s\\file.txt" % smb_share with open_file(filename, mode='w') as fd: fd.write(u"content") expected = "[NtStatus 0xc0000103] Not a directory: " with pytest.raises(OSError, match=re.escape(expected)): rmtree(filename) rmtree(filename, ignore_errors=True) callback_args = [] def callback(*args): callback_args.append(args) rmtree(filename, onerror=callback) assert len(callback_args) == 2 assert callback_args[0][0].__name__ == 'scandir' assert callback_args[0][1] == filename assert isinstance(callback_args[0][2][1], SMBOSError) assert callback_args[1][0].__name__ == 'rmdir' assert callback_args[1][1] == filename assert isinstance(callback_args[1][2][1], SMBOSError) @pytest.mark.skipif(os.name != "nt" and not os.environ.get('SMB_FORCE', False), reason="cannot create symlinks on Samba") def test_rmtree_symlink_as_dir(smb_share): src_dirname = "%s\\dir" % smb_share dst_dirname = "%s\\target" % smb_share mkdir(src_dirname) symlink("dir", dst_dirname) expected = "Cannot call rmtree on a symbolic link" with pytest.raises(OSError, match=re.escape(expected)): rmtree(dst_dirname) assert exists(src_dirname) assert exists(dst_dirname) rmtree(dst_dirname, ignore_errors=True) callback_args = [] def callback(*args): callback_args.append(args) rmtree(dst_dirname, onerror=callback) assert len(callback_args) == 1 assert callback_args[0][0].__name__ == 'islink' assert callback_args[0][1] == dst_dirname assert isinstance(callback_args[0][2][1], OSError)