Example #1
0
  /** @see org.olat.core.util.vfs.VFSItem#resolveFile(java.lang.String) */
  public static VFSItem resolveFile(VFSContainer rootContainer, String path) {

    path = VFSManager.sanitizePath(path);
    if (path.equals("/")) { // slash or empty path -> return this vfsitem
      return rootContainer;
    }

    // The following code block eliminates directory scans on file-systems,
    // which are done in the original code in the next block, which is left
    // there as a fall-back in case there are non-file-system implementations
    // of OLAT-VFS.
    // OLAT file-systems can be very large and directories can contain
    // quite numerous files. Scanning these can take a lot of time.
    // Just put together the paths of both arguments
    // and ask the file-system whether such an entry
    // exists. If yes, this entry must be exactly what is
    // to be returned as, the proper type of, VFSItem.
    if (rootContainer instanceof LocalFolderImpl) {
      String childName = extractChild(path);
      LocalFolderImpl l = (LocalFolderImpl) rootContainer;
      File t = new File(l.getBasefile().getAbsolutePath(), childName);
      if (t.exists()) {
        String bcroot = FolderConfig.getCanonicalRoot();
        String fsPath = t.getAbsolutePath();
        if (t.isDirectory()) {
          VFSContainer subContainer;
          if (fsPath.startsWith(bcroot)) {
            fsPath = fsPath.substring(bcroot.length(), fsPath.length());
            subContainer = new OlatRootFolderImpl(fsPath, rootContainer);
          } else {
            subContainer = new LocalFolderImpl(t, rootContainer);
          }
          String subPath = path.substring(childName.length() + 1);
          return resolveFile(subContainer, subPath);
        } else {
          if (fsPath.startsWith(bcroot)) {
            fsPath = fsPath.replace(bcroot, "");
            return new OlatRootFileImpl(fsPath, rootContainer);
          } else {
            return new LocalFileImpl(t, rootContainer);
          }
        }
      } else {
        return null;
      }
    }

    // leave original code block as fall-back for non-file-system-based implementations
    String childName = extractChild(path);
    List<VFSItem> children = rootContainer.getItems();
    for (VFSItem child : children) {
      String curName = child.getName();
      if (childName.equals(curName)) { // found , let child further resolve if needed
        return child.resolve(path.substring(childName.length() + 1));
      }
    }
    return null;
  }
Example #2
0
  private static ContainerAndFile findWritableRootFolderForRecursion(
      VFSContainer rootDir, String relFilePath, int recursionLevel) {
    recursionLevel++;
    if (recursionLevel > 20) {
      // Emergency exit condition: a directory hierarchy that has more than 20
      // levels? Probably not..
      log.warn(
          "Reached recursion level while finding writable root Folder - most likely a bug. rootDir::"
              + rootDir
              + " relFilePath::"
              + relFilePath);
      return null;
    }

    if (rootDir instanceof NamedContainerImpl) {
      rootDir = ((NamedContainerImpl) rootDir).getDelegate();
    }
    if (rootDir instanceof MergeSource) {
      MergeSource mergedDir = (MergeSource) rootDir;
      // first check if the next level is not a second MergeSource
      int stop = relFilePath.indexOf("/", 1);
      if (stop > 0) {
        String nextLevel = extractChild(relFilePath);
        VFSItem item = mergedDir.resolve(nextLevel);
        if (item instanceof NamedContainerImpl) {
          item = ((NamedContainerImpl) item).getDelegate();
        }
        if (item instanceof MergeSource) {
          rootDir = (MergeSource) item;
          relFilePath = relFilePath.substring(stop);
          return findWritableRootFolderForRecursion(rootDir, relFilePath, recursionLevel);
        }
      }

      VFSContainer rootWriteContainer = mergedDir.getRootWriteContainer();
      if (rootWriteContainer == null) {
        // we have a merge source without a write container, try it one higher,
        // go through all children of this one and search the correct child in
        // the path
        List<VFSItem> children = rootDir.getItems();
        if (children.isEmpty()) {
          // ups, a merge source without children, no good, return null
          return null;
        }

        String nextChildName = relFilePath.substring(1, relFilePath.indexOf("/", 1));
        for (VFSItem child : children) {
          // look up for the next child in the path
          if (child.getName().equals(nextChildName)) {
            // use this child as new root and remove the child name from the rel
            // path
            if (child instanceof VFSContainer) {
              rootDir = (VFSContainer) child;
              relFilePath = relFilePath.substring(relFilePath.indexOf("/", 1));
              break;
            } else {
              // ups, a merge source with a child that is not a VFSContainer -
              // no good, return null
              return null;
            }
          }
        }
      } else {
        // ok, we found a merge source with a write container
        rootDir = rootWriteContainer;
      }
    }
    if (rootDir != null && rootDir instanceof LocalFolderImpl) {
      // finished, we found a local folder we can use to write
      return new ContainerAndFile(rootDir, relFilePath);
    } else {
      // do recursion
      return findWritableRootFolderForRecursion(rootDir, relFilePath, recursionLevel);
    }
  }
Example #3
0
  /**
   * Get the path as string of the given item relative to the root container and the relative base
   * path
   *
   * @param item the item for which the relative path should be returned
   * @param rootContainer The root container for which the relative path should be calculated
   * @param relativeBasePath when NULL, the path will be calculated relative to the rootContainer;
   *     when NOT NULL, the relativeBasePath must represent a relative path within the root
   *     container that serves as the base. In this case, the calculated relative item path will
   *     start from this relativeBasePath
   * @return
   */
  public static String getRelativeItemPath(
      VFSItem item, VFSContainer rootContainer, String relativeBasePath) {
    // 1) Create path absolute to the root container
    if (item == null) return null;
    String absPath = "";
    VFSItem tmpItem = item;
    // Check for merged containers to fix problems with named containers, see OLAT-3848
    List<NamedContainerImpl> namedRootChilds = new ArrayList<NamedContainerImpl>();
    for (VFSItem rootItem : rootContainer.getItems()) {
      if (rootItem instanceof NamedContainerImpl) {
        namedRootChilds.add((NamedContainerImpl) rootItem);
      }
    }
    // Check if root container is the same as the item and vice versa. It is
    // necessary to perform the check on both containers to catch all potential
    // cases with MergedSource and NamedContainer where the check in one
    // direction is not necessarily the same as the opposite check
    while (tmpItem != null && !rootContainer.isSame(tmpItem) && !tmpItem.isSame(rootContainer)) {
      String itemFileName = tmpItem.getName();
      // fxdiff FXOLAT-125: virtual file system for CP
      if (tmpItem instanceof NamedLeaf) {
        itemFileName = ((NamedLeaf) tmpItem).getDelegate().getName();
      }

      // Special case: check if this is a named container, see OLAT-3848
      for (NamedContainerImpl namedRootChild : namedRootChilds) {
        if (namedRootChild.isSame(tmpItem)) {
          itemFileName = namedRootChild.getName();
        }
      }
      absPath = "/" + itemFileName + absPath;
      tmpItem = tmpItem.getParentContainer();
      if (tmpItem != null) {
        // test if this this is a merge source child container, see OLAT-5726
        VFSContainer grandParent = tmpItem.getParentContainer();
        if (grandParent instanceof MergeSource) {
          MergeSource mergeGrandParent = (MergeSource) grandParent;
          if (mergeGrandParent.isContainersChild((VFSContainer) tmpItem)) {
            // skip this parent container and use the merge grand-parent
            // instead, otherwise path contains the container twice
            tmpItem = mergeGrandParent;
          }
        }
      }
    }

    if (relativeBasePath == null) {
      return absPath;
    }
    // 2) Compute rel path to base dir of the current file

    // selpath = /a/irwas/subsub/nochsub/note.html 5
    // filenam = /a/irwas/index.html 3
    // --> subsub/nochsub/note.gif

    // or /a/irwas/bla/index.html
    // to /a/other/b/gugus.gif
    // --> ../../ other/b/gugus.gif

    // or /a/other/b/main.html
    // to /a/irwas/bla/goto.html
    // --> ../../ other/b/gugus.gif

    String base = relativeBasePath; // assume "/" is here
    if (!(base.indexOf("/") == 0)) {
      base = "/" + base;
    }

    String[] baseA = base.split("/");
    String[] targetA = absPath.split("/");
    int sp = 1;
    for (; sp < Math.min(baseA.length, targetA.length); sp++) {
      if (!baseA[sp].equals(targetA[sp])) {
        break;
      }
    }
    // special case: self-reference
    if (absPath.equals(base)) {
      sp = 1;
    }
    StringBuilder buffer = new StringBuilder();
    for (int i = sp; i < baseA.length - 1; i++) {
      buffer.append("../");
    }
    for (int i = sp; i < targetA.length; i++) {
      buffer.append(targetA[i] + "/");
    }
    buffer.deleteCharAt(buffer.length() - 1);
    String path = buffer.toString();

    String trimmed = path; // selectedPath.substring(1);
    return trimmed;
  }