Пример #1
0
 private static void invalidateSubtree(@NotNull VirtualFile file) {
   final VirtualFileSystemEntry impl = (VirtualFileSystemEntry) file;
   impl.invalidate();
   for (VirtualFile child : impl.getCachedChildren()) {
     invalidateSubtree(child);
   }
 }
  @Nullable
  private VirtualFileSystemEntry findChild(
      @NotNull String name,
      boolean doRefresh,
      boolean ensureCanonicalName,
      @NotNull NewVirtualFileSystem delegate) {
    boolean ignoreCase = !delegate.isCaseSensitive();
    Comparator comparator = getComparator(ignoreCase);
    VirtualFileSystemEntry result = doFindChild(name, ensureCanonicalName, delegate, comparator);

    if (result == NULL_VIRTUAL_FILE) {
      result = doRefresh ? createAndFindChildWithEventFire(name, delegate) : null;
    } else if (result != null
        && doRefresh
        && delegate.isDirectory(result) != result.isDirectory()) {
      RefreshQueue.getInstance().refresh(false, false, null, result);
      result = findChild(name, false, ensureCanonicalName, delegate);
    }

    if (result == null) {
      addToAdoptedChildren(!delegate.isCaseSensitive(), name, comparator);
    }

    return result;
  }
 // optimisation: do not travel up unnecessary
 private void markDirtyRecursivelyInternal() {
   for (VirtualFileSystemEntry child : getArraySafely()) {
     if (isAdoptedChild(child)) break;
     child.markDirtyInternal();
     if (child instanceof VirtualDirectoryImpl) {
       ((VirtualDirectoryImpl) child).markDirtyRecursivelyInternal();
     }
   }
 }
Пример #4
0
  @Nullable
  private VirtualFileSystemEntry findFileById(
      int id, boolean cachedOnly, TIntArrayList visited, int mask) {
    VirtualFileSystemEntry cached = myIdToDirCache.get(id);
    if (cached != null) return cached;

    if (visited != null
        && (visited.size() >= DEPTH_LIMIT || (mask & id) == id && visited.contains(id))) {
      @NonNls
      String sb =
          "Dead loop detected in persistent FS (id=" + id + " cached-only=" + cachedOnly + "):";
      for (int i = 0; i < visited.size(); i++) {
        int _id = visited.get(i);
        sb +=
            "\n  "
                + _id
                + " '"
                + getName(_id)
                + "' "
                + String.format("%02x", getFileAttributes(_id))
                + ' '
                + myIdToDirCache.containsKey(_id);
      }
      LOG.error(sb);
      return null;
    }

    int parentId = getParent(id);
    if (parentId >= id) {
      if (visited == null) visited = new TIntArrayList(DEPTH_LIMIT);
    }
    if (visited != null) visited.add(id);

    VirtualFileSystemEntry result;
    if (parentId == 0) {
      myRootsLock.readLock().lock();
      try {
        result = myRootsById.get(id);
      } finally {
        myRootsLock.readLock().unlock();
      }
    } else {
      VirtualFileSystemEntry parentFile = findFileById(parentId, cachedOnly, visited, mask | id);
      if (parentFile instanceof VirtualDirectoryImpl) {
        result = ((VirtualDirectoryImpl) parentFile).findChildById(id, cachedOnly);
      } else {
        result = null;
      }
    }

    if (result != null && result.isDirectory()) {
      VirtualFileSystemEntry old = myIdToDirCache.put(id, result);
      if (old != null) result = old;
    }
    return result;
  }
  public VirtualFileSystemEntry findChildById(int id, boolean cachedOnly) {
    VirtualFile[] array = getArraySafely();
    VirtualFileSystemEntry result = null;
    for (VirtualFile file : array) {
      VirtualFileSystemEntry withId = (VirtualFileSystemEntry) file;
      if (withId.getId() == id) {
        result = withId;
        break;
      }
    }
    if (result != null) return result;
    if (cachedOnly) return null;

    String name = ourPersistence.getName(id);
    return findChild(name, false, false, getFileSystem());
  }
  @TestOnly
  private static void assertAccessInTests(
      @NotNull VirtualFileSystemEntry child, @NotNull NewVirtualFileSystem delegate) {
    final Application application = ApplicationManager.getApplication();
    if (IS_UNDER_TEAMCITY
        && SHOULD_PERFORM_ACCESS_CHECK
        && application.isUnitTestMode()
        && application instanceof ApplicationImpl
        && ((ApplicationImpl) application).isComponentsCreated()) {
      if (delegate != LocalFileSystem.getInstance() && delegate != JarFileSystem.getInstance()) {
        return;
      }
      // root' children are loaded always
      if (child.getParent() == null || child.getParent().getParent() == null) return;

      Set<String> allowed = allowedRoots();
      boolean isUnder = allowed == null;
      if (!isUnder) {
        String childPath = child.getPath();
        if (delegate == JarFileSystem.getInstance()) {
          VirtualFile local = JarFileSystem.getInstance().getVirtualFileForJar(child);
          assert local != null : child;
          childPath = local.getPath();
        }
        for (String root : allowed) {
          if (FileUtil.startsWith(childPath, root)) {
            isUnder = true;
            break;
          }
          if (root.startsWith(JarFileSystem.PROTOCOL_PREFIX)) {
            String rootLocalPath =
                FileUtil.toSystemIndependentName(PathUtil.toPresentableUrl(root));
            isUnder = FileUtil.startsWith(childPath, rootLocalPath);
            if (isUnder) break;
          }
        }
      }

      assert isUnder || allowed.isEmpty()
          : "File accessed outside allowed roots: "
              + child
              + ";\nAllowed roots: "
              + new ArrayList<String>(allowed);
    }
  }
  @NotNull
  public VirtualFileSystemEntry createChild(
      @NotNull String name, int id, @NotNull NewVirtualFileSystem delegate) {
    VirtualFileSystemEntry child;

    final int attributes = ourPersistence.getFileAttributes(id);
    if (PersistentFS.isDirectory(attributes)) {
      child = new VirtualDirectoryImpl(name, this, delegate, id, attributes);
    } else {
      child = new VirtualFileImpl(name, this, id, attributes);
      //noinspection TestOnlyProblems
      assertAccessInTests(child, delegate);
    }

    if (delegate.markNewFilesAsDirty()) {
      child.markDirty();
    }

    return child;
  }
 @Override
 protected char[] appendPathOnFileSystem(int accumulatedPathLength, int[] positionRef) {
   char[] chars =
       getParent()
           .appendPathOnFileSystem(accumulatedPathLength + 1 + myName.length(), positionRef);
   if (positionRef[0] > 0 && chars[positionRef[0] - 1] != '/') {
     chars[positionRef[0]++] = '/';
   }
   positionRef[0] = VirtualFileSystemEntry.copyString(chars, positionRef[0], myName);
   return chars;
 }
Пример #9
0
  private void executeMove(@NotNull VirtualFile file, @NotNull VirtualFile newParent) {
    clearIdCache();

    final int fileId = getFileId(file);
    final int newParentId = getFileId(newParent);
    final int oldParentId = getFileId(file.getParent());

    removeIdFromParentList(oldParentId, fileId, file.getParent(), file);
    FSRecords.setParent(fileId, newParentId);
    appendIdToParentList(newParentId, fileId);
    ((VirtualFileSystemEntry) file).setParent(newParent);
  }
Пример #10
0
  private static void executeTouch(
      @NotNull VirtualFile file, boolean reloadContentFromDelegate, long newModificationStamp) {
    if (reloadContentFromDelegate) {
      setFlag(file, MUST_RELOAD_CONTENT, true);
    }

    final NewVirtualFileSystem delegate = getDelegate(file);
    final FileAttributes attributes = delegate.getAttributes(file);
    FSRecords.setLength(getFileId(file), attributes != null ? attributes.length : DEFAULT_LENGTH);
    FSRecords.setTimestamp(
        getFileId(file), attributes != null ? attributes.lastModified : DEFAULT_TIMESTAMP);

    ((VirtualFileSystemEntry) file).setModificationStamp(newModificationStamp);
  }
  private void assertConsistency(
      @NotNull VirtualFileSystemEntry[] array, boolean ignoreCase, @NotNull Object... details) {
    if (!CHECK) return;
    boolean allChildrenLoaded = allChildrenLoaded();
    for (int i = 0; i < array.length; i++) {
      VirtualFileSystemEntry file = array[i];
      boolean isAdopted = isAdoptedChild(file);
      assert !isAdopted || !allChildrenLoaded;
      if (isAdopted && i != array.length - 1) {
        assert isAdoptedChild(array[i + 1]);
      }
      if (i != 0) {
        VirtualFileSystemEntry prev = array[i - 1];
        String prevName = prev.getName();
        int cmp = file.compareNameTo(prevName, ignoreCase);
        if (cmp == 0) {
          error(
              verboseToString.fun(prev) + " equals to " + verboseToString.fun(file),
              array,
              details);
        }

        if (isAdopted == isAdoptedChild(prev)) {
          if (cmp <= 0) {
            error(
                "Not sorted: "
                    + verboseToString.fun(prev)
                    + " is not less than "
                    + verboseToString.fun(file),
                array,
                details);
          }
        }
      }
    }
  }
  public synchronized void addChild(@NotNull VirtualFileSystemEntry child) {
    VirtualFileSystemEntry[] array = myChildren;
    final String childName = child.getName();
    final boolean ignoreCase = !getFileSystem().isCaseSensitive();
    long r = findIndexInBoth(array, getComparator(childName, ignoreCase));
    int indexInReal = (int) (r >> 32);
    int indexInAdopted = (int) r;

    if (indexInAdopted >= 0) {
      // remove Adopted first
      removeFromArray(indexInAdopted);
    }
    if (indexInReal < 0) {
      insertChildAt(child, indexInReal);
    }
    // else already stored
    assertConsistency(myChildren, ignoreCase, child);
  }
 @Override
 public String fun(VirtualFileSystemEntry file) {
   //noinspection HardCodedStringLiteral
   return file
       + " (name: '"
       + file.getName()
       + "', "
       + file.getClass()
       + ", parent: "
       + file.getParent()
       + "; id: "
       + file.getId()
       + "; FS: "
       + file.getFileSystem()
       + "; delegate.attrs: "
       + file.getFileSystem().getAttributes(file)
       + "; caseSensitive: "
       + file.getFileSystem().isCaseSensitive()
       + "; canonical: "
       + file.getFileSystem().getCanonicallyCasedName(file)
       + ") ";
 }
Пример #14
0
 private static void executeSetTarget(@NotNull VirtualFile file, String target) {
   ((VirtualFileSystemEntry) file).setLinkTarget(target);
 }
 private static boolean isAdoptedChild(@NotNull VirtualFileSystemEntry v) {
   return v.getParent() == NULL_VIRTUAL_FILE;
 }
 @Override
 public int compareFileNameTo(@NotNull String myName, @NotNull VirtualFileSystemEntry file) {
   return -file.compareNameTo(myName, true);
 }
  private void assertConsistency(
      @NotNull VirtualFileSystemEntry[] array, boolean ignoreCase, @NotNull Object... details) {
    if (!CHECK) return;
    boolean allChildrenLoaded = allChildrenLoaded();
    for (int i = 0; i < array.length; i++) {
      VirtualFileSystemEntry file = array[i];
      boolean isAdopted = isAdoptedChild(file);
      assert !isAdopted || !allChildrenLoaded;
      if (isAdopted && i != array.length - 1) {
        assert isAdoptedChild(array[i + 1]);
      }
      if (i != 0) {
        VirtualFileSystemEntry prev = array[i - 1];
        String prevName = prev.getName();
        int cmp = file.compareNameTo(prevName, ignoreCase);
        if (cmp == 0) {
          Function<VirtualFileSystemEntry, String> verboseToString =
              new Function<VirtualFileSystemEntry, String>() {
                @Override
                public String fun(VirtualFileSystemEntry entry) {
                  return entry
                      + " (name: '"
                      + entry.getName()
                      + "', "
                      + entry.getClass()
                      + ", parent:"
                      + entry.getParent()
                      + "; id:"
                      + entry.getId()
                      + "; FS:"
                      + entry.getFileSystem()
                      + "; delegate.attrs:"
                      + entry.getFileSystem().getAttributes(entry)
                      + "; caseSensitive:"
                      + entry.getFileSystem().isCaseSensitive()
                      + "; canonical:"
                      + entry.getFileSystem().getCanonicallyCasedName(entry)
                      + ") ";
                }
              };
          String children = StringUtil.join(array, verboseToString, ",");
          throw new AssertionError(
              verboseToString.fun(prev)
                  + " equals to "
                  + verboseToString.fun(file)
                  + "; children: "
                  + children
                  + "\nDetails: "
                  + ContainerUtil.map(
                      details,
                      new Function<Object, Object>() {
                        @Override
                        public Object fun(Object o) {
                          return o instanceof Object[] ? Arrays.toString((Object[]) o) : o;
                        }
                      }));
        }

        if (isAdopted == isAdoptedChild(prev)) {
          assert cmp > 0 : "Not sorted. " + Arrays.toString(details);
        }
      }
    }
  }
Пример #18
0
 private static void executeRename(@NotNull VirtualFile file, @NotNull final String newName) {
   final int id = getFileId(file);
   FSRecords.setName(id, newName);
   ((VirtualFileSystemEntry) file).setNewName(newName);
 }
Пример #19
0
 private static void executeSetWritable(@NotNull VirtualFile file, boolean writableFlag) {
   setFlag(file, IS_READ_ONLY, !writableFlag);
   ((VirtualFileSystemEntry) file).updateProperty(VirtualFile.PROP_WRITABLE, writableFlag);
 }
Пример #20
0
  @Override
  @Nullable
  public VirtualFileSystemEntry findRoot(
      @NotNull String basePath, @NotNull NewVirtualFileSystem fs) {
    if (basePath.isEmpty()) {
      LOG.error("Invalid root, fs=" + fs);
      return null;
    }

    String rootUrl = normalizeRootUrl(basePath, fs);

    myRootsLock.readLock().lock();
    try {
      VirtualFileSystemEntry root = myRoots.get(rootUrl);
      if (root != null) return root;
    } finally {
      myRootsLock.readLock().unlock();
    }

    final VirtualFileSystemEntry newRoot;
    int rootId = FSRecords.findRootRecord(rootUrl);

    VfsData.Segment segment = VfsData.getSegment(rootId, true);
    VfsData.DirectoryData directoryData = new VfsData.DirectoryData();
    if (fs instanceof ArchiveFileSystem) {
      String parentPath =
          basePath.substring(0, basePath.indexOf(ArchiveFileSystem.ARCHIVE_SEPARATOR));
      VirtualFile parentFile = LocalFileSystem.getInstance().findFileByPath(parentPath);
      if (parentFile == null) return null;
      FileType type = FileTypeRegistry.getInstance().getFileTypeByFileName(parentFile.getName());
      if (!(type instanceof ArchiveFileType)) return null;
      newRoot = new ArchiveRoot(fs, rootId, segment, directoryData, parentFile);
    } else {
      newRoot = new FsRoot(fs, rootId, segment, directoryData, basePath);
    }

    FileAttributes attributes =
        fs.getAttributes(
            new StubVirtualFile() {
              @NotNull
              @Override
              public String getPath() {
                return newRoot.getPath();
              }

              @Nullable
              @Override
              public VirtualFile getParent() {
                return null;
              }
            });
    if (attributes == null || !attributes.isDirectory()) {
      return null;
    }

    boolean mark = false;

    myRootsLock.writeLock().lock();
    try {
      VirtualFileSystemEntry root = myRoots.get(rootUrl);
      if (root != null) return root;

      VfsData.initFile(rootId, segment, -1, directoryData);
      mark = writeAttributesToRecord(rootId, 0, newRoot, fs, attributes);

      myRoots.put(rootUrl, newRoot);
      myRootsById.put(rootId, newRoot);
    } finally {
      myRootsLock.writeLock().unlock();
    }

    if (!mark && attributes.lastModified != FSRecords.getTimestamp(rootId)) {
      newRoot.markDirtyRecursively();
    }

    LOG.assertTrue(
        rootId == newRoot.getId(),
        "root=" + newRoot + " expected=" + rootId + " actual=" + newRoot.getId());

    return newRoot;
  }
Пример #21
0
 private static void executeSetHidden(@NotNull VirtualFile file, boolean hiddenFlag) {
   setFlag(file, IS_HIDDEN, hiddenFlag);
   ((VirtualFileSystemEntry) file).updateProperty(VirtualFile.PROP_HIDDEN, hiddenFlag);
 }