/**
  * Recursively compute the difference between snapshots under a given directory/file.
  *
  * @param node The directory/file under which the diff is computed.
  * @param parentPath Relative path (corresponding to the snapshot root) of the node's parent.
  * @param diffReport data structure used to store the diff.
  */
 private void computeDiffRecursively(
     INode node, List<byte[]> parentPath, SnapshotDiffInfo diffReport) {
   ChildrenDiff diff = new ChildrenDiff();
   byte[][] relativePath = parentPath.toArray(new byte[parentPath.size()][]);
   if (node.isDirectory()) {
     INodeDirectory dir = node.asDirectory();
     if (dir instanceof INodeDirectoryWithSnapshot) {
       INodeDirectoryWithSnapshot sdir = (INodeDirectoryWithSnapshot) dir;
       boolean change = sdir.computeDiffBetweenSnapshots(diffReport.from, diffReport.to, diff);
       if (change) {
         diffReport.addDirDiff(sdir, relativePath, diff);
       }
     }
     ReadOnlyList<INode> children =
         dir.getChildrenList(diffReport.isFromEarlier() ? diffReport.to : diffReport.from);
     for (INode child : children) {
       final byte[] name = child.getLocalNameBytes();
       if (diff.searchIndex(ListType.CREATED, name) < 0
           && diff.searchIndex(ListType.DELETED, name) < 0) {
         parentPath.add(name);
         computeDiffRecursively(child, parentPath, diffReport);
         parentPath.remove(parentPath.size() - 1);
       }
     }
   } else if (node.isFile() && node.asFile() instanceof FileWithSnapshot) {
     FileWithSnapshot file = (FileWithSnapshot) node.asFile();
     Snapshot earlierSnapshot = diffReport.isFromEarlier() ? diffReport.from : diffReport.to;
     Snapshot laterSnapshot = diffReport.isFromEarlier() ? diffReport.to : diffReport.from;
     boolean change = file.getDiffs().changedBetweenSnapshots(earlierSnapshot, laterSnapshot);
     if (change) {
       diffReport.addFileDiff(file.asINodeFile(), relativePath);
     }
   }
 }
 /**
  * Compute the difference between two snapshots (or a snapshot and the current directory) of the
  * directory.
  *
  * @param from The name of the start point of the comparison. Null indicating the current tree.
  * @param to The name of the end point. Null indicating the current tree.
  * @return The difference between the start/end points.
  * @throws SnapshotException If there is no snapshot matching the starting point, or if
  *     endSnapshotName is not null but cannot be identified as a previous snapshot.
  */
 SnapshotDiffInfo computeDiff(final String from, final String to) throws SnapshotException {
   Snapshot fromSnapshot = getSnapshotByName(from);
   Snapshot toSnapshot = getSnapshotByName(to);
   // if the start point is equal to the end point, return null
   if (from.equals(to)) {
     return null;
   }
   SnapshotDiffInfo diffs = new SnapshotDiffInfo(this, fromSnapshot, toSnapshot);
   computeDiffRecursively(this, new ArrayList<byte[]>(), diffs);
   return diffs;
 }