@Override
  public void copy(URI fromURI, URI toURI) {
    // TODO - Determine how copy should work. Currently copy and move are
    // different. Copy works like an OS where "if destination exists, put
    // it underneath. else name if for destination. IE cp a/b n would create
    // just n... or if n already exists, then it would create n/b.
    // I don't think FS2 needs this level of complexity. Move is implemented
    // more simply, fast fail if destination exists.

    // DEEP copy
    boolean toRootPreExists = exists(toURI);

    URI newRootURI = CoreFS2Utils.createCopiedURI(toRootPreExists, fromURI, toURI, fromURI);

    // copy root
    copySingleNode(fromURI, newRootURI);

    // copy descendants (tree-walking order does not matter for memory
    // implementation)
    Set<URI> descendants = listDescendants(fromURI);
    for (URI descendant : descendants) {
      // there is some complexity determining the new location, based around
      // whether the target pre-exists
      URI descendantToURI =
          CoreFS2Utils.createCopiedURI(toRootPreExists, fromURI, toURI, descendant);
      copySingleNode(descendant, descendantToURI);
    }
  }