def test_samefile_with_broken_symlink(smb_share): file1 = "%s\\file1.txt" % smb_share file2 = "%s\\file2.txt" % smb_share symlink(file1, file2) expected = "[NtStatus 0xc0000034] No such file or directory: " with pytest.raises(OSError, match=re.escape(expected)): samefile(file1, file2)
def test_samefile_missing_path2(smb_share): file1 = "%s\\file1.txt" % smb_share file2 = "%s\\file2.txt" % smb_share with open_file(file2, mode='w') as fd: fd.write(u"content") expected = "[NtStatus 0xc0000034] No such file or directory: " with pytest.raises(OSError, match=re.escape(expected)): samefile(file1, file2)
def test_samefile_with_symlink(smb_share): file1 = "%s\\file1.txt" % smb_share file2 = "%s\\file2.txt" % smb_share with open_file(file1, mode='w') as fd: fd.write(u"content") symlink(file1, file2) assert samefile(file1, file2) is True
def test_samefile_with_different_files(smb_share): file1 = "%s\\file1.txt" % smb_share file2 = "%s\\file2.txt" % smb_share with open_file(file1, mode='w') as fd: fd.write(u"content") with open_file(file2, mode='w') as fd: fd.write(u"content") assert samefile(file1, file2) is False
def copyfile(src, dst, follow_symlinks=True, **kwargs): """ Copy the contents (no metadata) of the file names src to a file named dst and return dst in the most efficient way possible. If the src and dst reside on the same UNC share then a more efficient remote side copy is used. If the src and dst reside on the same local path then the proper shutil.copyfile() method is called, otherwise the content is copied using copyfileobj() in chunks. dst must be the complete target file name; look at copy() for a copy that accepts a target directory path. If src dst specify the same file, ValueError is raised. The destination location must be writable; otherwise, an OSError exception will be raised. If dst already exists, it will be replaced. Special files such as character or block devices and pipes cannot be copied with this function. If follow_symlinks is 'False' and src is a symbolic link, a new symbolic link will be created instead of copying the file src points to. This will fail if the symbolic link at src is a different root as dst. :param src: The src filepath to copy. :param dst: The destinoation filepath to copy to. :param follow_symlinks: Whether to copy the symlink target of source or the symlink itself. :param kwargs: Common arguments used to build the SMB Session for any UNC paths. :return: The dst path. """ def wrap_not_implemented(function_name): def raise_not_implemented(*args, **kwargs): raise NotImplementedError( "%s is unavailable on this platform as a local operation" % function_name) return raise_not_implemented norm_src = ntpath.normpath(src) if norm_src.startswith('\\\\'): src_root = ntpath.splitdrive(norm_src)[0] islink_func = islink readlink_func = readlink symlink_func = symlink src_open = open_file src_kwargs = kwargs else: src_root = None islink_func = os.path.islink # readlink and symlink are not available on Windows on Python 2. readlink_func = getattr(os, 'readlink', wrap_not_implemented('readlink')) symlink_func = getattr(os, 'symlink', wrap_not_implemented('symlink')) src_open = open src_kwargs = {} norm_dst = ntpath.normpath(dst) if norm_dst.startswith('\\\\'): dst_root = ntpath.splitdrive(norm_dst)[0] dst_open = open_file dst_kwargs = kwargs else: dst_root = None dst_open = open dst_kwargs = {} if not follow_symlinks and islink_func(src, **src_kwargs): if src_root != dst_root: raise ValueError("Cannot copy a symlink on different roots.") symlink_func(readlink_func(src), dst, **src_kwargs) return dst if src_root is None and dst_root is None: # The files are local and follow_symlinks is True, rely on the builtin copyfile mechanism. shutil.copyfile(src, dst) return dst if src_root == dst_root: # The files are located on the same share and follow_symlinks is True, rely on smbclient.copyfile for an # efficient server side copy. try: is_same = samefile(src, dst, **kwargs) except OSError as err: if err.errno == errno.ENOENT: is_same = False else: raise if is_same: raise shutil.Error( to_native("'%s' and '%s' are the same file, cannot copy" % (src, dst))) smbclient_copyfile(src, dst, **kwargs) return dst # Finally we are copying across different roots so we just chunk the data using copyfileobj with src_open(src, mode='rb', **src_kwargs) as src_fd, dst_open(dst, mode='wb', **dst_kwargs) as dst_fd: copyfileobj(src_fd, dst_fd, MAX_PAYLOAD_SIZE) return dst