Пример #1
0
 /**
  * Get the container which security callback affects this item. This searches up the path of
  * parents to see wether it can find any container with a callback. If no callback can be found,
  * null is returned.
  *
  * @param vfsItem
  * @return
  */
 public static VFSContainer findInheritingSecurityCallbackContainer(VFSItem vfsItem) {
   if (vfsItem == null) return null;
   // first resolve delegates of any NamedContainers to get the actual container (might be a
   // MergeSource)
   if (vfsItem instanceof NamedContainerImpl)
     return findInheritingSecurityCallbackContainer(((NamedContainerImpl) vfsItem).getDelegate());
   // special treatment for MergeSource
   if (vfsItem instanceof MergeSource) {
     MergeSource mergeSource = (MergeSource) vfsItem;
     VFSContainer rootWriteContainer = mergeSource.getRootWriteContainer();
     if (rootWriteContainer != null && rootWriteContainer.getLocalSecurityCallback() != null) {
       // if the root write container has a security callback set, it will always override
       // any local securitycallback set on the mergesource
       return rootWriteContainer;
     } else if (mergeSource.getLocalSecurityCallback() != null) {
       return mergeSource;
     } else if (mergeSource.getParentContainer() != null) {
       return findInheritingSecurityCallbackContainer(mergeSource.getParentContainer());
     }
   } else {
     if ((vfsItem instanceof VFSContainer) && (vfsItem.getLocalSecurityCallback() != null))
       return (VFSContainer) vfsItem;
     if (vfsItem.getParentContainer() != null)
       return findInheritingSecurityCallbackContainer(vfsItem.getParentContainer());
   }
   return null;
 }
Пример #2
0
 /**
  * Check the quota usage on this VFSContainer. If no security callback is provided, this returns
  * -1 (meaning no quota on this folder). Similarly, if no quota is defined,
  * VFSSecurityCallback.NO_QUOTA_DEFINED will be returned to signal no quota on this container.
  *
  * @param securityCallback
  * @param container
  * @return
  */
 public static long getQuotaLeftKB(VFSContainer container) {
   VFSContainer inheritingItem = findInheritingSecurityCallbackContainer(container);
   if (inheritingItem == null || inheritingItem.getLocalSecurityCallback().getQuota() == null)
     return Quota.UNLIMITED;
   long usageKB = getUsageKB(inheritingItem);
   return inheritingItem.getLocalSecurityCallback().getQuota().getQuotaKB().longValue() - usageKB;
 }
Пример #3
0
  /**
   * Check if descendant is child of parent or same as parent.
   *
   * @param descendant
   * @param root
   * @return
   */
  public static boolean isSelfOrParent(VFSContainer descendant, VFSContainer parent) {
    if (parent.isSame(descendant)) return true;
    VFSContainer parentContainer = descendant.getParentContainer();
    if (parentContainer != null && parentContainer.isSame(parent)) return true;

    return false;
  }
Пример #4
0
 /**
  * Check if descendant is indeed a descendant of root..
  *
  * @param parent
  * @param child
  * @return
  */
 public static boolean isContainerDescendantOrSelf(VFSContainer descendant, VFSContainer root) {
   if (root.isSame(descendant)) return true;
   VFSContainer parentContainer = descendant.getParentContainer();
   while (parentContainer != null) {
     if (parentContainer.isSame(root)) return true;
     parentContainer = parentContainer.getParentContainer();
   }
   return false;
 }
Пример #5
0
  /**
   * Resolves a file path in the base container or creates this file under the given path. The
   * method creates any missing directories.
   *
   * @param baseContainer The base directory. User must have write permissions on this container
   * @param relFilePath The path relative to the base container. Must start with a '/'. To separate
   *     sub directories use '/'
   * @return The resolved or created leaf or NULL if a problem happened
   */
  public static VFSLeaf resolveOrCreateLeafFromPath(
      VFSContainer baseContainer, String relFilePath) {
    if (StringHelper.containsNonWhitespace(relFilePath)) {
      int lastSlash = relFilePath.lastIndexOf("/");
      String relDirPath = relFilePath;
      String fileName = null;
      if (lastSlash == -1) {
        // relFilePath is the file name - no directories involved
        relDirPath = null;
        fileName = relFilePath;
      } else if (lastSlash == 0) {
        // Remove start slash from file name
        relDirPath = null;
        fileName = relFilePath.substring(1, relFilePath.length());
      } else {
        relDirPath = relFilePath.substring(0, lastSlash);
        fileName = relFilePath.substring(lastSlash);
      }

      // Create missing directories and set parent dir for later file creation
      VFSContainer parent = baseContainer;
      if (StringHelper.containsNonWhitespace(relDirPath)) {
        parent = resolveOrCreateContainerFromPath(baseContainer, relDirPath);
      }
      // Now create file in that dir
      if (StringHelper.containsNonWhitespace(fileName)) {
        VFSLeaf leaf = null;
        VFSItem resolvedFile = parent.resolve(fileName);
        if (resolvedFile == null) {
          leaf = parent.createChildLeaf(fileName);
          if (leaf == null) {
            log.error(
                "Could not create leaf with relPath::"
                    + relFilePath
                    + " in base container::"
                    + getRealPath(baseContainer),
                null);
          }
        } else {
          if (resolvedFile instanceof VFSLeaf) {
            leaf = (VFSLeaf) resolvedFile;
          } else {
            leaf = null;
            log.error(
                "Could not create relPath::"
                    + relFilePath
                    + ", a directory with this name exists (but not a file) in base container::"
                    + getRealPath(baseContainer),
                null);
          }
        }
        return leaf;
      }
    }
    return null;
  }
Пример #6
0
 public static VFSContainer getOrCreateContainer(VFSContainer parent, String name) {
   VFSItem item = parent.resolve(name);
   if (item instanceof VFSContainer) {
     return (VFSContainer) item;
   } else if (item != null) {
     return null; // problem
   } else {
     return parent.createChildContainer(name);
   }
 }
Пример #7
0
 /**
  * Returns a similar but non existing file name in root based on the given name.
  *
  * @param root
  * @param name
  * @return A non existing name based on the given name in the root directory
  */
 public static String similarButNonExistingName(VFSContainer root, String name) {
   VFSItem existingItem = null;
   String newName = name;
   existingItem = root.resolve(newName);
   int i = 1;
   while (existingItem != null) {
     newName = FileUtils.appendNumberAtTheEndOfFilename(name, i++);
     existingItem = root.resolve(newName);
   }
   return newName;
 }
Пример #8
0
 /**
  * @param container
  * @param filename
  * @return
  */
 public static String rename(VFSContainer container, String filename) {
   String newName = filename;
   VFSItem newFile = container.resolve(newName);
   for (int count = 0; newFile != null && count < 999; ) {
     count++;
     newName = FileUtils.appendNumberAtTheEndOfFilename(filename, count);
     newFile = container.resolve(newName);
   }
   if (newFile == null) {
     return newName;
   }
   return null;
 }
Пример #9
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;
  }
Пример #10
0
  /**
   * Check wether this container has a quota assigned to itself.
   *
   * @param container
   * @return Quota if this container has a Quota assigned, null otherwise.
   */
  public static Quota isTopLevelQuotaContainer(VFSContainer container) {
    VFSSecurityCallback callback = container.getLocalSecurityCallback();
    if (callback != null && callback.getQuota() != null) return callback.getQuota();

    // extract delegate if this is a NamedContainer instance...
    if (container instanceof NamedContainerImpl)
      container = ((NamedContainerImpl) container).getDelegate();

    // check if this is a MergeSource with a root write container
    if (container instanceof MergeSource) {
      VFSContainer rwContainer = ((MergeSource) container).getRootWriteContainer();
      if (rwContainer != null
          && rwContainer.getLocalSecurityCallback() != null
          && rwContainer.getLocalSecurityCallback().getQuota() != null)
        return rwContainer.getLocalSecurityCallback().getQuota();
    }
    return null;
  }
Пример #11
0
  /**
   * Copy the content of the source container to the target container.
   *
   * @param source
   * @param target
   * @return
   */
  public static boolean copyContent(VFSContainer source, VFSContainer target) {
    if (!source.exists()) {
      return false;
    }
    if (isSelfOrParent(source, target)) {
      return false;
    }

    if (source instanceof NamedContainerImpl) {
      source = ((NamedContainerImpl) source).getDelegate();
    }
    if (target instanceof NamedContainerImpl) {
      target = ((NamedContainerImpl) target).getDelegate();
    }

    if (source instanceof LocalImpl && target instanceof LocalImpl) {
      LocalImpl localSource = (LocalImpl) source;
      LocalImpl localTarget = (LocalImpl) target;
      File localSourceFile = localSource.getBasefile();
      File localTargetFile = localTarget.getBasefile();
      return FileUtils.copyDirContentsToDir(localSourceFile, localTargetFile, false, "VFScopyDir");
    }
    return false;
  }
Пример #12
0
 /** @see org.olat.core.util.vfs.VFSItem#canRename() */
 public VFSStatus canRename() {
   VFSContainer inheritingContainer = VFSManager.findInheritingSecurityCallbackContainer(this);
   if (inheritingContainer != null && !inheritingContainer.getLocalSecurityCallback().canWrite())
     return VFSConstants.NO_SECURITY_DENIED;
   return VFSConstants.YES;
 }
Пример #13
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);
    }
  }
Пример #14
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;
  }
Пример #15
0
 /**
  * Resolves a directory path in the base container or creates this directory. The method creates
  * any missing directories.
  *
  * @param baseContainer The base directory. User must have write permissions on this container
  * @param relContainerPath The path relative to the base container. Must start with a '/'. To
  *     separate sub directories use '/'
  * @return The resolved or created container or NULL if a problem happened
  */
 public static VFSContainer resolveOrCreateContainerFromPath(
     VFSContainer baseContainer, String relContainerPath) {
   VFSContainer resultContainer = baseContainer;
   if (!VFSConstants.YES.equals(baseContainer.canWrite())) {
     log.error(
         "Could not create relPath::"
             + relContainerPath
             + ", base container::"
             + getRealPath(baseContainer)
             + " not writable",
         null);
     resultContainer = null;
   } else if (StringHelper.containsNonWhitespace(relContainerPath)) {
     // Try to resolve given rel path from current container
     VFSItem resolvedPath = baseContainer.resolve(relContainerPath.trim());
     if (resolvedPath == null) {
       // Does not yet exist - create subdir
       String[] pathSegments = relContainerPath.split("/");
       for (int i = 0; i < pathSegments.length; i++) {
         String segment = pathSegments[i].trim();
         if (StringHelper.containsNonWhitespace(segment)) {
           resolvedPath = resultContainer.resolve(segment);
           if (resolvedPath == null) {
             resultContainer = resultContainer.createChildContainer(segment);
             if (resultContainer == null) {
               log.error(
                   "Could not create container with name::"
                       + segment
                       + " in relPath::"
                       + relContainerPath
                       + " in base container::"
                       + getRealPath(baseContainer),
                   null);
               break;
             }
           } else {
             if (resolvedPath instanceof VFSContainer) {
               resultContainer = (VFSContainer) resolvedPath;
             } else {
               resultContainer = null;
               log.error(
                   "Could not create container with name::"
                       + segment
                       + " in relPath::"
                       + relContainerPath
                       + ", a file with this name exists (but not a directory) in base container::"
                       + getRealPath(baseContainer),
                   null);
               break;
             }
           }
         }
       }
     } else {
       // Parent dir already exists,  make sure this is really a container and not a file!
       if (resolvedPath instanceof VFSContainer) {
         resultContainer = (VFSContainer) resolvedPath;
       } else {
         resultContainer = null;
         log.error(
             "Could not create relPath::"
                 + relContainerPath
                 + ", a file with this name exists (but not a directory) in base container::"
                 + getRealPath(baseContainer),
             null);
       }
     }
   }
   return resultContainer;
 }