@SuppressWarnings({"HardCodedStringLiteral"})
  @Nullable
  public static VirtualFile findRelativeFile(@NotNull String uri, @Nullable VirtualFile base) {
    if (base != null) {
      if (!base.isValid()) {
        LOG.error("Invalid file name: " + base.getName() + ", url: " + uri);
      }
    }

    uri = uri.replace('\\', '/');

    if (uri.startsWith("file:///")) {
      uri = uri.substring("file:///".length());
      if (!SystemInfo.isWindows) uri = "/" + uri;
    } else if (uri.startsWith("file:/")) {
      uri = uri.substring("file:/".length());
      if (!SystemInfo.isWindows) uri = "/" + uri;
    } else if (uri.startsWith("file:")) {
      uri = uri.substring("file:".length());
    }

    VirtualFile file = null;

    if (uri.startsWith("jar:file:/")) {
      uri = uri.substring("jar:file:/".length());
      if (!SystemInfo.isWindows) uri = "/" + uri;
      file = VirtualFileManager.getInstance().findFileByUrl(JarFileSystem.PROTOCOL_PREFIX + uri);
    } else {
      if (!SystemInfo.isWindows && StringUtil.startsWithChar(uri, '/')) {
        file = LocalFileSystem.getInstance().findFileByPath(uri);
      } else if (SystemInfo.isWindows
          && uri.length() >= 2
          && Character.isLetter(uri.charAt(0))
          && uri.charAt(1) == ':') {
        file = LocalFileSystem.getInstance().findFileByPath(uri);
      }
    }

    if (file == null && uri.contains(JarFileSystem.JAR_SEPARATOR)) {
      file = JarFileSystem.getInstance().findFileByPath(uri);
      if (file == null && base == null) {
        file = VirtualFileManager.getInstance().findFileByUrl(uri);
      }
    }

    if (file == null) {
      if (base == null) return LocalFileSystem.getInstance().findFileByPath(uri);
      if (!base.isDirectory()) base = base.getParent();
      if (base == null) return LocalFileSystem.getInstance().findFileByPath(uri);
      file = VirtualFileManager.getInstance().findFileByUrl(base.getUrl() + "/" + uri);
      if (file == null) return null;
    }

    return file;
  }
 private static VirtualFile doCreateDirectoriesIfMissing(String dir) throws IOException {
   final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByPath(dir);
   if (file == null) {
     int pos = dir.lastIndexOf('/');
     if (pos < 0) return null;
     VirtualFile parent = createDirectoryIfMissing(dir.substring(0, pos));
     if (parent == null) return null;
     final String dirName = dir.substring(pos + 1);
     return parent.createChildDirectory(LocalFileSystem.getInstance(), dirName);
   }
   return file;
 }
 @Nullable
 public static VirtualFile findFileByIoFile(@NotNull File file, boolean refreshIfNeeded) {
   LocalFileSystem fileSystem = LocalFileSystem.getInstance();
   VirtualFile virtualFile = fileSystem.findFileByIoFile(file);
   if (virtualFile == null && refreshIfNeeded) {
     virtualFile = fileSystem.refreshAndFindFileByIoFile(file);
   }
   return virtualFile;
 }
 public static String getUrlForLibraryRoot(@NotNull File libraryRoot) {
   String path = FileUtil.toSystemIndependentName(libraryRoot.getAbsolutePath());
   if (FileTypeManager.getInstance().getFileTypeByFileName(libraryRoot.getName())
       == FileTypes.ARCHIVE) {
     return VirtualFileManager.constructUrl(
         JarFileSystem.getInstance().getProtocol(), path + JarFileSystem.JAR_SEPARATOR);
   } else {
     return VirtualFileManager.constructUrl(LocalFileSystem.getInstance().getProtocol(), path);
   }
 }
 public static VirtualFile createDirectoryIfMissing(VirtualFile parent, String relativePath)
     throws IOException {
   for (String each : StringUtil.split(relativePath, "/")) {
     VirtualFile child = parent.findChild(each);
     if (child == null) {
       child = parent.createChildDirectory(LocalFileSystem.getInstance(), each);
     }
     parent = child;
   }
   return parent;
 }
  public static void markDirtyAndRefresh(
      boolean async, boolean recursive, boolean loadChildren, VirtualFile... files) {
    List<VirtualFile> list = ContainerUtil.filter(Condition.NOT_NULL, files);
    if (list.isEmpty()) {
      return;
    }

    for (VirtualFile file : list) {
      if (loadChildren) {
        file.getChildren();
      }

      if (file instanceof NewVirtualFile) {
        if (recursive) {
          ((NewVirtualFile) file).markDirtyRecursively();
        } else {
          ((NewVirtualFile) file).markDirty();
        }
      }
    }

    LocalFileSystem.getInstance().refreshFiles(list, async, recursive, null);
  }
  @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;
  }
 @Nullable
 public static VirtualFile getUserHomeDir() {
   final String path = SystemProperties.getUserHome();
   return LocalFileSystem.getInstance().findFileByPath(FileUtil.toSystemIndependentName(path));
 }
  @Override
  @Nullable
  public VirtualFileSystemEntry findRoot(
      @NotNull String basePath, @NotNull NewVirtualFileSystem fs) {
    String rootUrl = normalizeRootUrl(basePath, fs);
    boolean isFakeRoot = basePath.isEmpty();
    VirtualFileSystemEntry root;

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

    myRootsLock.writeLock().lock();
    try {
      root = isFakeRoot ? mySuperRoot : myRoots.get(rootUrl);
      if (root != null) return root;

      int rootId = FSRecords.findRootRecord(rootUrl);
      root = myRootsById.get(rootId);
      if (root != null) return root;

      if (isFakeRoot) {
        // fake super-root
        root = new FakeRoot(fs, rootId);
      } else if (fs instanceof JarFileSystem) {
        // optimization: for jar roots do not store base path in the myName field, use local FS
        // file's getPath()
        String parentPath = basePath.substring(0, basePath.indexOf(JarFileSystem.JAR_SEPARATOR));
        VirtualFile parentLocalFile = LocalFileSystem.getInstance().findFileByPath(parentPath);
        if (parentLocalFile == null) return null;

        // check one more time since the findFileByPath could have created the root (by reentering
        // the findRoot)
        root = myRoots.get(rootUrl);
        if (root != null) return root;
        root = myRootsById.get(rootId);
        if (root != null) return root;

        root = new JarRoot(fs, rootId, parentLocalFile);
      } else {
        root = new FsRoot(fs, rootId, basePath);
      }

      if (isFakeRoot) {
        mySuperRoot = root;
      } else {
        FileAttributes attributes = fs.getAttributes(root);
        if (attributes == null || !attributes.isDirectory()) {
          return null;
        }
        final boolean newRoot = writeAttributesToRecord(rootId, 0, root, fs, attributes);
        if (!newRoot && attributes.lastModified != FSRecords.getTimestamp(rootId)) {
          root.markDirtyRecursively();
        }

        myRoots.put(rootUrl, root);
        myRootsById.put(rootId, root);

        if (rootId != root.getId()) throw new AssertionError();
      }

      return root;
    } finally {
      myRootsLock.writeLock().unlock();
    }
  }