From f3adfacccd3685a284091ffc1e96a1821d6c0401 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Thu, 19 Sep 2019 13:45:20 +0200
Subject: [PATCH] OO-4261: fix copy method of VFS container with revisions, add
 warns

---
 .../InfoMessageFrontendManagerImpl.java       | 30 ++++++++-------
 .../java/org/olat/core/util/FileUtils.java    |  2 +-
 .../olat/core/util/vfs/LocalFolderImpl.java   | 22 ++++++++---
 .../vfs/filters/VFSVersionsItemFilter.java    | 38 +++++++++++++++++++
 .../java/org/olat/course/CourseFactory.java   |  4 +-
 5 files changed, 73 insertions(+), 23 deletions(-)
 create mode 100644 src/main/java/org/olat/core/util/vfs/filters/VFSVersionsItemFilter.java

diff --git a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java b/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java
index c1a0b035d2c..4d081a057d0 100644
--- a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java
+++ b/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java
@@ -169,21 +169,23 @@ public class InfoMessageFrontendManagerImpl implements InfoMessageFrontendManage
 	
 	private VFSContainer getResourceContainer(OLATResourceable ores) {
 		VFSContainer root = getStoragePath();
-		String type = ores.getResourceableTypeName().toLowerCase();
-		VFSItem typePath = root.resolve(type);
-		if(typePath == null) {
-			typePath = root.createChildContainer(type);
-		}
-		String id = ores.getResourceableId().toString();
-		if(typePath instanceof VFSContainer) {
-			VFSContainer typeContainer = (VFSContainer)typePath;
-			VFSItem resourceItem = typeContainer.resolve(id);
-			if(resourceItem == null) {
-				resourceItem = typeContainer.createChildContainer(id);
+		if(ores != null && ores.getResourceableTypeName() != null) {
+			String type = ores.getResourceableTypeName().toLowerCase();
+			VFSItem typePath = root.resolve(type);
+			if(typePath == null) {
+				typePath = root.createChildContainer(type);
 			}
-			
-			if(resourceItem instanceof VFSContainer) {
-				return (VFSContainer)resourceItem;
+			String id = ores.getResourceableId().toString();
+			if(typePath instanceof VFSContainer) {
+				VFSContainer typeContainer = (VFSContainer)typePath;
+				VFSItem resourceItem = typeContainer.resolve(id);
+				if(resourceItem == null) {
+					resourceItem = typeContainer.createChildContainer(id);
+				}
+				
+				if(resourceItem instanceof VFSContainer) {
+					return (VFSContainer)resourceItem;
+				}
 			}
 		}
 		return null;
diff --git a/src/main/java/org/olat/core/util/FileUtils.java b/src/main/java/org/olat/core/util/FileUtils.java
index 228dd29f049..58cba9304f2 100644
--- a/src/main/java/org/olat/core/util/FileUtils.java
+++ b/src/main/java/org/olat/core/util/FileUtils.java
@@ -953,7 +953,7 @@ public class FileUtils {
 			long tim = System.nanoTime() - s;
 			double dtim = tim == 0 ? 0.5 : tim; // avg of those less than 1 nanoseconds is taken as 0.5 nanoseconds
 			double bps = tot*1000*1000/dtim;
-			log.debug(String.format("cpio %,13d bytes %6.2f ms avg %6.1f Mbps %s%n", tot, dtim/1000/1000, bps/1024, wt));
+			log.debug(String.format("cpio %,13d bytes %6.2f ms avg %6.1f Mbps %s", tot, dtim/1000/1000, bps/1024, wt));
 		}
 		return tot;
 	}
diff --git a/src/main/java/org/olat/core/util/vfs/LocalFolderImpl.java b/src/main/java/org/olat/core/util/vfs/LocalFolderImpl.java
index 3da002f4ae3..085e878ef1c 100644
--- a/src/main/java/org/olat/core/util/vfs/LocalFolderImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/LocalFolderImpl.java
@@ -37,18 +37,19 @@ import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.logging.log4j.Logger;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.commons.services.vfs.VFSRepositoryModule;
 import org.olat.core.commons.services.vfs.VFSRepositoryService;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.AssertException;
-import org.apache.logging.log4j.Logger;
 import org.olat.core.logging.Tracing;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.vfs.filters.VFSItemFilter;
 import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
+import org.olat.core.util.vfs.filters.VFSVersionsItemFilter;
 
 /**
  * Description:<br>
@@ -161,6 +162,7 @@ public class LocalFolderImpl extends LocalImpl implements VFSContainer {
 	 */
 	private VFSStatus copyFrom(VFSItem source, boolean checkQuota) {
 		if (source.canCopy() != VFSConstants.YES) {
+			log.warn("Cannot copy file {} security denied", source);
 			return VFSConstants.NO_SECURITY_DENIED;
 		}
 		
@@ -168,26 +170,32 @@ public class LocalFolderImpl extends LocalImpl implements VFSContainer {
 		File basefile = getBasefile();
 
 		// check if there is already an item with the same name...
-		if (resolve(sourcename) != null)
+		if (resolve(sourcename) != null) {
+			log.warn("Cannot copy file {} name already used", sourcename);
 			return VFSConstants.ERROR_NAME_ALREDY_USED;
+		}
 		
 		// add either file bla.txt or folder blu as a child of this folder
 		if (source instanceof VFSContainer) {
 			// copy recursively
 			VFSContainer sourcecontainer = (VFSContainer)source;
 			// check if this is a containing container...
-			if (VFSManager.isSelfOrParent(sourcecontainer, this))
+			if (VFSManager.isSelfOrParent(sourcecontainer, this)) {
+				log.warn("Cannot copy file {}  overlapping", this);
 				return VFSConstants.ERROR_OVERLAPPING;
+			}
 			
 			// "copy" the container means creating a folder with that name
 			// and let the children copy
 
 			// create the folder
 			LocalFolderImpl rootcopyfolder = new LocalFolderImpl(new File(basefile, sourcename), this);
-			List<VFSItem> children = sourcecontainer.getItems();
+			List<VFSItem> children = sourcecontainer.getItems(new VFSVersionsItemFilter());
 			for (VFSItem chd:children) {
 				VFSStatus status = rootcopyfolder.copyFrom(chd, false);
-				if (status != VFSConstants.SUCCESS) return status;
+				if (status != VFSConstants.SUCCESS) {
+					log.warn("Cannot copy file {} with status {}", chd, status);
+				}
 			}
 		} else if (source instanceof VFSLeaf) {
 			// copy single item
@@ -195,8 +203,10 @@ public class LocalFolderImpl extends LocalImpl implements VFSContainer {
 			// check quota
 			if (checkQuota) {
 				long quotaLeft = VFSManager.getQuotaLeftKB(this);
-				if(quotaLeft != Quota.UNLIMITED && quotaLeft < (s.getSize() / 1024))
+				if(quotaLeft != Quota.UNLIMITED && quotaLeft < (s.getSize() / 1024)) {
+					log.warn("Cannot copy file {} quota exceeded {}", s, quotaLeft);
 					return VFSConstants.ERROR_QUOTA_EXCEEDED;
+				}
 			}
 			
 			File fTarget = new File(basefile, sourcename);
diff --git a/src/main/java/org/olat/core/util/vfs/filters/VFSVersionsItemFilter.java b/src/main/java/org/olat/core/util/vfs/filters/VFSVersionsItemFilter.java
new file mode 100644
index 00000000000..484eaceb5f4
--- /dev/null
+++ b/src/main/java/org/olat/core/util/vfs/filters/VFSVersionsItemFilter.java
@@ -0,0 +1,38 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.util.vfs.filters;
+
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.filters.VFSItemFilter;
+
+/**
+ * 
+ * Initial date: 19 sept. 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class VFSVersionsItemFilter implements VFSItemFilter {
+	
+	@Override
+	public boolean accept(VFSItem vfsItem) {
+		String name = vfsItem.getName();
+		return !name.startsWith("._oo_vr_") && !name.equals("__MACOSX");
+	}
+}
diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java
index 791531add00..7ee85fa2a9d 100644
--- a/src/main/java/org/olat/course/CourseFactory.java
+++ b/src/main/java/org/olat/course/CourseFactory.java
@@ -458,8 +458,8 @@ public class CourseFactory {
 			// copy course folder
 			VFSContainer sourceCourseContainer = sourceCourse.getIsolatedCourseBaseContainer();
 			if (sourceCourseContainer.exists()) {
-				targetCourse.getIsolatedCourseBaseContainer()
-					.copyContentOf(sourceCourseContainer);
+				VFSContainer targetCourseContainer = targetCourse.getIsolatedCourseBaseContainer();
+				targetCourseContainer.copyContentOf(sourceCourseContainer);
 			}
 
 			// copy folder nodes directories
-- 
GitLab