@Override
    public Path copy(final Path source, final Path target, final TransferStatus status,
                     final ConnectionCallback prompt, final StreamListener listener) throws BackgroundException {
        final SMBSession.DiskShareWrapper share = session.openShare(source);
        try {
            try (final File sourceFile = share.get().openFile(new SMBPathContainerService(session).getKey(source),
                    new HashSet<>(Arrays.asList(AccessMask.FILE_READ_DATA, AccessMask.FILE_READ_ATTRIBUTES)),
                    Collections.singleton(FileAttributes.FILE_ATTRIBUTE_NORMAL),
                    Collections.singleton(SMB2ShareAccess.FILE_SHARE_READ),
                    SMB2CreateDisposition.FILE_OPEN,
                    Collections.singleton(SMB2CreateOptions.FILE_NON_DIRECTORY_FILE));
                 final File targetFile = share.get().openFile(new SMBPathContainerService(session).getKey(target),
                         Collections.singleton(AccessMask.MAXIMUM_ALLOWED),
                         Collections.singleton(FileAttributes.FILE_ATTRIBUTE_NORMAL),
                         Collections.singleton(SMB2ShareAccess.FILE_SHARE_READ),
                         status.isExists() ? SMB2CreateDisposition.FILE_OVERWRITE : SMB2CreateDisposition.FILE_CREATE,
                         Collections.singleton(SMB2CreateOptions.FILE_NON_DIRECTORY_FILE))) {
                sourceFile.remoteCopyTo(targetFile);
            }
            listener.sent(status.getLength());
        }
        catch(IOException e) {
            throw new SMBTransportExceptionMappingService().map("Cannot copy {0}", e, source);
        }
        catch(SMBRuntimeException e) {
            throw new SMBExceptionMappingService().map("Cannot copy {0}", e, source);
        }
        catch(BufferException e) {
            throw new BackgroundException(e);
        }
        finally {
            session.releaseShare(share);
        }
        return target;
    }
@Test
    public void testCopyFile() throws Exception {
        final Path home = new DefaultHomeFinderService(session).find();
        final Path file = new SMBTouchFeature(session).touch(new Path(home,
                new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
        final PathAttributes attr = new SMBAttributesFinderFeature(session).find(file);
        final Path destinationFolder = new SMBDirectoryFeature(session).mkdir(
                new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
        final Path copy = new Path(destinationFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
        final Path fileCopied = new SMBCopyFeature(session).copy(file, copy, new TransferStatus(), new DisabledConnectionCallback(), new DisabledStreamListener());
        assertNotEquals(attr, new SMBAttributesFinderFeature(session).find(fileCopied));
        ListService list = new SMBListService(session);
        assertTrue(list.list(home, new DisabledListProgressListener()).contains(file));
        assertTrue(list.list(destinationFolder, new DisabledListProgressListener()).contains(copy));
        new SMBDeleteFeature(session).delete(Arrays.asList(file, copy, destinationFolder), new DisabledLoginCallback(), new Delete.DisabledCallback());
    }