private Versions readVersions(VFSLeaf leaf, VFSLeaf fVersions) {
    if (fVersions == null) {
      return new NotVersioned();
    }

    try {
      VFSContainer fVersionContainer = fVersions.getParentContainer();
      VersionsFileImpl versions = (VersionsFileImpl) XStreamHelper.readObject(mystream, fVersions);
      versions.setVersionFile(fVersions);
      versions.setCurrentVersion((Versionable) leaf);
      if (versions.getRevisionNr() == null || versions.getRevisionNr().length() == 0) {
        versions.setRevisionNr(getNextRevisionNr(versions));
      }

      for (VFSRevision revision : versions.getRevisions()) {
        RevisionFileImpl revisionImpl = (RevisionFileImpl) revision;
        revisionImpl.setContainer(fVersionContainer);
      }
      return versions;
    } catch (Exception e) {
      log.warn("This file is not a versions XML file: " + fVersions, e);
      fVersions.delete();
      VersionsFileImpl versions = new VersionsFileImpl();
      versions.setCurrentVersion((Versionable) leaf);
      versions.setVersioned(isVersioned(leaf));
      versions.setRevisionNr(getNextRevisionNr(versions));
      log.warn("Deleted corrupt version XML file and created new version XML file: " + versions);
      // the old revisions can not be restored automatically. They are still on disk, you could
      // recover them
      // manually. This is not a perfect solution, but at least the user does not get an RS
      return versions;
    }
  }
  /**
   * Clean up all revisions files, xml file
   *
   * @param leaf
   */
  private void cleanUp(VFSLeaf leaf) {
    String relPath = getRelPath(leaf);
    if (relPath == null) return; // cannot handle

    File fVersion = new File(getRootVersionsFile(), relPath + ".xml");
    File fParentVersion = fVersion.getParentFile();
    if (!fParentVersion.exists()) return; // already deleted

    VFSLeaf versionLeaf = null;
    if (fVersion.exists()) {
      LocalFolderImpl localVersionContainer = new LocalFolderImpl(fParentVersion);
      versionLeaf = (VFSLeaf) localVersionContainer.resolve(fVersion.getName());
    }

    if (versionLeaf == null) return; // already deleted
    Versions versions = readVersions(leaf, versionLeaf);
    for (VFSRevision versionToDelete : versions.getRevisions()) {
      RevisionFileImpl versionImpl = (RevisionFileImpl) versionToDelete;
      VFSLeaf fileToDelete = versionImpl.getFile();
      if (fileToDelete != null) {
        fileToDelete.delete();
      }
    }
    versionLeaf.delete();
  }
  @Override
  public boolean move(Versionable currentVersion, VFSContainer container) {
    VFSLeaf currentFile = (VFSLeaf) currentVersion;
    VFSLeaf fVersions = getCanonicalVersionXmlFile(currentFile, true);
    Versions versions = readVersions(currentFile, fVersions);

    VFSContainer versionContainer = getCanonicalVersionFolder(container, true);

    boolean allOk = VFSConstants.YES.equals(versionContainer.copyFrom(fVersions));
    for (VFSRevision revision : versions.getRevisions()) {
      RevisionFileImpl revisionImpl = (RevisionFileImpl) revision;
      VFSLeaf revisionFile = revisionImpl.getFile();
      if (revisionFile != null) {
        allOk &= VFSConstants.YES.equals(versionContainer.copyFrom(revisionFile));
      }
    }

    allOk &= VFSConstants.YES.equals(fVersions.delete());
    for (VFSRevision revision : versions.getRevisions()) {
      VFSLeaf revisionFile = ((RevisionFileImpl) revision).getFile();
      if (revisionFile != null) {
        allOk &= VFSConstants.YES.equals(revisionFile.delete());
      }
    }
    return allOk;
  }
  private boolean isVersionsXmlFile(VFSLeaf fVersions) {
    if (fVersions == null || !fVersions.exists()) {
      return false;
    }
    InputStream in = fVersions.getInputStream();
    if (in == null) {
      return false;
    }

    Scanner scanner = new Scanner(in);
    scanner.useDelimiter(TAG_PATTERN);

    boolean foundVersionsTag = false;
    while (scanner.hasNext()) {
      String tag = scanner.next();
      if ("versions".equals(tag)) {
        foundVersionsTag = true;
        break;
      }
    }

    scanner.close();
    IOUtils.closeQuietly(in);
    return foundVersionsTag;
  }
  private boolean isSameFile(VFSLeaf currentFile, VersionsFileImpl versions) {
    boolean same = false;
    if (versions.getRevisions() != null && !versions.getRevisions().isEmpty()) {
      VFSRevision lastRevision = versions.getRevisions().get(versions.getRevisions().size() - 1);

      long lastSize = lastRevision.getSize();
      long currentSize = currentFile.getSize();
      if (currentSize == lastSize
          && currentSize > 0
          && lastRevision instanceof RevisionFileImpl
          && currentFile instanceof LocalFileImpl) {
        RevisionFileImpl lastRev = ((RevisionFileImpl) lastRevision);
        LocalFileImpl current = (LocalFileImpl) currentFile;
        // can be the same file
        try {
          Checksum cm1 =
              FileUtils.checksum(((LocalFileImpl) lastRev.getFile()).getBasefile(), new Adler32());
          Checksum cm2 = FileUtils.checksum(current.getBasefile(), new Adler32());
          same = cm1.getValue() == cm2.getValue();
        } catch (IOException e) {
          log.debug("Error calculating the checksum of files");
        }
      }
    }
    return same;
  }
  /**
   * Some temporary/lock files of specific editors need to be force deleted with all versions. Word
   * can reuse older names.
   *
   * @param leaf
   * @return
   */
  private boolean isTemporaryFile(VFSLeaf leaf) {
    String name = leaf.getName();
    // temporary files
    if (name.endsWith(".tmp")) {
      // Word 2010: ~WRD0002.tmp
      if (name.startsWith("~WRD") || name.startsWith("~WRL")) {
        return true;
      }
      // PowerPoint 2010: ppt5101.tmp
      if (name.startsWith("ppt")) {
        return true;
      }
    }
    // lock files of Word 2010, Excel 2010, PowerPoint 2010:
    if (name.startsWith("~$")
        && (name.endsWith(".docx") || name.endsWith(".xlsx") || name.endsWith(".pptx"))) {
      return true;
    }

    // OpenOffice locks: .~lock.Versions_21.odt#
    if (name.startsWith(".~lock.")
        && (name.endsWith(".odt#") /* Writer */
            || name.endsWith(".ods#") /* Calc */
            || name.endsWith(".odp#") /* Impress */
            || name.endsWith("odf#") /* Math */
            || name.endsWith(".odg#") /* Draw */)) {
      return true;
    }
    // OpenOffice database lock
    if (name.endsWith(".odb.lck")) {
      return true;
    }

    return false;
  }
  @Override
  public boolean delete(OrphanVersion orphan) {
    VFSLeaf versionLeaf = orphan.getVersionsLeaf();

    if (versionLeaf == null) return true; // already deleted
    Versions versions = orphan.getVersions();
    for (VFSRevision versionToDelete : versions.getRevisions()) {
      RevisionFileImpl versionImpl = (RevisionFileImpl) versionToDelete;
      versionImpl.setContainer(orphan.getVersionsLeaf().getParentContainer());
      VFSLeaf fileToDelete = versionImpl.getFile();
      if (fileToDelete != null) {
        fileToDelete.delete();
      }
    }
    versionLeaf.delete();
    return true;
  }
 private void pruneVersionHistory(
     VFSLeaf versionsLeaf, long maxHistoryLength, ProgressDelegate progress) {
   if (versionsLeaf.getName().endsWith(".xml") && isVersionsXmlFile(versionsLeaf)) {
     File originalFile = reversedOriginFile(versionsLeaf);
     if (originalFile.exists()) {
       VFSLeaf original = new LocalFileImpl(originalFile);
       if (progress != null) progress.setInfo(original.getName());
       Versions versions = readVersions(original, versionsLeaf);
       List<VFSRevision> revisions = versions.getRevisions();
       if (revisions.size() > maxHistoryLength) {
         List<VFSRevision> revisionsToDelete =
             revisions.subList(0, revisions.size() - (int) maxHistoryLength);
         deleteRevisions((Versionable) original, revisionsToDelete);
       }
     }
   }
 }
 @Override
 public boolean rename(VFSItem item, String newname) {
   if (item instanceof VFSLeaf) {
     VFSLeaf currentFile = (VFSLeaf) item;
     VFSLeaf versionFile = getCanonicalVersionXmlFile(currentFile, true);
     // infinite loop if rename is own versions file
     return VFSConstants.YES.equals(versionFile.rename(newname + ".xml"));
   } else if (item instanceof VFSContainer) {
     VFSContainer container = (VFSContainer) item;
     VFSContainer versionContainer = getCanonicalVersionFolder(container, false);
     if (versionContainer == null) {
       return true;
     }
     return VFSConstants.YES.equals(versionContainer.rename(newname));
   }
   return false;
 }
Example #10
0
 @Override
 public boolean deleteVersions(List<Versions> versions) {
   for (Versions versionToDelete : versions) {
     if (versionToDelete instanceof VersionsFileImpl) {
       VersionsFileImpl versionsImpl = (VersionsFileImpl) versionToDelete;
       VFSLeaf versionFile = versionsImpl.getVersionFile();
       if (versionFile != null) {
         // robust against manual file system manipulation
         versionFile.deleteSilently();
       }
       for (VFSRevision revisionToDelete : versionsImpl.getRevisions()) {
         RevisionFileImpl versionImpl = (RevisionFileImpl) revisionToDelete;
         VFSLeaf fileToDelete = versionImpl.getFile();
         if (fileToDelete != null) {
           fileToDelete.deleteSilently();
         }
       }
     }
   }
   return true;
 }
Example #11
0
 private Versions isOrphan(VFSLeaf potentialOrphan) {
   try {
     if (potentialOrphan.exists()) {
       VersionsFileImpl versions =
           (VersionsFileImpl) XStreamHelper.readObject(mystream, potentialOrphan);
       return versions;
     }
     return null;
   } catch (Exception e) {
     return null;
   }
 }
 @Override
 public boolean isThumbnailPossible(VFSLeaf file) {
   String extension = FileUtils.getFileSuffix(file.getName());
   if (StringHelper.containsNonWhitespace(extension)) {
     for (ThumbnailSPI thumbnailSPI : thumbnailSPIes) {
       if (thumbnailSPI.getExtensions().contains(extension)) {
         return true;
       }
     }
   }
   return false;
 }
 @Override
 public FinalSize generateThumbnail(
     VFSLeaf file, VFSLeaf thumbnailFile, int maxWidth, int maxHeight)
     throws CannotGenerateThumbnailException {
   String extension = FileUtils.getFileSuffix(file.getName()).toLowerCase();
   for (ThumbnailSPI thumbnailSPI : thumbnailSPIes) {
     if (thumbnailSPI.getExtensions().contains(extension)) {
       FinalSize finalSize =
           thumbnailSPI.generateThumbnail(file, thumbnailFile, maxWidth, maxHeight);
       if (finalSize != null) {
         return finalSize;
       } // else, try to find an other SPI which can thumbnailed this file
     }
   }
   return null;
 }
Example #14
0
  @Override
  public boolean deleteRevisions(Versionable currentVersion, List<VFSRevision> versionsToDelete) {
    VFSLeaf currentFile = (VFSLeaf) currentVersion;
    Versions versions = readVersions(currentFile, true);
    List<VFSRevision> allVersions = versions.getRevisions();

    Map<String, VFSLeaf> filenamesToDelete = new HashMap<String, VFSLeaf>(allVersions.size());
    for (VFSRevision versionToDelete : versionsToDelete) {
      RevisionFileImpl versionImpl = (RevisionFileImpl) versionToDelete;
      for (Iterator<VFSRevision> allVersionIt = allVersions.iterator(); allVersionIt.hasNext(); ) {
        RevisionFileImpl allVersionImpl = (RevisionFileImpl) allVersionIt.next();
        if (allVersionImpl.getFilename() != null
            && allVersionImpl.getFilename().equals(versionImpl.getFilename())) {
          allVersionIt.remove();
          break;
        }
      }

      VFSLeaf fileToDelete = versionImpl.getFile();
      if (fileToDelete != null) {
        filenamesToDelete.put(fileToDelete.getName(), fileToDelete);
      }
    }

    List<RevisionFileImpl> missingFiles = new ArrayList<>();
    for (VFSRevision survivingVersion : allVersions) {
      RevisionFileImpl survivingVersionImpl = (RevisionFileImpl) survivingVersion;
      VFSLeaf revFile = survivingVersionImpl.getFile();
      if (revFile == null) {
        missingFiles.add(survivingVersionImpl); // file is missing
      } else if (filenamesToDelete.containsKey(revFile.getName())) {
        filenamesToDelete.remove(revFile.getName());
      }
    }
    if (missingFiles.size() > 0) {
      allVersions.removeAll(missingFiles);
    }

    for (VFSLeaf fileToDelete : filenamesToDelete.values()) {
      fileToDelete.deleteSilently();
    }

    VFSLeaf versionFile = getCanonicalVersionXmlFile(currentFile, true);
    XStreamHelper.writeObject(mystream, versionFile, versions);
    if (currentVersion.getVersions() instanceof VersionsFileImpl) {
      ((VersionsFileImpl) currentVersion.getVersions()).update(versions);
    }
    return true;
  }
Example #15
0
  private boolean copyRevision(
      VFSRevision revision, VFSLeaf fNewVersions, VersionsFileImpl targetVersions) {
    if (!(revision instanceof RevisionFileImpl)) {
      logWarn("Copy only copy persisted revisions", null);
    }

    RevisionFileImpl revisionImpl = (RevisionFileImpl) revision;
    String revUuid = revisionImpl.getUuid();
    for (VFSRevision rev : targetVersions.getRevisions()) {
      if (rev instanceof RevisionFileImpl) {
        RevisionFileImpl fRev = (RevisionFileImpl) rev;
        if (StringHelper.containsNonWhitespace(fRev.getUuid()) && fRev.getUuid().equals(revUuid)) {
          return true;
        }
      }
    }

    String uuid = UUID.randomUUID().toString().replace("-", "") + "_" + revision.getName();

    RevisionFileImpl newRevision = new RevisionFileImpl();
    newRevision.setName(revision.getName());
    newRevision.setFilename(uuid);
    newRevision.setRevisionNr(getNextRevisionNr(targetVersions));
    newRevision.setComment(revision.getComment());
    newRevision.setAuthor(revision.getAuthor());
    newRevision.setLastModified(revision.getLastModified());
    newRevision.setUuid(revUuid);

    // copy -> the files revision
    InputStream revisionIn = revision.getInputStream();

    VFSLeaf target = fNewVersions.getParentContainer().createChildLeaf(uuid);
    if (VFSManager.copyContent(revisionIn, target)) {
      targetVersions.setComment(revision.getComment());
      targetVersions.getRevisions().add(newRevision);
      targetVersions.setRevisionNr(getNextRevisionNr(targetVersions));
      targetVersions.setAuthor(revision.getAuthor());
      return true;
    }
    return false;
  }
Example #16
0
  /**
   * @see
   *     org.olat.core.util.vfs.version.VersionsManager#addToRevisions(org.olat.core.util.vfs.version.Versionable,
   *     org.olat.core.id.Identity, java.lang.String)
   */
  @Override
  public boolean addToRevisions(Versionable currentVersion, Identity identity, String comment) {
    int maxNumOfVersions = versioningConfigurator.getMaxNumOfVersionsAllowed();
    if (maxNumOfVersions == 0) {
      return true; // deactivated, return all ok
    }

    VFSLeaf currentFile = (VFSLeaf) currentVersion;

    VFSLeaf versionFile = getCanonicalVersionXmlFile(currentFile, true);
    if (versionFile == null) {
      return false; // cannot do something with the current file
    }

    VFSContainer versionContainer = versionFile.getParentContainer();

    String name = currentFile.getName();

    // read from the
    Versions v = readVersions(currentFile, versionFile);
    if (!(v instanceof VersionsFileImpl)) {
      log.error("Wrong implementation of Versions: " + v);
      return false;
    }
    VersionsFileImpl versions = (VersionsFileImpl) v;
    boolean sameFile = isSameFile(currentFile, versions);
    String uuid =
        sameFile ? getLastRevisionFilename(versions) : UUID.randomUUID().toString() + "_" + name;

    String versionNr = getNextRevisionNr(versions);
    String currentAuthor = versions.getAuthor();
    long lastModifiedDate = 0;
    if (currentFile instanceof MetaTagged) {
      MetaInfo metaInfo = ((MetaTagged) currentFile).getMetaInfo();
      if (metaInfo != null) {
        metaInfo.clearThumbnails();
        if (currentAuthor == null) {
          currentAuthor = metaInfo.getAuthor();
        }
        lastModifiedDate = metaInfo.getLastModified();
      }
    }

    if (lastModifiedDate <= 0) {
      Calendar cal = Calendar.getInstance();
      cal.setTime(new Date());
      lastModifiedDate = cal.getTimeInMillis();
    }

    RevisionFileImpl newRevision = new RevisionFileImpl();
    newRevision.setUuid(UUID.randomUUID().toString());
    newRevision.setName(name);
    newRevision.setFilename(uuid);
    newRevision.setRevisionNr(versionNr);
    newRevision.setComment(versions.getComment());
    newRevision.setAuthor(currentAuthor);
    newRevision.setLastModified(lastModifiedDate);

    if (versions.getRevisions().isEmpty() && currentVersion instanceof MetaTagged) {
      MetaTagged metaTagged = (MetaTagged) currentVersion;
      versions.setCreator(metaTagged.getMetaInfo().getAuthor());
    }

    if (sameFile || VFSManager.copyContent(currentFile, versionContainer.createChildLeaf(uuid))) {
      if (identity != null) {
        versions.setAuthor(identity.getName());
      }

      if (maxNumOfVersions >= 0 && versions.getRevisions().size() >= maxNumOfVersions) {
        List<VFSRevision> revisions = versions.getRevisions();
        int numOfVersionsToDelete =
            Math.min(revisions.size(), (revisions.size() - maxNumOfVersions) + 1);
        if (numOfVersionsToDelete > 0) {
          List<VFSRevision> versionsToDelete = revisions.subList(0, numOfVersionsToDelete);
          deleteRevisions(currentVersion, versionsToDelete);
          versions = (VersionsFileImpl) currentVersion.getVersions();
        }
      }
      versions.setComment(comment);
      versions.getRevisions().add(newRevision);
      versions.setRevisionNr(getNextRevisionNr(versions));
      XStreamHelper.writeObject(mystream, versionFile, versions);
      if (currentVersion.getVersions() instanceof VersionsFileImpl) {
        ((VersionsFileImpl) currentVersion.getVersions()).update(versions);
      }
      return true;
    } else {
      log.error("Cannot create a version of this file: " + currentVersion);
    }
    return false;
  }