@Override
    public AttributedList<Path> search(final Path workdir, final Filter<Path> regex, final ListProgressListener listener) throws BackgroundException {
        if(workdir.isRoot()) {
            if(StringUtils.isEmpty(RequestEntityRestStorageService.findBucketInHostname(session.getHost()))) {
                final AttributedList<Path> result = new AttributedList<>();
                final AttributedList<Path> buckets = new S3BucketListService(session).list(workdir, listener);
                for(Path bucket : buckets) {
                    result.addAll(filter(regex, new S3ObjectListService(session, acl).list(bucket, listener, null)));
                }
                result.addAll(filter(regex, buckets));
                return result;
            }
        }
        try {
            return filter(regex, new S3ObjectListService(session, acl).list(workdir, listener, null));
        }
        catch(NotfoundException e) {
            return AttributedList.emptyList();
        }
    }
@Test
    public void testSearchInDirectory() throws Exception {
        final Path bucket = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
        final S3AccessControlListFeature acl = new S3AccessControlListFeature(session);
        final String name = new AlphanumericRandomStringService().random();
        final Path file = new Path(bucket, name, EnumSet.of(Path.Type.file));
        session.getFeature(Touch.class).touch(file, new TransferStatus());
        final S3SearchFeature feature = new S3SearchFeature(session, acl);
        assertTrue(feature.search(bucket, new SearchFilter(name), new DisabledListProgressListener()).contains(file));
        assertTrue(feature.search(bucket, new SearchFilter(StringUtils.upperCase(name)), new DisabledListProgressListener()).contains(file));
        assertTrue(feature.search(bucket, new SearchFilter(StringUtils.substring(name, 2)), new DisabledListProgressListener()).contains(file));
        // Glob pattern
        assertTrue(feature.search(bucket, new SearchFilter(String.format("*%s", StringUtils.substring(name, 2))), new DisabledListProgressListener()).contains(file));
        {
            final AttributedList<Path> result = feature.search(bucket, new SearchFilter(StringUtils.substring(name, 0, name.length() - 2)), new DisabledListProgressListener());
            assertTrue(result.contains(file));
        }
        assertFalse(feature.search(new Path(bucket, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new SearchFilter(name), new DisabledListProgressListener()).contains(file));
        final Path subdir = new S3DirectoryFeature(session, new S3WriteFeature(session, acl), acl).mkdir(new Path(bucket, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
        assertTrue(feature.search(bucket, new SearchFilter(new AlphanumericRandomStringService().random()), new DisabledListProgressListener()).isEmpty());
        assertFalse(feature.search(subdir, new SearchFilter(name), new DisabledListProgressListener()).contains(file));
        final Path filesubdir = new S3TouchFeature(session, acl).touch(new Path(subdir, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
        {
            final AttributedList<Path> result = feature.search(bucket, new SearchFilter(filesubdir.getName()), new DisabledListProgressListener());
            assertNotNull(result.find(new SimplePathPredicate(filesubdir)));
            assertEquals(subdir, result.find(new SimplePathPredicate(filesubdir)).getParent());
        }
        {
            final AttributedList<Path> result = feature.search(subdir, new SearchFilter(filesubdir.getName()), new DisabledListProgressListener());
            assertNotNull(result.find(new SimplePathPredicate(filesubdir)));
            assertEquals(subdir, result.find(new SimplePathPredicate(filesubdir)).getParent());
        }
        new S3DefaultDeleteFeature(session).delete(Arrays.asList(file, filesubdir, subdir), new DisabledLoginCallback(), new Delete.DisabledCallback());
    }