@Override
		public FileWrapper[] run() throws Exception {
			final String bucket = this.step.getBucket();
			final String path = this.step.getPath();
			final String glob = this.step.getGlob();
			final boolean onlyFiles = this.step.isOnlyFiles();

			Preconditions.checkArgument(bucket != null && !bucket.isEmpty(), "Bucket must not be null or empty");

			this.getContext().get(TaskListener.class).getLogger().format("Searching s3://%s/%s for glob:'%s' %s%n", bucket, path, glob, onlyFiles ? "(only files)" : "");

			AmazonS3 s3Client = AWSClientFactory.create(Execution.this.step.createS3ClientOptions().createAmazonS3ClientBuilder(), Execution.this.getContext());

			// Construct a PatternMatcher to match the files.
			// Essentially, we're going to match against "${path}/${glob}".  Obviously,
			// if there's no path, then we're going to leave that part out.  If no glob
			// was given, then we're going to default to "*", which will match everything
			// at the level of the path (but no deeper).
			//
			// Note that a glob of "**" will match everything (both files and folders) under
			// the path.
			final String matcherString = computeMatcherString(path, glob);
			PathMatcher matcher = FileSystems.getDefault().getPathMatcher(matcherString);

			// This is how may components there are in the root path.  We'll use this information
			// to strip out these parts from the matches later on.
			//
			// For exmple, if `path` is "path/to", then this will be "2".
			final int pathComponentCount = path.length() == 0 ? 0 : Paths.get(path).getNameCount();

			// This is the list of S3 file information for all of the matching objects.
			List<FileWrapper> matchingObjects = new ArrayList<>();

			// This is the list of folders that we need to investigate.
			// We're going to start with the path that we've been given,
			// and then we'll grow it from there.
			List<String> folders = new ArrayList<>();
			folders.add(path);

			// Go through all of the folders that we need to investigate,
			// popping the first item off and working on it.  When they're
			// all gone, we'll be done.
			while (!folders.isEmpty()) {
				// This is the folder to investigate.
				String folder = folders.remove(0);

				// Create the request to list the objects within it.
				ListObjectsRequest request = new ListObjectsRequest();
				request.setBucketName(bucket);
				request.setPrefix(folder);
				request.setDelimiter("/");
				if (folder.length() > 0 && !folder.endsWith("/")) {
					request.setPrefix(folder + "/");
				}

				// Get the list of objects within the folder.  Because AWS
				// might paginate this, we're going to continue dealing with
				// the "objectListing" object until it claims that it's done.
				ObjectListing objectListing = s3Client.listObjects(request);
				while (true) {
					// Add any real objects to the list of objects to delete.
					for (S3ObjectSummary entry : objectListing.getObjectSummaries()) {
						// S3 does this sneaky thing with folders created in the management console:
						// It *actually* creates a zero-length file whose name ends in "/".
						//
						// Here, we're going to quietly skip those entries; they'll be handled normally
						// by the folder pathway below, anyway.  (Yes, they are returned as actual s3
						// entities as well as prefixes).
						if (entry.getKey().endsWith("/")) {
							continue;
						}

						Path javaPath = Paths.get(entry.getKey());
						if (matcher.matches(javaPath)) {
							FileWrapper file = createFileWrapperFromFile(pathComponentCount, javaPath, entry);
							matchingObjects.add(file);
						}
					}
					// Add any folders to the list of folders that we need to investigate.
					folders.addAll(objectListing.getCommonPrefixes());
					// In addition, if we are allowed to add folders to the list, then
					// go through the folders and add any matching ones.
					if (!onlyFiles) {
						for (String prefix : objectListing.getCommonPrefixes()) {
							Path javaPath = Paths.get(prefix);
							if (matcher.matches(javaPath)) {
								FileWrapper file = createFileWrapperFromFolder(pathComponentCount, javaPath);
								matchingObjects.add(file);
							}
						}
					}

					// If this listing is complete, then we can stop.
					if (!objectListing.isTruncated()) {
						break;
					}
					// Otherwise, we need to get the next batch and repeat.
					objectListing = s3Client.listNextBatchOfObjects(objectListing);
				}
			}

			FileWrapper[] stepResult = new FileWrapper[matchingObjects.size()];
			stepResult = matchingObjects.toArray(stepResult);

			this.getContext().get(TaskListener.class).getLogger().println("Search complete");
			return stepResult;
		}
This is whether or not we are only going to return files.
By default, both files and folders are returned.
src/main/java/de/taimos/pipeline/aws/S3FindFilesStep.java