code: @Override
    public void close() throws IOException {
      if (open.compareAndSet(true, false)) {
        onClose.run();
  
        Throwable thrown = null;
        do {
          for (Closeable resource : resources) {
            try {
              resource.close();
            } catch (Throwable e) {
              if (thrown == null) {
                thrown = e;
              } else {
                thrown.addSuppressed(e);
              }
            } finally {
              // ensure the resource is removed even if it doesn't remove itself when closed
              resources.remove(resource);
            }
          }
  
          // It's possible for a thread registering a resource to register that resource after open
          // has been set to false and even after we've looped through and closed all the resources.
          // Since registering must be incremented *before* checking the state of open, however,
          // when we reach this point in that situation either the register call is still in progress
          // (registering > 0) or the new resource has been successfully added (resources not empty).
          // In either case, we just need to repeat the loop until there are no more register calls
          // in progress (no new calls can start and no resources left to close.
        } while (registering.get() > 0 || !resources.isEmpty());
        Throwables.propagateIfPossible(thrown, IOException.class);
      }
    }
docs: Closes the file system, runs the {@code onClose} callback and closes all registered resources.