private void executeDelete(@NotNull VirtualFile file) {
    if (!file.exists()) {
      LOG.error("Deleting a file, which does not exist: " + file.getPath());
      return;
    }
    clearIdCache();

    int id = getFileId(file);

    final VirtualFile parent = file.getParent();
    final int parentId = parent == null ? 0 : getFileId(parent);

    if (parentId == 0) {
      String rootUrl =
          normalizeRootUrl(file.getPath(), (NewVirtualFileSystem) file.getFileSystem());
      myRootsLock.writeLock().lock();
      try {
        myRoots.remove(rootUrl);
        myRootsById.remove(id);
        FSRecords.deleteRootRecord(id);
      } finally {
        myRootsLock.writeLock().unlock();
      }
    } else {
      removeIdFromParentList(parentId, id, parent, file);
      VirtualDirectoryImpl directory = (VirtualDirectoryImpl) file.getParent();
      assert directory != null : file;
      directory.removeChild(file);
    }

    FSRecords.deleteRecordRecursively(id);

    invalidateSubtree(file);
  }
 @Override
 protected char[] appendPathOnFileSystem(int accumulatedPathLength, int[] positionRef) {
   String parentPath = myParentLocalFile.getPath();
   char[] chars =
       new char
           [parentPath.length() + JarFileSystem.JAR_SEPARATOR.length() + accumulatedPathLength];
   positionRef[0] = copyString(chars, positionRef[0], myParentLocalFile.getPath());
   positionRef[0] = copyString(chars, positionRef[0], JarFileSystem.JAR_SEPARATOR);
   return chars;
 }
  @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 applyChildrenChangeEvents(VirtualFile parent, List<VFileEvent> events) {
    final NewVirtualFileSystem delegate = getDelegate(parent);
    TIntArrayList childrenIdsUpdated = new TIntArrayList();
    List<VirtualFile> childrenToBeUpdated = new SmartList<VirtualFile>();

    assert parent != null && parent != mySuperRoot;
    final int parentId = getFileId(parent);
    assert parentId != 0;
    TIntHashSet parentChildrenIds = new TIntHashSet(FSRecords.list(parentId));
    boolean hasRemovedChildren = false;

    for (VFileEvent event : events) {
      if (event instanceof VFileCreateEvent) {
        String name = ((VFileCreateEvent) event).getChildName();
        final VirtualFile fake = new FakeVirtualFile(parent, name);
        final FileAttributes attributes = delegate.getAttributes(fake);

        if (attributes != null) {
          final int childId = createAndFillRecord(delegate, fake, parentId, attributes);
          assert parent instanceof VirtualDirectoryImpl : parent;
          final VirtualDirectoryImpl dir = (VirtualDirectoryImpl) parent;
          VirtualFileSystemEntry child = dir.createChild(name, childId, dir.getFileSystem());
          childrenToBeUpdated.add(child);
          childrenIdsUpdated.add(childId);
          parentChildrenIds.add(childId);
        }
      } else if (event instanceof VFileDeleteEvent) {
        VirtualFile file = ((VFileDeleteEvent) event).getFile();
        if (!file.exists()) {
          LOG.error("Deleting a file, which does not exist: " + file.getPath());
          continue;
        }

        hasRemovedChildren = true;
        int id = getFileId(file);

        childrenToBeUpdated.add(file);
        childrenIdsUpdated.add(-id);
        parentChildrenIds.remove(id);
      }
    }

    FSRecords.updateList(parentId, parentChildrenIds.toArray());

    if (hasRemovedChildren) clearIdCache();
    VirtualDirectoryImpl parentImpl = (VirtualDirectoryImpl) parent;

    for (int i = 0, len = childrenIdsUpdated.size(); i < len; ++i) {
      final int childId = childrenIdsUpdated.get(i);
      final VirtualFile childFile = childrenToBeUpdated.get(i);

      if (childId > 0) {
        parentImpl.addChild((VirtualFileSystemEntry) childFile);
      } else {
        FSRecords.deleteRecordRecursively(-childId);
        parentImpl.removeChild(childFile);
        invalidateSubtree(childFile);
      }
    }
  }
  @NotNull
  private VirtualFilePointer create(
      @Nullable VirtualFile file,
      @NotNull String url,
      @NotNull final Disposable parentDisposable,
      @Nullable VirtualFilePointerListener listener) {
    String protocol;
    VirtualFileSystem fileSystem;
    if (file == null) {
      protocol = VirtualFileManager.extractProtocol(url);
      fileSystem = myVirtualFileManager.getFileSystem(protocol);
    } else {
      protocol = null;
      fileSystem = file.getFileSystem();
    }
    if (fileSystem == TempFileSystem.getInstance()) {
      // for tests, recreate always since
      VirtualFile found =
          fileSystem == null
              ? null
              : file != null ? file : VirtualFileManager.getInstance().findFileByUrl(url);
      return new IdentityVirtualFilePointer(found, url);
    }
    if (fileSystem != LocalFileSystem.getInstance() && fileSystem != JarFileSystem.getInstance()) {
      // 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);
      url = VirtualFileManager.constructUrl(protocol, path);
    } else {
      path = file.getPath();
      // url has come from VirtualFile.getUrl() and is good enough
    }

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

    int newCount = pointer.incrementUsageCount();

    if (newCount == 1) {
      Disposer.register(parentDisposable, pointer);
    } else {
      // already registered
      register(parentDisposable, pointer);
    }

    return pointer;
  }
 private ArchiveRoot(
     @NotNull NewVirtualFileSystem fs,
     int id,
     VfsData.Segment segment,
     VfsData.DirectoryData data,
     VirtualFile parentLocalFile) {
   super(id, segment, data, fs);
   myParentLocalFile = parentLocalFile;
   myParentPath = myParentLocalFile.getPath();
 }
  @Override
  public VirtualFile createChildFile(
      Object requestor, @NotNull VirtualFile parent, @NotNull String file) throws IOException {
    getDelegate(parent).createChildFile(requestor, parent, file);
    processEvent(new VFileCreateEvent(requestor, parent, file, false, false));

    final VirtualFile child = parent.findChild(file);
    if (child == null) {
      throw new IOException("Cannot create child file '" + file + "' at " + parent.getPath());
    }
    return child;
  }
  @Override
  public VirtualFile createChildDirectory(
      Object requestor, @NotNull VirtualFile parent, @NotNull String dir) throws IOException {
    getDelegate(parent).createChildDirectory(requestor, parent, dir);
    processEvent(new VFileCreateEvent(requestor, parent, dir, true, false));

    final VirtualFile child = parent.findChild(dir);
    if (child == null) {
      throw new IOException("Cannot create child directory '" + dir + "' at " + parent.getPath());
    }
    return child;
  }
  @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;
  }
  private void assertEvent(Class<? extends VFileEvent> type, String... paths) {
    List<VFileEvent> events = getEvents(type.getSimpleName(), null);
    assertEquals(events.toString(), paths.length, events.size());

    Set<String> pathSet =
        ContainerUtil.map2Set(
            paths,
            new Function<String, String>() {
              @Override
              public String fun(final String path) {
                return FileUtil.toSystemIndependentName(path);
              }
            });

    for (VFileEvent event : events) {
      assertTrue(event.toString(), type.isInstance(event));
      VirtualFile eventFile = event.getFile();
      assertNotNull(event.toString(), eventFile);
      assertTrue(
          eventFile + " not in " + Arrays.toString(paths), pathSet.remove(eventFile.getPath()));
    }
  }
    @Override
    public void before(@NotNull final List<? extends VFileEvent> events) {
      cleanContainerCaches();
      List<VirtualFilePointer> toFireEvents = new ArrayList<VirtualFilePointer>();
      List<String> toUpdateUrl = new ArrayList<String>();

      synchronized (VirtualFilePointerManagerImpl.this) {
        for (VFileEvent event : events) {
          if (event instanceof VFileDeleteEvent) {
            final VFileDeleteEvent deleteEvent = (VFileDeleteEvent) event;
            String url = deleteEvent.getFile().getPath();
            addPointersUnder(url, true, toFireEvents);
          } else if (event instanceof VFileCreateEvent) {
            final VFileCreateEvent createEvent = (VFileCreateEvent) event;
            String url = createEvent.getPath();
            addPointersUnder(url, false, toFireEvents);
          } else if (event instanceof VFileCopyEvent) {
            final VFileCopyEvent copyEvent = (VFileCopyEvent) event;
            String url = copyEvent.getNewParent().getPath() + "/" + copyEvent.getFile().getName();
            addPointersUnder(url, false, toFireEvents);
          } else if (event instanceof VFileMoveEvent) {
            final VFileMoveEvent moveEvent = (VFileMoveEvent) event;
            List<VirtualFilePointer> pointers = new ArrayList<VirtualFilePointer>();
            addPointersUnder(moveEvent.getFile().getPath(), false, pointers);
            for (VirtualFilePointer pointer : pointers) {
              VirtualFile file = pointer.getFile();
              if (file != null) {
                toUpdateUrl.add(file.getPath());
              }
            }
          } else if (event instanceof VFilePropertyChangeEvent) {
            final VFilePropertyChangeEvent change = (VFilePropertyChangeEvent) event;
            if (VirtualFile.PROP_NAME.equals(change.getPropertyName())) {
              List<VirtualFilePointer> pointers = new ArrayList<VirtualFilePointer>();
              addPointersUnder(change.getFile().getPath(), false, pointers);
              for (VirtualFilePointer pointer : pointers) {
                VirtualFile file = pointer.getFile();
                if (file != null) {
                  toUpdateUrl.add(file.getPath());
                }
              }
            }
          }
        }

        myEvents = new ArrayList<EventDescriptor>();
        for (VirtualFilePointerListener listener : myUrlToPointerMaps.keySet()) {
          if (listener == null) continue;
          EventDescriptor event = new EventDescriptor(listener, toFireEvents);
          myEvents.add(event);
        }
      }

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

      if (!toFireEvents.isEmpty()) {
        VirtualFilePointer[] arr =
            toFireEvents.toArray(new VirtualFilePointer[toFireEvents.size()]);
        myBus.syncPublisher(VirtualFilePointerListener.TOPIC).beforeValidityChanged(arr);
      }

      myPointersToUpdate = toFireEvents;
      myUrlsToUpdate = toUpdateUrl;
    }