private void serializeDirDiffList(
     INodeDirectory dir, final List<INodeReference> refList, OutputStream out)
     throws IOException {
   DirectoryWithSnapshotFeature sf = dir.getDirectoryWithSnapshotFeature();
   if (sf != null) {
     List<DirectoryDiff> diffList = sf.getDiffs().asList();
     SnapshotDiffSection.DiffEntry entry =
         SnapshotDiffSection.DiffEntry.newBuilder()
             .setInodeId(dir.getId())
             .setType(Type.DIRECTORYDIFF)
             .setNumOfDiff(diffList.size())
             .build();
     entry.writeDelimitedTo(out);
     for (int i = diffList.size() - 1; i >= 0; i--) { // reverse order!
       DirectoryDiff diff = diffList.get(i);
       SnapshotDiffSection.DirectoryDiff.Builder db =
           SnapshotDiffSection.DirectoryDiff.newBuilder()
               .setSnapshotId(diff.getSnapshotId())
               .setChildrenSize(diff.getChildrenSize())
               .setIsSnapshotRoot(diff.isSnapshotRoot());
       INodeDirectoryAttributes copy = diff.snapshotINode;
       if (!diff.isSnapshotRoot() && copy != null) {
         db.setName(ByteString.copyFrom(copy.getLocalNameBytes()))
             .setSnapshotCopy(buildINodeDirectory(copy, parent.getSaverContext()));
       }
       // process created list and deleted list
       List<INode> created = diff.getChildrenDiff().getList(ListType.CREATED);
       db.setCreatedListSize(created.size());
       List<INode> deleted = diff.getChildrenDiff().getList(ListType.DELETED);
       for (INode d : deleted) {
         if (d.isReference()) {
           refList.add(d.asReference());
           db.addDeletedINodeRef(refList.size() - 1);
         } else {
           db.addDeletedINode(d.getId());
         }
       }
       db.build().writeDelimitedTo(out);
       saveCreatedList(created, out);
     }
   }
 }
    /** Load DirectoryDiff list for a directory with snapshot feature */
    private void loadDirectoryDiffList(
        InputStream in, INodeDirectory dir, int size, final List<INodeReference> refList)
        throws IOException {
      if (!dir.isWithSnapshot()) {
        dir.addSnapshotFeature(null);
      }
      DirectoryDiffList diffs = dir.getDiffs();
      final LoaderContext state = parent.getLoaderContext();

      for (int i = 0; i < size; i++) {
        // load a directory diff
        SnapshotDiffSection.DirectoryDiff diffInPb =
            SnapshotDiffSection.DirectoryDiff.parseDelimitedFrom(in);
        final int snapshotId = diffInPb.getSnapshotId();
        final Snapshot snapshot = snapshotMap.get(snapshotId);
        int childrenSize = diffInPb.getChildrenSize();
        boolean useRoot = diffInPb.getIsSnapshotRoot();
        INodeDirectoryAttributes copy = null;
        if (useRoot) {
          copy = snapshot.getRoot();
        } else if (diffInPb.hasSnapshotCopy()) {
          INodeSection.INodeDirectory dirCopyInPb = diffInPb.getSnapshotCopy();
          final byte[] name = diffInPb.getName().toByteArray();
          PermissionStatus permission =
              loadPermission(dirCopyInPb.getPermission(), state.getStringTable());
          AclFeature acl = null;
          if (dirCopyInPb.hasAcl()) {
            acl =
                new AclFeature(
                    FSImageFormatPBINode.Loader.loadAclEntries(
                        dirCopyInPb.getAcl(), state.getStringTable()));
          }

          long modTime = dirCopyInPb.getModificationTime();
          boolean noQuota = dirCopyInPb.getNsQuota() == -1 && dirCopyInPb.getDsQuota() == -1;

          copy =
              noQuota
                  ? new INodeDirectoryAttributes.SnapshotCopy(name, permission, acl, modTime)
                  : new INodeDirectoryAttributes.CopyWithQuota(
                      name,
                      permission,
                      acl,
                      modTime,
                      dirCopyInPb.getNsQuota(),
                      dirCopyInPb.getDsQuota());
        }
        // load created list
        List<INode> clist = loadCreatedList(in, dir, diffInPb.getCreatedListSize());
        // load deleted list
        List<INode> dlist =
            loadDeletedList(
                refList,
                in,
                dir,
                diffInPb.getDeletedINodeList(),
                diffInPb.getDeletedINodeRefList());
        // create the directory diff
        DirectoryDiff diff =
            new DirectoryDiff(snapshotId, copy, null, childrenSize, clist, dlist, useRoot);
        diffs.addFirst(diff);
      }
    }