@NotNull
  private VirtualFilePointer create(
      @Nullable("null means the pointer will be created from the (not null) url") VirtualFile file,
      @Nullable("null means url has to be computed from the (not-null) file path") String url,
      @NotNull Disposable parentDisposable,
      @Nullable VirtualFilePointerListener listener) {
    VirtualFileSystem fileSystem;
    String protocol;
    String path;
    if (file == null) {
      int protocolEnd = url.indexOf(URLUtil.SCHEME_SEPARATOR);
      if (protocolEnd == -1) {
        protocol = null;
        fileSystem = null;
      } else {
        protocol = url.substring(0, protocolEnd);
        fileSystem = myVirtualFileManager.getFileSystem(protocol);
      }
      path = url.substring(protocolEnd + URLUtil.SCHEME_SEPARATOR.length());
    } else {
      fileSystem = file.getFileSystem();
      protocol = fileSystem.getProtocol();
      path = file.getPath();
      url = VirtualFileManager.constructUrl(protocol, path);
    }

    if (fileSystem == TEMP_FILE_SYSTEM) {
      // for tests, recreate always
      VirtualFile found = file == null ? VirtualFileManager.getInstance().findFileByUrl(url) : file;
      return new IdentityVirtualFilePointer(found, url);
    }

    boolean isJar = fileSystem == JAR_FILE_SYSTEM;
    if (fileSystem != LOCAL_FILE_SYSTEM && !isJar) {
      // we are unable to track alien file systems for now
      VirtualFile found =
          fileSystem == null
              ? null
              : file != null ? file : VirtualFileManager.getInstance().findFileByUrl(url);
      // if file is null, this pointer will never be alive
      return getOrCreateIdentity(url, found);
    }

    if (file == null) {
      String cleanPath = cleanupPath(path, isJar);
      // if newly created path is the same as substringed from url one then the url did not change,
      // we can reuse it
      //noinspection StringEquality
      if (cleanPath != path) {
        url = VirtualFileManager.constructUrl(protocol, cleanPath);
        path = cleanPath;
      }
    }
    // else url has come from VirtualFile.getPath() and is good enough

    VirtualFilePointerImpl pointer =
        getOrCreate(parentDisposable, listener, path, Pair.create(file, url));
    DelegatingDisposable.registerDisposable(parentDisposable, pointer);
    return pointer;
  }
 private void copyToTemp(VirtualFile file) {
   try {
     final byte[] bytes = file.contentsToByteArray();
     mySavedCopies.put(file, bytes);
     mySavedTimestamps.put(file, file.getTimeStamp());
   } catch (IOException e) {
     LOG.error(e);
   }
 }
 private void saveChangedProjectFile(
     final VirtualFile file, @Nullable final Project project, final StateStorage storage) {
   if (file.exists()) {
     copyToTemp(file);
   }
   registerProjectToReload(project, file, storage);
 }
 @Override
 public void saveChangedProjectFile(final VirtualFile file, final Project project) {
   if (file.exists()) {
     copyToTemp(file);
   }
   registerProjectToReload(project, file, null);
 }
  @NotNull
  private VirtualFilePointer create(
      @Nullable VirtualFile file,
      @NotNull String url,
      @NotNull final Disposable parentDisposable,
      @Nullable VirtualFilePointerListener listener) {
    String protocol;
    IVirtualFileSystem fileSystem;
    if (file == null) {
      protocol = VirtualFileManager.extractProtocol(url);
      fileSystem = myVirtualFileManager.getFileSystem(protocol);
    } else {
      protocol = null;
      fileSystem = file.getFileSystem();
    }
    if (fileSystem == myTempFileSystem) {
      // for tests, recreate always
      VirtualFile found = file == null ? VirtualFileManager.getInstance().findFileByUrl(url) : file;
      return new IdentityVirtualFilePointer(found, url);
    }
    if (fileSystem != myLocalFileSystem && !(fileSystem instanceof ArchiveFileSystem)) {
      // we are unable to track alien file systems for now
      VirtualFile found =
          fileSystem == null
              ? null
              : file != null ? file : VirtualFileManager.getInstance().findFileByUrl(url);
      // if file is null, this pointer will never be alive
      return getOrCreateIdentity(url, found);
    }

    String path;
    if (file == null) {
      path = VirtualFileManager.extractPath(url);
      path = cleanupPath(path, protocol, fileSystem);
      url = VirtualFileManager.constructUrl(protocol, path);
    } else {
      path = file.getPath();
      // url has come from VirtualFile.getUrl() and is good enough
    }

    VirtualFilePointerImpl pointer =
        getOrCreate(parentDisposable, listener, path, Pair.create(file, url));

    DelegatingDisposable.registerDisposable(parentDisposable, pointer);

    return pointer;
  }
 @Override
 @NotNull
 public synchronized VirtualFilePointer create(
     @NotNull VirtualFile file,
     @NotNull Disposable parent,
     @Nullable VirtualFilePointerListener listener) {
   return create(file, file.getUrl(), parent, listener);
 }
  private void restoreCopy(VirtualFile file) {
    try {
      if (file == null) return; // Externally deleted actually.
      if (!file.isWritable()) return; // IDEA was unable to save it as well. So no need to restore.

      final byte[] bytes = mySavedCopies.get(file);
      if (bytes != null) {
        try {
          file.setBinaryContent(bytes, -1, mySavedTimestamps.get(file));
        } catch (IOException e) {
          Messages.showWarningDialog(
              ProjectBundle.message("project.reload.write.failed", file.getPresentableUrl()),
              ProjectBundle.message("project.reload.write.failed.title"));
        }
      }
    } finally {
      mySavedCopies.remove(file);
      mySavedTimestamps.remove(file);
    }
  }
  @Override
  public void before(@NotNull final List<? extends VFileEvent> events) {
    List<FilePointerPartNode> toFireEvents = new ArrayList<FilePointerPartNode>();
    List<FilePointerPartNode> toUpdateUrl = new ArrayList<FilePointerPartNode>();
    VirtualFilePointer[] toFirePointers;

    synchronized (this) {
      incModificationCount();
      for (VFileEvent event : events) {
        if (event instanceof VFileDeleteEvent) {
          final VFileDeleteEvent deleteEvent = (VFileDeleteEvent) event;
          addPointersUnder(deleteEvent.getFile(), false, "", toFireEvents);

        } else if (event instanceof VFileCreateEvent) {
          final VFileCreateEvent createEvent = (VFileCreateEvent) event;
          addPointersUnder(createEvent.getParent(), true, createEvent.getChildName(), toFireEvents);
        } else if (event instanceof VFileCopyEvent) {
          final VFileCopyEvent copyEvent = (VFileCopyEvent) event;
          addPointersUnder(
              copyEvent.getNewParent(), true, copyEvent.getFile().getName(), toFireEvents);
        } else if (event instanceof VFileMoveEvent) {
          final VFileMoveEvent moveEvent = (VFileMoveEvent) event;
          VirtualFile eventFile = moveEvent.getFile();
          addPointersUnder(moveEvent.getNewParent(), true, eventFile.getName(), toFireEvents);

          List<FilePointerPartNode> nodes = new ArrayList<FilePointerPartNode>();
          addPointersUnder(eventFile, false, "", nodes);
          for (FilePointerPartNode pair : nodes) {
            VirtualFile file = pair.leaf.getFile();
            if (file != null) {
              toUpdateUrl.add(pair);
            }
          }
        } else if (event instanceof VFilePropertyChangeEvent) {
          final VFilePropertyChangeEvent change = (VFilePropertyChangeEvent) event;
          if (VirtualFile.PROP_NAME.equals(change.getPropertyName())) {
            VirtualFile eventFile = change.getFile();
            VirtualFile parent = eventFile.getParent(); // e.g. for LightVirtualFiles
            addPointersUnder(parent, true, change.getNewValue().toString(), toFireEvents);

            List<FilePointerPartNode> nodes = new ArrayList<FilePointerPartNode>();
            addPointersUnder(eventFile, false, "", nodes);
            for (FilePointerPartNode pair : nodes) {
              VirtualFile file = pair.leaf.getFile();
              if (file != null) {
                toUpdateUrl.add(pair);
              }
            }
          }
        }
      }

      myEvents = new ArrayList<EventDescriptor>();
      toFirePointers = toPointers(toFireEvents);
      for (final VirtualFilePointerListener listener : myPointers.keySet()) {
        if (listener == null) continue;
        List<VirtualFilePointer> filtered =
            ContainerUtil.filter(
                toFirePointers,
                new Condition<VirtualFilePointer>() {
                  @Override
                  public boolean value(VirtualFilePointer pointer) {
                    return ((VirtualFilePointerImpl) pointer).getListener() == listener;
                  }
                });
        if (!filtered.isEmpty()) {
          EventDescriptor event =
              new EventDescriptor(
                  listener, filtered.toArray(new VirtualFilePointer[filtered.size()]));
          myEvents.add(event);
        }
      }
    }

    for (EventDescriptor descriptor : myEvents) {
      descriptor.fireBefore();
    }

    if (!toFireEvents.isEmpty()) {
      myBus.syncPublisher(VirtualFilePointerListener.TOPIC).beforeValidityChanged(toFirePointers);
    }

    myPointersToFire = toFireEvents;
    myPointersToUpdateUrl = toUpdateUrl;
  }