@Override
    public AttributedList<Path> search(final Path workdir, final Filter<Path> regex, final ListProgressListener listener) throws BackgroundException {
        try {
            final AttributedList<Path> list = new AttributedList<>();
            String prefix = null;
            final AttributedList<Path> containers;
            if(workdir.isRoot()) {
                containers = new B2BucketListService(session, fileid).list(new Path(String.valueOf(Path.DELIMITER), EnumSet.of(Path.Type.volume, Path.Type.directory)), listener);
            }
            else {
                containers = new AttributedList<>(Collections.singletonList(containerService.getContainer(workdir)));
                if(!containerService.isContainer(workdir)) {
                    prefix = containerService.getKey(workdir) + Path.DELIMITER;
                }
            }
            for(Path container : containers) {
                String startFilename = prefix;
                do {
                    final B2ListFilesResponse response = session.getClient().listFileNames(
                            fileid.getVersionId(container),
                            startFilename,
                            new HostPreferences(session.getHost()).getInteger("b2.listing.chunksize"),
                            prefix, null);
                    for(B2FileInfoResponse info : response.getFiles()) {
                        final Path f = new Path(String.format("%s%s%s", container.getAbsolute(), Path.DELIMITER, info.getFileName()), EnumSet.of(Path.Type.file));
                        if(regex.accept(f)) {
                            list.add(f.withAttributes(new B2AttributesFinderFeature(session, fileid).toAttributes(info)));
                        }
                    }
                    startFilename = response.getNextFileName();
                }
                while(startFilename != null);
            }
            return list;
        }
        catch(B2ApiException e) {
            throw new B2ExceptionMappingService(fileid).map(e);
        }
        catch(IOException e) {
            throw new DefaultIOExceptionMappingService().map(e);
        }
    }
@Test
    public void testSearchInBucket() throws Exception {
        final String name = new AlphanumericRandomStringService().random();
        final Path bucket = new Path("test-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
        final B2VersionIdProvider fileid = new B2VersionIdProvider(session);
        final Path file = new B2TouchFeature(session, fileid).touch(new Path(bucket, name, EnumSet.of(Path.Type.file)), new TransferStatus());
        final B2SearchFeature feature = new B2SearchFeature(session, fileid);
        assertNotNull(feature.search(bucket, new SearchFilter(name), new DisabledListProgressListener()).find(new SimplePathPredicate(file)));
        assertNotNull(feature.search(bucket, new SearchFilter(StringUtils.upperCase(name)), new DisabledListProgressListener()).find(new SimplePathPredicate(file)));
        assertNotNull(feature.search(bucket, new SearchFilter(StringUtils.substring(name, 2)), new DisabledListProgressListener()).find(new SimplePathPredicate(file)));
        assertNotNull(feature.search(bucket, new SearchFilter(StringUtils.substring(name, 0, name.length() - 2)), new DisabledListProgressListener()).find(new SimplePathPredicate(file)));
        final Path subdir = new Path(bucket, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
        assertNull(feature.search(subdir, new SearchFilter(name), new DisabledListProgressListener()).find(new SimplePathPredicate(file)));
        new B2DeleteFeature(session, fileid).delete(Collections.singletonList(file), new DisabledLoginCallback(), new Delete.DisabledCallback());
    }