diff --git a/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java b/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java
index dcb0f629b30a4fba97b46f9de419599c6444ae67..fdfa27c7afbfe92379872331361dd3bbfca3ec8b 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java
@@ -22,7 +22,6 @@ package org.olat.core.commons.modules.bc;
 
 import static java.util.Arrays.asList;
 
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.controllers.linkchooser.FileLinkChooserController;
 import org.olat.core.commons.controllers.linkchooser.LinkChooserController;
 import org.olat.core.commons.controllers.linkchooser.URLChoosenEvent;
@@ -46,15 +45,14 @@ import org.olat.core.logging.activity.CoreLoggingResourceable;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.Util;
-import org.olat.core.util.vfs.VFSConstants;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSLockManager;
 import org.olat.core.util.vfs.VFSManager;
-import org.olat.core.util.vfs.meta.MetaInfo;
 import org.olat.core.util.vfs.version.Versionable;
 import org.olat.core.util.vfs.version.Versions;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -79,13 +77,13 @@ public class FileCopyController extends LinkChooserController {
 	private VFSLeaf existingVFSItem;
 	private String renamedFilename;
 	
-	private final VFSLockManager vfsLockManager;
+	@Autowired
+	private VFSLockManager vfsLockManager;
 	
 	public FileCopyController(UserRequest ureq, WindowControl wControl, VFSContainer rootDir,
 			FolderComponent folderComponent) {
 		super(ureq, wControl, rootDir, null, null, null, false, "", null, true);
 		this.folderComponent = folderComponent;
-		vfsLockManager = CoreSpringFactory.getImpl(VFSLockManager.class);
 	}
 	
 	@Override
@@ -287,21 +285,12 @@ public class FileCopyController extends LinkChooserController {
 	}
 	
 	private void finishUpload(UserRequest ureq) {
-		VFSManager.copyContent(sourceLeaf, newFile);
+		VFSManager.copyContent(sourceLeaf, newFile, true);
 		finishSuccessfullUpload(newFile.getName(), ureq);
 	}
 	
 	private void finishSuccessfullUpload(String fileName, UserRequest ureq) {
-		VFSContainer currentContainer  = folderComponent.getCurrentContainer();
-		VFSItem item = currentContainer.resolve(fileName);
-		if (item instanceof VFSLeaf && item.canMeta() == VFSConstants.YES) {
-			MetaInfo meta = item.getMetaInfo();
-			meta.setAuthor(ureq.getIdentity());
-			meta.clearThumbnails();//if overwrite an older file
-			meta.write();
-		}
 		ThreadLocalUserActivityLogger.log(FolderLoggingAction.FILE_COPIED, getClass(), CoreLoggingResourceable.wrapUploadFile(fileName));
-
 		// Notify listeners about upload
 		fireEvent(ureq, new FolderEvent(FolderEvent.NEW_FILE_EVENT, newFile.getName()));
 		fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
diff --git a/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java b/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java
index 04b35930c4c7c48aeb6397a5f43e9348839f42a6..f5a1cdbfcd78011148aca8296e4f0042c0e15333 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java
@@ -733,8 +733,7 @@ public class FileUploadController extends FormBasicController {
 				meta = metaDataCtr.getMetaInfo(meta);
 			}
 			meta.setAuthor(getIdentity());
-			meta.clearThumbnails();//if overwrite an older file
-			meta.write();
+			meta.clearThumbnails();//clear write the meta
 		}
 		
 		if(item == null) {
diff --git a/src/main/java/org/olat/core/commons/modules/bc/FolderConfig.java b/src/main/java/org/olat/core/commons/modules/bc/FolderConfig.java
index 2ccdf9b17fcf80b69de3c8c40c6de3a1792d7c7e..82ec617ed21f5ccc0f7d484fa86758e737cb336d 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/FolderConfig.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/FolderConfig.java
@@ -273,12 +273,20 @@ public class FolderConfig {
 		return getCanonicalRoot() + META_DIR;
 	}
 	
+	public static Path getCanonicalMetaRootPath() {
+		return Paths.get(getCanonicalRoot(), META_DIR);
+	}
+	
 	/**
 	 * @return the canonical path to the version root directory
 	 */
 	public static String getCanonicalVersionRoot() {
 		return getCanonicalRoot() + VERSION_DIR;
 	}
+	
+	public static Path getCanonicalVersionRootPath() {
+		return Paths.get(getCanonicalRoot(), VERSION_DIR);
+	}
 
 	/**
 	 * @return the canonical path to the repository root directory.
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditMeta.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditMeta.java
index 0aafeebc5419e4989baa00f0d54eef18cdbda84c..0f3ffbba8c1f867df27d9abcfbca1c1b715b1d9d 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditMeta.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditMeta.java
@@ -159,7 +159,6 @@ public class CmdEditMeta extends BasicController implements FolderCommand {
 						getWindowControl().setError(translator.translate("TargetNameAlreadyUsed"));
 						status = FolderCommandStatus.STATUS_FAILED;
 					} else {
-						meta.rename(fileName);
 						if(VFSConstants.NO.equals(currentItem.rename(fileName))) {
 							getWindowControl().setError(translator.translate("FileRenameFailed", new String[]{fileName}));
 							status = FolderCommandStatus.STATUS_FAILED;
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdMoveCopy.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdMoveCopy.java
index ab0063c6523688e79abb1fdcecbd0bf2cc86ce3a..54abca308b41debdf28ea1bd466a960e9dfef0b9 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdMoveCopy.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdMoveCopy.java
@@ -90,7 +90,7 @@ public class CmdMoveCopy extends DefaultController implements FolderCommand {
 		main.contextPut("fileselection", fileSelection);
 		
 		//check if command is executed on a file list containing invalid filenames or paths
-		if(fileSelection.getInvalidFileNames().size()>0) {		
+		if(!fileSelection.getInvalidFileNames().isEmpty()) {		
 			main.contextPut("invalidFileNames", fileSelection.getInvalidFileNames());
 		}		
 
@@ -135,10 +135,10 @@ public class CmdMoveCopy extends DefaultController implements FolderCommand {
 
 	public String getTarget() {
 		FolderTreeModel ftm = (FolderTreeModel) selTree.getTreeModel();
-		String selectedPath = ftm.getSelectedPath(selTree.getSelectedNode());
-		return selectedPath;
+		return ftm.getSelectedPath(selTree.getSelectedNode());
 	}
 
+	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		if(cancelButton == source) {
 			status = FolderCommandStatus.STATUS_CANCELED;
@@ -167,13 +167,7 @@ public class CmdMoveCopy extends DefaultController implements FolderCommand {
 		List<VFSItem> sources = getSanityCheckedSourceItems(target, ureq);
 		if (sources == null) return;
 		
-		boolean targetIsRelPath = (target.getRelPath() != null);
 		for (VFSItem vfsSource:sources) {
-			if (targetIsRelPath && (vfsSource.canMeta() == VFSConstants.YES)) {
-				// copy the metainfo first
-				vfsSource.getMetaInfo().moveCopyToDir(target, move);
-			}
-			
 			VFSItem targetFile = target.resolve(vfsSource.getName());
 			if(vfsSource instanceof VFSLeaf && targetFile != null && targetFile instanceof Versionable
 					&& ((Versionable)targetFile).getVersions().isVersioned()) {
diff --git a/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java b/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java
index 3a72e5149ca3783761e5331ca04650a104269e89..55a441ce039cb9d2cc412b0f170b287813e2f07a 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java
@@ -196,8 +196,9 @@ public class ListRenderer {
 		Versions versions = null;
 		if(canContainerVersion && child instanceof Versionable) {
 			Versionable versionable = (Versionable)child;
-			if(versionable.getVersions().isVersioned()) {
-				versions = versionable.getVersions();
+			Versions possibleVersions = versionable.getVersions();
+			if(possibleVersions.isVersioned()) {
+				versions = possibleVersions;
 			}
 		}
 		boolean canVersion = versions != null && !versions.getRevisions().isEmpty();
diff --git a/src/main/java/org/olat/core/commons/modules/bc/meta/Size.java b/src/main/java/org/olat/core/commons/modules/bc/meta/Size.java
deleted file mode 100644
index d90731df030af59bdbc0caed151dde392eba42d1..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/commons/modules/bc/meta/Size.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <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
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <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>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.
-*/
-package org.olat.core.commons.modules.bc.meta;
-
-public class Size {
-	
-	private int width;
-	private int height;
-	
-	public Size() {
-		//
-	}
-	
-	public Size(int width, int height) {
-		this.width = width;
-		this.height = height;
-	}
-
-	public int getWidth() {
-		return width;
-	}
-
-	public void setWidth(int width) {
-		this.width = width;
-	}
-
-	public int getHeight() {
-		return height;
-	}
-
-	public void setHeight(int height) {
-		this.height = height;
-	}
-	
-	public String toString() {
-		return "size[width=" + width + ":height=" + height + "]";
-	}
-}
diff --git a/src/main/java/org/olat/core/util/vfs/LocalFileImpl.java b/src/main/java/org/olat/core/util/vfs/LocalFileImpl.java
index 120eda680fb79325e0f8b7bbeb4b283e4f3a4553..ddf28ef0e0419e1d8cc7e74bedd83052fcf80135 100644
--- a/src/main/java/org/olat/core/util/vfs/LocalFileImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/LocalFileImpl.java
@@ -139,6 +139,9 @@ public class LocalFileImpl extends LocalImpl implements VFSLeaf, Versionable {
 			//rename the versions
 			CoreSpringFactory.getImpl(VersionsManager.class).rename(this, newname);
 		}
+		if(canMeta() == VFSConstants.YES) {
+			getMetaInfo().rename(newname);
+		}
 		boolean ren = f.renameTo(nf);
 		if (ren) {
 			// f.renameTo() does NOT modify the path contained in the object f!!
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 bc5a1212b224e48fcba9a46af2041a0359da630b..03cf264d2710ca00b6c25c924c4589a486ebfa0e 100644
--- a/src/main/java/org/olat/core/util/vfs/LocalFolderImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/LocalFolderImpl.java
@@ -28,6 +28,7 @@ package org.olat.core.util.vfs;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
@@ -144,8 +145,9 @@ public class LocalFolderImpl extends LocalImpl implements VFSContainer {
 	 * @return
 	 */
 	private VFSStatus copyFrom(VFSItem source, boolean checkQuota) {
-
-		if (source.canCopy() != VFSConstants.YES) throw new RuntimeException("cannot copy from");
+		if (source.canCopy() != VFSConstants.YES) {
+			return VFSConstants.NO_SECURITY_DENIED;
+		}
 		
 		String sourcename = source.getName();
 		File basefile = getBasefile();
@@ -166,10 +168,7 @@ public class LocalFolderImpl extends LocalImpl implements VFSContainer {
 			// and let the children copy
 
 			// create the folder
-			File outdir = new File(basefile, sourcename);
-			outdir.mkdir();
-			LocalFolderImpl rootcopyfolder = new LocalFolderImpl(outdir, this);
-
+			LocalFolderImpl rootcopyfolder = new LocalFolderImpl(new File(basefile, sourcename), this);
 			List<VFSItem> children = sourcecontainer.getItems();
 			for (VFSItem chd:children) {
 				VFSStatus status = rootcopyfolder.copyFrom(chd, false);
@@ -185,17 +184,24 @@ public class LocalFolderImpl extends LocalImpl implements VFSContainer {
 					return VFSConstants.ERROR_QUOTA_EXCEEDED;
 			}
 			
-			try {
-				FileUtils.bcopy(s.getInputStream(), new File(basefile, sourcename), "VFScopyFrom");
+			File fTarget = new File(basefile, sourcename);
+			try(InputStream in=s.getInputStream()) {
+				FileUtils.bcopy(in, fTarget, "VFScopyFrom");
 			} catch (Exception e) {
 				return VFSConstants.ERROR_FAILED;
 			}
 			
 			if(s instanceof Versionable && ((Versionable)s).getVersions().isVersioned()) {
-				((Versionable)s).getVersions().move(this);
+				((Versionable)s).getVersions().copy(this);
 			}
-
-		} else throw new RuntimeException("neither a leaf nor a container!");
+			
+			boolean copyMetaData = source.canMeta() == VFSConstants.YES && canMeta() == VFSConstants.YES;
+			if(copyMetaData) {
+				source.getMetaInfo().moveCopyToDir(this, false);
+			}
+		} else {
+			throw new RuntimeException("neither a leaf nor a container!");
+		}
 		return VFSConstants.SUCCESS;
 	}
 
diff --git a/src/main/java/org/olat/core/util/vfs/LocalImpl.java b/src/main/java/org/olat/core/util/vfs/LocalImpl.java
index 0d765f44f4f06b3998957859057acf112e888c75..f0fba5b8d95d519210c5ff10c561108e4b25e91c 100644
--- a/src/main/java/org/olat/core/util/vfs/LocalImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/LocalImpl.java
@@ -137,9 +137,12 @@ public abstract class LocalImpl implements VFSItem, JavaIOItem {
 	
 	@Override
 	public VFSStatus canMeta() {
-		File bFile = getBasefile();
+		Path bFile = getBasefile().toPath();
 		Path bcRoot = FolderConfig.getCanonicalRootPath();
-		return bFile.toPath().startsWith(bcRoot) ? VFSConstants.YES : VFSConstants.NO;
+		return bFile.startsWith(bcRoot)
+				&& !bFile.startsWith(FolderConfig.getCanonicalMetaRootPath())
+				&& !bFile.startsWith(FolderConfig.getCanonicalVersionRootPath())
+				? VFSConstants.YES : VFSConstants.NO;
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/core/util/vfs/VFSManager.java b/src/main/java/org/olat/core/util/vfs/VFSManager.java
index 35ff79db2b3b4746cba729ce7a17fb049d283c09..b0c32fd937f509cf4073473bd4e52d3095b8a351 100644
--- a/src/main/java/org/olat/core/util/vfs/VFSManager.java
+++ b/src/main/java/org/olat/core/util/vfs/VFSManager.java
@@ -48,6 +48,13 @@ public class VFSManager {
 	
 	private static final OLog log = Tracing.createLoggerFor(VFSManager.class);
 	
+	/**
+	 * The method create an instance of VFSLeaf
+	 * but doesn't create the file.
+	 * 
+	 * @param fileRelPath The relative path to bcroot.
+	 * @return An instance of VFSLeaf
+	 */
 	public static LocalFileImpl olatRootLeaf(String fileRelPath) {
 		File file = new File(FolderConfig.getCanonicalRoot() + fileRelPath);
 		return new LocalFileImpl(file, null);
@@ -553,13 +560,9 @@ public class VFSManager {
 			buffer.append(targetA[i] + "/");
 		}
 		buffer.deleteCharAt(buffer.length() - 1);
-		String path = buffer.toString();
-
-		String trimmed = path; // selectedPath.substring(1);
-		return trimmed;
+		return buffer.toString();
 	}
 
-
 	/**
 	 * This method takes a VFSContainer and a relative path to a file that exists
 	 * within this container. The method checks if the given container is a
@@ -697,40 +700,26 @@ public class VFSManager {
 	/**
 	 * Copies the content of the source to the target leaf.
 	 * 
-	 * @param source
-	 * @param target
+	 * @param source The source file
+	 * @param target The target file
+	 * @param withMetadata true if the metadata must be copied too
 	 * @return True on success, false on failure
 	 */
-	public static boolean copyContent(VFSLeaf source, VFSLeaf target) {
+	public static boolean copyContent(VFSLeaf source, VFSLeaf target, boolean withMetadata) {
 		boolean successful;
 		if (source != null && target != null) {
-			InputStream in = new BufferedInputStream(source.getInputStream());
-			OutputStream out = new BufferedOutputStream(target.getOutputStream(false));
-			// write the input to the output
-			try {
-				byte[] buf = new byte[FileUtils.BSIZE];
-				int i = 0;
-        while ((i = in.read(buf)) != -1) {
-            out.write(buf, 0, i);
-        }
+			try(InputStream in = new BufferedInputStream(source.getInputStream());
+				OutputStream out = new BufferedOutputStream(target.getOutputStream(false))) {
+				FileUtils.cpio(in, out, "Copy content");
 				successful = true;
-			} catch (IOException e) {
-				// something went wrong.
-				successful = false;
+			} catch(IOException e) {
 				log.error("Error while copying content from source: " + source.getName() + " to target: " + target.getName(), e);
-			} finally {
-				// Close streams
-				try {
-					if (out != null) {
-						out.flush();
-						out.close();
-					}
-					if (in != null) {
-						in.close();
-					}
-				} catch (IOException ex) {
-					log.error("Error while closing/cleaning up in- and output streams", ex);
-				}
+				successful = false;
+			}
+			
+			if(withMetadata && source.canMeta() == VFSConstants.YES && target.canMeta() == VFSConstants.YES) {
+				VFSContainer parentTargetContainer = target.getParentContainer();
+				source.getMetaInfo().moveCopyToDir(parentTargetContainer, false);
 			}
 		} else {
 			// source or target is null
@@ -741,10 +730,12 @@ public class VFSManager {
 	}
 	
 	/**
-	 * Copy the content of the source container to the target container.
-	 * @param source
-	 * @param target
-	 * @return
+	 * Copy the content of the source container to the target container without
+	 * versions or metadata.
+	 * 
+	 * @param source The source container
+	 * @param target the target container
+	 * @return true if successful
 	 */
 	public static boolean copyContent(VFSContainer source, VFSContainer target) {
 		if(!source.exists()) {
@@ -760,12 +751,10 @@ public class VFSManager {
 		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();
+			File localSourceFile = ((LocalImpl)source).getBasefile();
+			File localTargetFile = ((LocalImpl)target).getBasefile();
 			return FileUtils.copyDirContentsToDir(localSourceFile, localTargetFile, false, "VFScopyDir");
 		}
 		return false;
@@ -779,13 +768,13 @@ public class VFSManager {
 	 */
 	public static boolean copyContent(File source, VFSLeaf target) {
 		try(InputStream inStream = new FileInputStream(source)) {
-			return copyContent(inStream, target, true);
+			return copyContent(inStream, target);
 		} catch(IOException ex) {
 			log.error("", ex);
 			return false;
 		}
 	}
-	
+
 	/**
 	 * Copies the stream to the target leaf.
 	 * 
@@ -794,47 +783,17 @@ public class VFSManager {
 	 * @return True on success, false on failure
 	 */
 	public static boolean copyContent(InputStream inStream, VFSLeaf target) {
-		return copyContent(inStream, target, true);
-	}
-	
-	/**
-	 * Copies the stream to the target leaf.
-	 * 
-	 * @param source
-	 * @param target
-	 * @param closeInput set to false if it's a ZipInputStream
-	 * @return True on success, false on failure
-	 */
-	public static boolean copyContent(InputStream inStream, VFSLeaf target, boolean closeInput) {
 		boolean successful;
 		if (inStream != null && target != null) {
-			InputStream in = new BufferedInputStream(inStream);
-			OutputStream out = new BufferedOutputStream(target.getOutputStream(false));
 			// write the input to the output
-			try {
-				byte[] buf = new byte[FileUtils.BSIZE];
-				int i = 0;
-        while ((i = in.read(buf)) != -1) {
-            out.write(buf, 0, i);
-        }
+			try(InputStream in = new BufferedInputStream(inStream);
+					OutputStream out = new BufferedOutputStream(target.getOutputStream(false))) {
+				FileUtils.cpio(in, out, "");
 				successful = true;
 			} catch (IOException e) {
 				// something went wrong.
 				successful = false;
 				log.error("Error while copying content from source: " + inStream + " to target: " + target.getName(), e);
-			} finally {
-				// Close streams
-				try {
-					if (out != null) {
-						out.flush();
-						out.close();
-					}
-					if (closeInput && in != null) {
-						in.close();
-					}
-				} catch (IOException ex) {
-					log.error("Error while closing/cleaning up in- and output streams", ex);
-				}
 			}
 		} else {
 			// source or target is null
@@ -853,8 +812,7 @@ public class VFSManager {
 	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++;
+		for(int count=1; newFile != null && count < 999 ; count++) {
 			newName = FileUtils.appendNumberAtTheEndOfFilename(filename, count);
 		    newFile = container.resolve(newName);
 		}
diff --git a/src/main/java/org/olat/core/util/vfs/meta/MetaInfoFileImpl.java b/src/main/java/org/olat/core/util/vfs/meta/MetaInfoFileImpl.java
index 24e4ce97509f568b52b1e57f694bb0d03eaf98c8..f471ce277191a1d907e36597fe063933bcd34d64 100644
--- a/src/main/java/org/olat/core/util/vfs/meta/MetaInfoFileImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/meta/MetaInfoFileImpl.java
@@ -166,9 +166,11 @@ public class MetaInfoFileImpl implements MetaInfo, Serializable {
 		// rename meta info file name
 		if (isDirectory()) { // rename the directory, which is the parent of the actual ".xml" file
 			File metaFileDirectory = metaFile.getParentFile();
-			metaFileDirectory.renameTo(new File(metaFileDirectory.getParentFile(), newName));
-		} else { // rename the file
-			metaFile.renameTo(new File(metaFile.getParentFile(), newName + ".xml"));
+			if(!metaFileDirectory.renameTo(new File(metaFileDirectory.getParentFile(), newName))) {
+				log.error("Cannot rename meta directory: " + this, null);
+			}
+		} else if(!metaFile.renameTo(new File(metaFile.getParentFile(), newName + ".xml"))) { // rename the file
+			log.error("Cannot rename meta file: " + this, null);
 		}
 	}
 	
@@ -191,8 +193,9 @@ public class MetaInfoFileImpl implements MetaInfo, Serializable {
 			}
 		}
 		
-		if (move) FileUtils.moveFileToDir(fSource, fTarget);
-		else {
+		if (move) {
+			FileUtils.moveFileToDir(fSource, fTarget);
+		} else {
 			//copy
 			Map<String,String> pathToUuid = new HashMap<>();
 			File mTarget = new File(fTarget, fSource.getName());
@@ -200,7 +203,7 @@ public class MetaInfoFileImpl implements MetaInfo, Serializable {
 			
 			if(FileUtils.copyFileToDir(fSource, fTarget, "copy metadata")) {
 				File endTarget = new File(fTarget, fSource.getName());
-				generateUUIDRec(endTarget, pathToUuid);
+				postMetaCopy(endTarget, pathToUuid);
 			}
 		}
 	}
@@ -223,7 +226,7 @@ public class MetaInfoFileImpl implements MetaInfo, Serializable {
 		}
 	}
 
-	private void generateUUIDRec(File endTarget, Map<String,String> pathToUuid) {
+	private void postMetaCopy(File endTarget, Map<String,String> pathToUuid) {
 		if(!endTarget.exists()) {
 			return;
 		}
@@ -231,7 +234,7 @@ public class MetaInfoFileImpl implements MetaInfo, Serializable {
 		try {
 			if(endTarget.isDirectory()) {
 				for(File subEndTarget:endTarget.listFiles(new XmlFilter())) {
-					generateUUIDRec(subEndTarget, pathToUuid);
+					postMetaCopy(subEndTarget, pathToUuid);
 				}
 			} else {
 				MetaInfoFileImpl copyMeta = new MetaInfoFileImpl();
@@ -239,11 +242,11 @@ public class MetaInfoFileImpl implements MetaInfo, Serializable {
 				if (copyMeta.parseSAX(endTarget)) {
 					String tempUuid = pathToUuid.get(endTarget.getCanonicalPath());
 					if(StringHelper.containsNonWhitespace(tempUuid)) {
-						copyMeta.uuid =tempUuid;
+						copyMeta.uuid = tempUuid;
 					} else {
 						copyMeta.generateUUID();
 					}
-					copyMeta.write();
+					copyMeta.clearThumbnails();//clear write the meta
 				}
 			}
 		} catch (IOException e) {
diff --git a/src/main/java/org/olat/core/util/vfs/restapi/VFSWebservice.java b/src/main/java/org/olat/core/util/vfs/restapi/VFSWebservice.java
index 5779948cac9c35f078df48a300ab0218593a38cf..ea62ecabb1b7560ed46e8874c32c2fafddb9886f 100644
--- a/src/main/java/org/olat/core/util/vfs/restapi/VFSWebservice.java
+++ b/src/main/java/org/olat/core/util/vfs/restapi/VFSWebservice.java
@@ -55,6 +55,7 @@ import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
+import org.olat.core.util.FileUtils;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.vfs.VFSConstants;
@@ -411,11 +412,9 @@ public class VFSWebservice {
 			return Response.serverError().status(Status.FORBIDDEN).build();
 		}
 
-		try {
-			OutputStream out = newFile.getOutputStream(false);
-			IOUtils.copy(file, out);
-			IOUtils.closeQuietly(out);
-			IOUtils.closeQuietly(file);
+		try(OutputStream out = newFile.getOutputStream(false)) {
+			FileUtils.cpio(file, out, "Copy");
+			FileUtils.closeSafely(file);
 			return Response.ok(createFileVO(newFile, uriInfo)).build();
 		} catch (IOException e) {
 			return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
diff --git a/src/main/java/org/olat/core/util/vfs/version/NotVersioned.java b/src/main/java/org/olat/core/util/vfs/version/NotVersioned.java
index dee434b379fcd29127d4b303bb8212a651fbe6fd..9a8d94c5e332dbf8f3601ea88d32d160161a2571 100644
--- a/src/main/java/org/olat/core/util/vfs/version/NotVersioned.java
+++ b/src/main/java/org/olat/core/util/vfs/version/NotVersioned.java
@@ -38,10 +38,12 @@ import org.olat.core.util.vfs.VFSContainer;
  */
 public class NotVersioned implements Versions {
 
+	@Override
 	public boolean isVersioned() {
 		return false;
 	}
 
+	@Override
 	public List<VFSRevision> getRevisions() {
 		return Collections.emptyList();
 	}
@@ -51,30 +53,42 @@ public class NotVersioned implements Versions {
 		return "";
 	}
 
+	@Override
 	public String getCreator() {
 		return "";
 	}
 
+	@Override
 	public String getComment() {
 		return "";
 	}
 
+	@Override
 	public String getRevisionNr() {
 		return "";
 	}
 
+	@Override
 	public boolean addVersion(Identity identity, String comment, InputStream newVersion) {
 		return false;
 	}
 
+	@Override
 	public boolean move(VFSContainer container) {
 		return false;
 	}
 
+	@Override
+	public boolean copy(VFSContainer container) {
+		return false;
+	}
+
+	@Override
 	public boolean delete(Identity identity, List<VFSRevision> versionsToDelete) {
 		return false;
 	}
 
+	@Override
 	public boolean restore(Identity identity, VFSRevision version, String comment) {
 		return false;
 	}
diff --git a/src/main/java/org/olat/core/util/vfs/version/Versionable.java b/src/main/java/org/olat/core/util/vfs/version/Versionable.java
index 59da86cb4911722c085db2e82739698f7735c96c..913212851334d8e167c23eedef087043a465877f 100644
--- a/src/main/java/org/olat/core/util/vfs/version/Versionable.java
+++ b/src/main/java/org/olat/core/util/vfs/version/Versionable.java
@@ -31,9 +31,6 @@ package org.olat.core.util.vfs.version;
  */
 public interface Versionable {
 
-	/**
-	 * @return @see org.olat.core.util.vfs.version.Versions
-	 */
 	public Versions getVersions();
 
 }
diff --git a/src/main/java/org/olat/core/util/vfs/version/Versions.java b/src/main/java/org/olat/core/util/vfs/version/Versions.java
index 864215c993a3bcdb4d667b31834f0c0d8bd17ed1..8de0d815927446a2f241bc0f3d1abb1658966c85 100644
--- a/src/main/java/org/olat/core/util/vfs/version/Versions.java
+++ b/src/main/java/org/olat/core/util/vfs/version/Versions.java
@@ -78,9 +78,16 @@ public interface Versions {
 	/**
 	 * move the file
 	 * @param container
-	 * @return
+	 * @return true if successful
 	 */
 	public boolean move(VFSContainer container);
+	
+	/**
+	 * Copy the file
+	 * @param container
+	 * @return true if successful
+	 */
+	public boolean copy(VFSContainer container);
 
 	/**
 	 * restore the file to the revision given as parameter
diff --git a/src/main/java/org/olat/core/util/vfs/version/VersionsFileImpl.java b/src/main/java/org/olat/core/util/vfs/version/VersionsFileImpl.java
index bba0d20c79bbb1db959335e14e18108373d6331b..d725a54651ef1d4f91a9723c0a2be09e65c42c27 100644
--- a/src/main/java/org/olat/core/util/vfs/version/VersionsFileImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/version/VersionsFileImpl.java
@@ -90,6 +90,12 @@ public class VersionsFileImpl implements Versions {
 		return CoreSpringFactory.getImpl(VersionsManager.class).move(getCurrentVersion(), container);
 	}
 
+	@Override
+	public boolean copy(VFSContainer container) {
+		return CoreSpringFactory.getImpl(VersionsManager.class).copy(getCurrentVersion(), container);
+	}
+
+	@Override
 	public boolean restore(Identity identity, VFSRevision version, String comments) {
 		return CoreSpringFactory.getImpl(VersionsManager.class).restore(getCurrentVersion(), version, comments);
 	}
diff --git a/src/main/java/org/olat/core/util/vfs/version/VersionsFileManager.java b/src/main/java/org/olat/core/util/vfs/version/VersionsFileManager.java
index 9fedb89145027dbbbe2f26abd091372ddeeadc73..869ebf3e413d4a0c485457085ec847e4242b3941 100644
--- a/src/main/java/org/olat/core/util/vfs/version/VersionsFileManager.java
+++ b/src/main/java/org/olat/core/util/vfs/version/VersionsFileManager.java
@@ -46,6 +46,7 @@ import org.olat.core.logging.Tracing;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.async.ProgressDelegate;
+import org.olat.core.util.io.ShieldInputStream;
 import org.olat.core.util.vfs.JavaIOItem;
 import org.olat.core.util.vfs.LocalFileImpl;
 import org.olat.core.util.vfs.LocalFolderImpl;
@@ -241,10 +242,10 @@ public class VersionsFileManager implements VersionsManager {
 		VFSLeaf currentFile = (VFSLeaf) currentVersion;
 		if (addToRevisions(currentVersion, identity, comment)) {
 			// copy the content of the new file to the old
-			boolean closeInputStream = !(newFile instanceof net.sf.jazzlib.ZipInputStream || newFile instanceof java.util.zip.ZipInputStream);
-			if (VFSManager.copyContent(newFile, currentFile, closeInputStream)) {
-				return true;
+			if(newFile instanceof net.sf.jazzlib.ZipInputStream || newFile instanceof java.util.zip.ZipInputStream) {
+				newFile = new ShieldInputStream(newFile);
 			}
+			return VFSManager.copyContent(newFile, currentFile);
 		} else {
 			log.error("Cannot create a version of this file: " + currentVersion);
 		}
@@ -328,6 +329,16 @@ public class VersionsFileManager implements VersionsManager {
 		}
 		return false;
 	}
+	
+	@Override
+	public boolean copy(Versionable currentVersion, VFSContainer container) {
+		VFSLeaf currentFile = (VFSLeaf) currentVersion;
+		VFSLeaf fVersions = getCanonicalVersionXmlFile(currentFile, true);
+		Versions versions = readVersions(currentFile, fVersions);
+
+		VFSContainer versionContainer = getCanonicalVersionFolder(container, true);
+		return copy(versionContainer, fVersions, versions);
+	}
 
 	@Override
 	public boolean move(Versionable currentVersion, VFSContainer container) {
@@ -336,21 +347,25 @@ public class VersionsFileManager implements VersionsManager {
 		Versions versions = readVersions(currentFile, fVersions);
 
 		VFSContainer versionContainer = getCanonicalVersionFolder(container, true);
+		boolean allOk = copy(versionContainer, fVersions, versions);
 
-		boolean allOk = VFSConstants.YES.equals(versionContainer.copyFrom(fVersions));
+		allOk &= VFSConstants.YES.equals(fVersions.delete());
 		for (VFSRevision revision : versions.getRevisions()) {
-			RevisionFileImpl revisionImpl = (RevisionFileImpl) revision;
-			VFSLeaf revisionFile = revisionImpl.getFile();
+			VFSLeaf revisionFile = ((RevisionFileImpl) revision).getFile();
 			if (revisionFile != null) {
-				allOk &= VFSConstants.YES.equals(versionContainer.copyFrom(revisionFile));
+				allOk &= VFSConstants.YES.equals(revisionFile.delete());
 			}
 		}
-
-		allOk &= VFSConstants.YES.equals(fVersions.delete());
+		return allOk;
+	}
+	
+	private boolean copy(VFSContainer versionContainer, VFSLeaf fVersions, Versions versions) {
+		boolean allOk = VFSConstants.YES.equals(versionContainer.copyFrom(fVersions));
 		for (VFSRevision revision : versions.getRevisions()) {
-			VFSLeaf revisionFile = ((RevisionFileImpl) revision).getFile();
+			RevisionFileImpl revisionImpl = (RevisionFileImpl) revision;
+			VFSLeaf revisionFile = revisionImpl.getFile();
 			if (revisionFile != null) {
-				allOk &= VFSConstants.YES.equals(revisionFile.delete());
+				allOk &= VFSConstants.YES.equals(versionContainer.copyFrom(revisionFile));
 			}
 		}
 		return allOk;
@@ -673,7 +688,7 @@ public class VersionsFileManager implements VersionsManager {
 			}
 		}
 
-		if (sameFile || VFSManager.copyContent(currentFile, versionContainer.createChildLeaf(uuid))) {
+		if (sameFile || VFSManager.copyContent(currentFile, versionContainer.createChildLeaf(uuid), false)) {
 			if (identity != null) {
 				versions.setAuthor(identity.getName());
 			}
diff --git a/src/main/java/org/olat/core/util/vfs/version/VersionsManager.java b/src/main/java/org/olat/core/util/vfs/version/VersionsManager.java
index b4bac7ec25659ee706ad9196784cc9db588438b3..3cd8d2e8d36c15e9092d17625d1ef93951dc83e6 100644
--- a/src/main/java/org/olat/core/util/vfs/version/VersionsManager.java
+++ b/src/main/java/org/olat/core/util/vfs/version/VersionsManager.java
@@ -105,6 +105,15 @@ public interface VersionsManager extends ConfigOnOff {
 	 */
 	public boolean move(Versionable currentVersion, VFSContainer container);
 	
+	/**
+	 * Copy a versioned file to the target container
+	 * 
+	 * @param currentVersion
+	 * @param target container
+	 * @return
+	 */
+	public boolean copy(Versionable currentVersion, VFSContainer container);
+	
 	/**
 	 * Move a versioned file to an other (WebDAV only!!!)
 	 * 
diff --git a/src/main/java/org/olat/course/nodes/dialog/ui/DialogCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/dialog/ui/DialogCourseNodeRunController.java
index 7a66858b498ddb68f9416815b7384f7173b48f44..9ce7b513c300152416047baf63476a5664807a7c 100644
--- a/src/main/java/org/olat/course/nodes/dialog/ui/DialogCourseNodeRunController.java
+++ b/src/main/java/org/olat/course/nodes/dialog/ui/DialogCourseNodeRunController.java
@@ -352,7 +352,7 @@ public class DialogCourseNodeRunController extends BasicController implements Ac
 		if(copyVl == null) {
 			copyVl = (VFSLeaf)dialogContainer.resolve(vl.getName());
 		}
-		VFSManager.copyContent(vl, copyVl);
+		VFSManager.copyContent(vl, copyVl, true);
 		
 		// inform subscription manager about new element
 		if (subsContext != null) {
diff --git a/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java b/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java
index d0bb16b20b5fe03f24b9fde101182eecc81ed56d..6b7dd1c4a113002fddf9ddb54411952470274572 100644
--- a/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java
+++ b/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java
@@ -175,7 +175,7 @@ public class ConvertToGTACourseNode {
 					for(VFSItem dropppedItem:userDropContainer.getItems()) {
 						if(dropppedItem instanceof VFSLeaf) {
 							VFSLeaf submittedDocument = sumbitContainer.createChildLeaf(dropppedItem.getName());
-							VFSManager.copyContent((VFSLeaf)dropppedItem, submittedDocument);
+							VFSManager.copyContent((VFSLeaf)dropppedItem, submittedDocument, true);
 							convertMetada(userDropContainer, sumbitContainer, dropppedItem.getName(), null, null);
 							dropped = true;
 						}
@@ -204,7 +204,7 @@ public class ConvertToGTACourseNode {
 					for(VFSItem returnedItem:userContainer.getItems()) {
 						if(returnedItem instanceof VFSLeaf) {
 							VFSLeaf correctionDocument = correctionContainer.createChildLeaf(returnedItem.getName());
-							VFSManager.copyContent((VFSLeaf)returnedItem, correctionDocument);
+							VFSManager.copyContent((VFSLeaf)returnedItem, correctionDocument, true);
 							convertMetada(userContainer, correctionContainer, returnedItem.getName(), null, null);
 							returned = true;
 						}
@@ -293,7 +293,7 @@ public class ConvertToGTACourseNode {
 		for(VFSItem solution:solutionContainer.getItems()) {
 			if(solution instanceof VFSLeaf) {
 				VFSLeaf solutionDocument = solutionDirectory.createChildLeaf(solution.getName());
-				VFSManager.copyContent((VFSLeaf)solution, solutionDocument);
+				VFSManager.copyContent((VFSLeaf)solution, solutionDocument, true);
 				
 				Solution solDef = new Solution();
 				convertMetada(solutionContainer, solutionDirectory, solution.getName(), null, solDef);
diff --git a/src/main/java/org/olat/ims/cp/objects/CPFile.java b/src/main/java/org/olat/ims/cp/objects/CPFile.java
index 7b342248163206e610250fbf2a7708f69beb58a9..4d5e0b08600c916c96dac94fd0946e118d9d7ccb 100644
--- a/src/main/java/org/olat/ims/cp/objects/CPFile.java
+++ b/src/main/java/org/olat/ims/cp/objects/CPFile.java
@@ -96,7 +96,7 @@ public class CPFile extends DefaultElement implements CPNode {
 		VFSContainer parentContainer = file.getParentContainer();
 		String newName = VFSManager.similarButNonExistingName(parentContainer, file.getName());
 		VFSLeaf leafCopy = parentContainer.createChildLeaf(newName);
-		VFSManager.copyContent(file, leafCopy);
+		VFSManager.copyContent(file, leafCopy, true);
 		copy.setFile(leafCopy);
 		copy.setHref(calculateHref(leafCopy));
 		return copy;
diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java b/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java
index 6a32ccd6261ee105c7456913293b052db21acfcf..82b04ff57fd7a4460544212ce65cee6973609aaa 100644
--- a/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java
+++ b/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java
@@ -161,7 +161,7 @@ public class QTIExportProcessor {
 		for(ItemMaterial material:itemAndMaterials.getMaterials()) {
 			String exportPath = material.getExportUri();
 			VFSLeaf leaf = editorContainer.createChildLeaf(exportPath);
-			VFSManager.copyContent(material.getLeaf(), leaf);
+			VFSManager.copyContent(material.getLeaf(), leaf, false);
 		}
 		return itemEl;
 	}
diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java b/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java
index a2155e5271b63e4cfa4f77d0dac4c5b1f6dbb6a5..e289ee0a60ed6be5769dac10e84c45f695d6e750 100644
--- a/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java
+++ b/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java
@@ -257,7 +257,7 @@ public class QTIQPoolServiceProvider implements QPoolSPI {
 				VFSItem sourceItem = sourceDir.resolve(material);
 				if(sourceItem instanceof VFSLeaf) {
 					VFSLeaf targetItem = baseDir.createChildLeaf(material);
-					VFSManager.copyContent((VFSLeaf)sourceItem, targetItem);
+					VFSManager.copyContent((VFSLeaf)sourceItem, targetItem, false);
 				}
 			}
 		}
diff --git a/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java b/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java
index f12265e9c141a5d41cfce8363179a79f308c8694..efaf8f3d2f982641ff2877c729d4a85672955449 100644
--- a/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java
+++ b/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java
@@ -159,7 +159,7 @@ public class VideoManagerImpl implements VideoManager {
 	public void setPosterframe(OLATResource videoResource, VFSLeaf posterframe){
 		VFSContainer masterContainer = getMasterContainer(videoResource);
 		VFSLeaf newPoster = VFSManager.resolveOrCreateLeafFromPath(masterContainer, FILENAME_POSTER_JPG);
-		VFSManager.copyContent(posterframe, newPoster);
+		VFSManager.copyContent(posterframe, newPoster, false);
 		
 		// Update also repository entry image, use new posterframe
 		VFSLeaf posterImage = (VFSLeaf)masterContainer.resolve(FILENAME_POSTER_JPG);
@@ -615,7 +615,7 @@ public class VideoManagerImpl implements VideoManager {
 		// 1) copy master video to final destination with standard name
 		VFSContainer masterContainer = getMasterContainer(videoResource);
 		VFSLeaf targetFile = VFSManager.resolveOrCreateLeafFromPath(masterContainer, FILENAME_VIDEO_MP4);
-		VFSManager.copyContent(masterVideo, targetFile);
+		VFSManager.copyContent(masterVideo, targetFile, false);
 		masterVideo.delete();
 
 		// calculate video duration
diff --git a/src/main/java/org/olat/modules/webFeed/manager/FeedFileStorge.java b/src/main/java/org/olat/modules/webFeed/manager/FeedFileStorge.java
index 5fa95a048c4bc2bf3a13585312347988d954d9b1..dd50003e47539e8b7f00087657de86a9aa6290f7 100644
--- a/src/main/java/org/olat/modules/webFeed/manager/FeedFileStorge.java
+++ b/src/main/java/org/olat/modules/webFeed/manager/FeedFileStorge.java
@@ -499,7 +499,7 @@ public class FeedFileStorge {
 		if (feedMediaContainer != null) {
 			deleteFeedMedia(feed);
 			if (media != null) {
-				VFSManager.copyContent(media, feedMediaContainer.createChildLeaf(media.getName()));
+				VFSManager.copyContent(media, feedMediaContainer.createChildLeaf(media.getName()), true);
 				saveFileName = media.getName();
 			}
 		}
diff --git a/src/main/java/org/olat/portfolio/manager/EPArtefactManager.java b/src/main/java/org/olat/portfolio/manager/EPArtefactManager.java
index 405a514c1234bcec95a0e6ef1e06672a1b5a365b..d6b2f0be984cbbce6d9121bd57c8b6eeb4a12fae 100755
--- a/src/main/java/org/olat/portfolio/manager/EPArtefactManager.java
+++ b/src/main/java/org/olat/portfolio/manager/EPArtefactManager.java
@@ -287,7 +287,7 @@ public class EPArtefactManager extends BasicManager {
 					if (artData == null) {
 						artData = container.createChildLeaf(ARTEFACT_CONTENT_FILENAME);
 					} 
-					VFSManager.copyContent(new ByteArrayInputStream(fullText.getBytes()), artData, true);
+					VFSManager.copyContent(new ByteArrayInputStream(fullText.getBytes()), artData);
 					artefact.setFulltextContent(ARTEFACT_FULLTEXT_ON_FS);
 					dbInstance.updateObject(artefact);
 				} catch (Exception e) {
diff --git a/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCreateTextArtefactStepForm00.java b/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCreateTextArtefactStepForm00.java
index eca0e8d86f746c93838f295ee63b527983df8185..ff8988212baf39117f451867935d2b80e12d8b92 100644
--- a/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCreateTextArtefactStepForm00.java
+++ b/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCreateTextArtefactStepForm00.java
@@ -115,7 +115,7 @@ public class EPCreateTextArtefactStepForm00 extends StepFormBasicController {
 			// save fulltext to temp-file
 			String fulltext = content.getValue();
 			VFSLeaf contFile = (VFSLeaf) vfsTemp.resolve(EPArtefactManager.ARTEFACT_CONTENT_FILENAME);
-			VFSManager.copyContent(new ByteArrayInputStream(fulltext.getBytes()), contFile, true);
+			VFSManager.copyContent(new ByteArrayInputStream(fulltext.getBytes()), contFile);
 
 			addToRunContext("artefact", artefact);
 			addToRunContext("tempArtFolder", vfsTemp);
diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java
index 9740e1856d36522fdf5799619b8e4379deea0e25..8a33fdcba1e9ec9fcd46529465abb9327c99d88b 100644
--- a/src/main/java/org/olat/repository/RepositoryManager.java
+++ b/src/main/java/org/olat/repository/RepositoryManager.java
@@ -169,7 +169,7 @@ public class RepositoryManager {
 		VFSContainer repositoryHome = new LocalFolderImpl(new File(FolderConfig.getCanonicalRepositoryHome()));
 		VFSLeaf newImage = repositoryHome.createChildLeaf(target.getResourceableId() + "." + sourceImageSuffix);
 		if (newImage != null) {
-			return VFSManager.copyContent(srcFile, newImage);
+			return VFSManager.copyContent(srcFile, newImage, false);
 		}
 		return false;
 	}
@@ -218,7 +218,7 @@ public class RepositoryManager {
 		if(targetExtension.equals(".png") || targetExtension.equals(".jpg")) {
 			Size newImageSize = imageHelper.getSize(newImageFile, extension);
 			if(newImageSize != null && newImageSize.getWidth() <= PICTURE_WIDTH && newImageSize.getHeight() <= PICTURE_HEIGHT) {
-				return VFSManager.copyContent(newImageFile, repoImage);
+				return VFSManager.copyContent(newImageFile, repoImage, false);
 			}
 		}
 
diff --git a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
index 536e6d09e5d9868e48bbc1e52876af60499f15db..c6fcfc1167e152438c366237884bb0aed899c762 100644
--- a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
+++ b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
@@ -131,7 +131,7 @@ public class ImsCPHandler extends FileHandler {
 		RepositoryEntry re = CoreSpringFactory.getImpl(RepositoryService.class).create(initialAuthor, null, "", displayname, description,
 				resource, RepositoryEntryStatusEnum.preparation, organisation);
 		
-		File fResourceFileroot = FileResourceManager.getInstance().getFileResourceRootImpl(resource).getBasefile();
+		File fResourceFileroot = FileResourceManager.getInstance().getFileResourceRoot(resource);
 		File zipRoot = new File(fResourceFileroot, FileResourceManager.ZIPDIR);
 		FileResource.copyResource(file, filename, zipRoot);
 		CPOfflineReadableManager.getInstance().makeCPOfflineReadable(cpResource, displayname);
@@ -146,10 +146,10 @@ public class ImsCPHandler extends FileHandler {
 		OLATResource sourceResource = source.getOlatResource();
 		OLATResource targetResource = target.getOlatResource();
 		
-		File sourceFileroot = FileResourceManager.getInstance().getFileResourceRootImpl(sourceResource).getBasefile();
+		File sourceFileroot = FileResourceManager.getInstance().getFileResourceRoot(sourceResource);
 		File zipRoot = new File(sourceFileroot, FileResourceManager.ZIPDIR);
 		
-		File targetFileroot = FileResourceManager.getInstance().getFileResourceRootImpl(targetResource).getBasefile();
+		File targetFileroot = FileResourceManager.getInstance().getFileResourceRoot(targetResource);
 		FileUtils.copyFileToDir(zipRoot, targetFileroot, "add file resource");
 		
 		//copy packaging info
diff --git a/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java b/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java
index 58f063d00c4f687822f2bf49afc66bbe9c700d8f..540e1efe83839efe1596ea587fe810e4e6e003a4 100644
--- a/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java
+++ b/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java
@@ -44,7 +44,6 @@ import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.Organisation;
 import org.olat.core.id.Roles;
 import org.olat.core.logging.AssertException;
-import org.olat.core.util.FileUtils;
 import org.olat.core.util.Util;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.coordinate.LockResult;
@@ -121,9 +120,9 @@ public class SharedFolderHandler implements RepositoryHandler {
 	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		OLATResource sourceResource = source.getOlatResource();
 		OLATResource targetResource = target.getOlatResource();
-		File sourceFileroot = FileResourceManager.getInstance().getFileResourceRootImpl(sourceResource).getBasefile();
-		File targetFileroot = FileResourceManager.getInstance().getFileResourceRootImpl(targetResource).getBasefile();
-		FileUtils.copyDirContentsToDir(sourceFileroot, targetFileroot, false, "copy");
+		VFSContainer sourceContainer = FileResourceManager.getInstance().getFileResourceRootImpl(sourceResource);
+		VFSContainer targetContainer = FileResourceManager.getInstance().getFileResourceRootImpl(targetResource);
+		targetContainer.copyFrom(sourceContainer);
 		return target;
 	}
 
diff --git a/src/main/java/org/olat/repository/manager/CatalogManager.java b/src/main/java/org/olat/repository/manager/CatalogManager.java
index 40162b5ea1c5bf4f82f22548fc232aaa70e5c5f9..36bb6828e07157ec12ad0b28958c15d332689701 100644
--- a/src/main/java/org/olat/repository/manager/CatalogManager.java
+++ b/src/main/java/org/olat/repository/manager/CatalogManager.java
@@ -773,13 +773,13 @@ public class CatalogManager implements UserDataDeletable, InitializingBean {
 		try {
 			if("jpeg".equals(extension) || "jpg".equals(extension)) {
 				VFSLeaf repoImage = catalogResourceHome.createChildLeaf(re.getKey() + ".jpg");
-				ok = VFSManager.copyContent(newImageFile, repoImage);
+				ok = VFSManager.copyContent(newImageFile, repoImage, false);
 			} else if("png".equals(extension)) {
 				VFSLeaf repoImage = catalogResourceHome.createChildLeaf(re.getKey() + ".png");
-				ok = VFSManager.copyContent(newImageFile, repoImage);
+				ok = VFSManager.copyContent(newImageFile, repoImage, false);
 			} else if("gif".equals(extension)) {
 				VFSLeaf repoImage = catalogResourceHome.createChildLeaf(re.getKey() + ".gif");
-				ok = VFSManager.copyContent(newImageFile, repoImage);
+				ok = VFSManager.copyContent(newImageFile, repoImage, false);
 			} else {
 				//scale to default and png
 				VFSLeaf repoImage = catalogResourceHome.createChildLeaf(re.getKey() + ".png");
diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_11_3_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_11_3_0.java
index d8b93275d5e767bcd5bbef3a6126398cb9b2d97e..8bda43d5902b7f601afe4204b4f5938bed803acc 100644
--- a/src/main/java/org/olat/upgrade/OLATUpgrade_11_3_0.java
+++ b/src/main/java/org/olat/upgrade/OLATUpgrade_11_3_0.java
@@ -131,7 +131,7 @@ public class OLATUpgrade_11_3_0 extends OLATUpgrade {
 						//check if modified track file already exists
 						if (masterContainer.resolve(path) == null) {
 							VFSLeaf target = masterContainer.createChildLeaf(path);
-							VFSManager.copyContent((VFSLeaf) item, target);
+							VFSManager.copyContent((VFSLeaf) item, target, false);
 						}
 					}
 				}
diff --git a/src/test/java/org/olat/core/util/vfs/VFSManagerTest.java b/src/test/java/org/olat/core/util/vfs/VFSManagerTest.java
index 081491ef1c4c30c7d45530bc95e649814294d952..3574aecec1989366db95fb911aa3a4d1aefedb35 100644
--- a/src/test/java/org/olat/core/util/vfs/VFSManagerTest.java
+++ b/src/test/java/org/olat/core/util/vfs/VFSManagerTest.java
@@ -28,16 +28,15 @@ package org.olat.core.util.vfs;
 import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.olat.test.OlatTestCase;
 
 /**
+ * 
  * <P>
  * Initial Date:  16.06.2009 <br>
  * @author patrickb
  */
-@RunWith(JUnit4.class)
-public class VFSManagerTest{
+public class VFSManagerTest extends OlatTestCase {
 
 	/**
 	 * Test method for {@link org.olat.core.util.vfs.VFSManager#sanitizePath(java.lang.String)}.
diff --git a/src/test/java/org/olat/core/util/vfs/VFSTest.java b/src/test/java/org/olat/core/util/vfs/VFSTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..660508af4e7933c22f6e1855312775e96e8c0919
--- /dev/null
+++ b/src/test/java/org/olat/core/util/vfs/VFSTest.java
@@ -0,0 +1,94 @@
+package org.olat.core.util.vfs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.FileUtils;
+import org.olat.core.util.vfs.meta.MetaInfo;
+import org.olat.test.OlatTestCase;
+
+
+/**
+ * 
+ * Initial date: 8 janv. 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class VFSTest extends OlatTestCase {
+	
+	private static final OLog log = Tracing.createLoggerFor(VFSTest.class);
+	
+	private static final String VFS_TEST_DIR = "/vfstest";
+	
+	/**
+	 * Test the copyFrom method (inclusive copy of metadata)
+	 */
+	@Test
+	public void copyFrom() {
+		String filename = UUID.randomUUID() + ".txt";
+		VFSContainer testContainer = VFSManager.olatRootContainer(VFS_TEST_DIR, null);
+		VFSLeaf firstLeaf = testContainer.createChildLeaf(filename);
+		Assert.assertEquals(VFSConstants.YES, firstLeaf.canMeta());
+		prepareFile(firstLeaf);
+		
+		MetaInfo metaInfo = firstLeaf.getMetaInfo();
+		metaInfo.setComment("A comment");
+		metaInfo.setCreator("Me");
+		Assert.assertTrue(metaInfo.write());
+		
+		VFSContainer targetContainer = VFSManager.olatRootContainer(VFS_TEST_DIR + "/vfstarger" + UUID.randomUUID(), null);
+		Assert.assertEquals(VFSConstants.YES, targetContainer.canMeta());
+		targetContainer.copyFrom(firstLeaf);
+		
+		VFSItem copiedItem = targetContainer.resolve(filename);
+		Assert.assertTrue(copiedItem instanceof VFSLeaf);
+		
+		VFSLeaf copiedLeaf = (VFSLeaf)copiedItem;
+		Assert.assertEquals(VFSConstants.YES, copiedLeaf.canMeta());
+		
+		MetaInfo copiedMetaInfo = copiedLeaf.getMetaInfo();
+		Assert.assertEquals("A comment", copiedMetaInfo.getComment());
+		Assert.assertEquals("Me", copiedMetaInfo.getCreator());
+	}
+	
+	@Test
+	public void rename() {
+		String filename = UUID.randomUUID() + ".txt";
+		VFSContainer testContainer = VFSManager.olatRootContainer(VFS_TEST_DIR, null);
+		VFSLeaf firstLeaf = testContainer.createChildLeaf(filename);
+		Assert.assertEquals(VFSConstants.YES, firstLeaf.canMeta());
+		prepareFile(firstLeaf);
+		
+		MetaInfo metaInfo = firstLeaf.getMetaInfo();
+		metaInfo.setComment("my old comment");
+		metaInfo.setCreator("Always Me");
+		Assert.assertTrue(metaInfo.write());
+		
+		String newName = UUID.randomUUID() + ".txt";
+		VFSStatus renamedStatus = firstLeaf.rename(newName);
+		Assert.assertEquals(VFSConstants.YES, renamedStatus);
+		
+		VFSItem renamedItem = testContainer.resolve(newName);
+		Assert.assertTrue(renamedItem instanceof VFSLeaf);
+		VFSLeaf renamedLeaf = (VFSLeaf)renamedItem;
+		
+		MetaInfo renamedMetaInfo = renamedLeaf.getMetaInfo();
+		Assert.assertEquals("my old comment", renamedMetaInfo.getComment());
+		Assert.assertEquals("Always Me", renamedMetaInfo.getCreator());
+	}
+	
+	private void prepareFile(VFSLeaf file) {
+		try(OutputStream out = file.getOutputStream(false);
+				InputStream in = VFSTest.class.getResourceAsStream("test.txt")) {
+			FileUtils.cpio(in, out, "");
+		} catch(IOException e) {
+			log.error("", e);
+		}
+	}
+}
diff --git a/src/test/java/org/olat/search/service/document/file/OfficeDocumentTest.java b/src/test/java/org/olat/search/service/document/file/OfficeDocumentTest.java
index 0c95172f50abac4061dc2d33952e55f0ecbd6ade..6c3edf48b27a17bf1684de97ae10f057b60fd880 100644
--- a/src/test/java/org/olat/search/service/document/file/OfficeDocumentTest.java
+++ b/src/test/java/org/olat/search/service/document/file/OfficeDocumentTest.java
@@ -29,9 +29,9 @@ import java.util.List;
 
 import org.junit.Assert;
 import org.junit.Test;
+import org.olat.core.util.vfs.LocalFileImpl;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.test.OlatTestCase;
-import org.olat.test.VFSJavaIOFile;
 
 /**
  * Test the low memory text extractor for OpenXML (Microsoft Office XML)
@@ -46,7 +46,7 @@ public class OfficeDocumentTest extends OlatTestCase {
 		URL docUrl = OfficeDocumentTest.class.getResource("Test_word_indexing.docx");
 		Assert.assertNotNull(docUrl);
 		
-		VFSLeaf doc = new VFSJavaIOFile(new File(docUrl.toURI()));
+		VFSLeaf doc = new LocalFileImpl(new File(docUrl.toURI()));
 		WordOOXMLDocument document = new WordOOXMLDocument();
 		FileContent content =	document.readContent(doc);
 		Assert.assertNotNull(content);
@@ -82,7 +82,7 @@ public class OfficeDocumentTest extends OlatTestCase {
 		URL docUrl = OfficeDocumentTest.class.getResource("Test_word_indexing.doc");
 		Assert.assertNotNull(docUrl);
 		
-		VFSLeaf doc = new VFSJavaIOFile(new File(docUrl.toURI()));
+		VFSLeaf doc = new LocalFileImpl(new File(docUrl.toURI()));
 		WordDocument document = new WordDocument();
 		FileContent content =	document.readContent(doc);
 		Assert.assertNotNull(content);
@@ -96,7 +96,7 @@ public class OfficeDocumentTest extends OlatTestCase {
 		URL docUrl = OfficeDocumentTest.class.getResource("Test_excel_indexing.xlsx");
 		Assert.assertNotNull(docUrl);
 
-		VFSLeaf doc = new VFSJavaIOFile(new File(docUrl.toURI()));
+		VFSLeaf doc = new LocalFileImpl(new File(docUrl.toURI()));
 		ExcelOOXMLDocument document = new ExcelOOXMLDocument();
 		FileContent content =	document.readContent(doc);
 		Assert.assertNotNull(content);
@@ -110,7 +110,7 @@ public class OfficeDocumentTest extends OlatTestCase {
 		URL docUrl = OfficeDocumentTest.class.getResource("Test_excel_indexing.xls");
 		Assert.assertNotNull(docUrl);
 
-		VFSLeaf doc = new VFSJavaIOFile(new File(docUrl.toURI()));
+		VFSLeaf doc = new LocalFileImpl(new File(docUrl.toURI()));
 		ExcelDocument document = new ExcelDocument();
 		FileContent content =	document.readContent(doc);
 		Assert.assertNotNull(content);
@@ -124,7 +124,7 @@ public class OfficeDocumentTest extends OlatTestCase {
 		URL docUrl = OfficeDocumentTest.class.getResource("Test_ppt_indexing.pptx");
 		Assert.assertNotNull(docUrl);
 
-		VFSLeaf doc = new VFSJavaIOFile(new File(docUrl.toURI()));
+		VFSLeaf doc = new LocalFileImpl(new File(docUrl.toURI()));
 		PowerPointOOXMLDocument document = new PowerPointOOXMLDocument();
 		FileContent content =	document.readContent(doc);
 		Assert.assertNotNull(content);
@@ -159,7 +159,7 @@ public class OfficeDocumentTest extends OlatTestCase {
 		URL docUrl = OfficeDocumentTest.class.getResource("Test_ppt_indexing.ppt");
 		Assert.assertNotNull(docUrl);
 
-		VFSLeaf doc = new VFSJavaIOFile(new File(docUrl.toURI()));
+		VFSLeaf doc = new LocalFileImpl(new File(docUrl.toURI()));
 		PowerPointDocument document = new PowerPointDocument();
 		FileContent content =	document.readContent(doc);
 		Assert.assertNotNull(content);
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index 76d343422224de854f1f53fdaa102d0bbf3ee33d..4e963be9040df166ec33cc2261d5a5ab02e306be 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -50,6 +50,7 @@ import org.junit.runners.Suite;
 	org.olat.core.gui.components.table.TableMultiSelectEventTest.class,
 	org.olat.core.gui.components.table.SorterTest.class,
 	org.olat.core.commons.chiefcontrollers.ChiefControllerMessageEventTest.class,
+	org.olat.core.util.vfs.VFSTest.class,
 	org.olat.core.util.vfs.VFSManagerTest.class,
 	org.olat.core.util.filter.impl.XSSFilterTest.class,
 	org.olat.core.util.filter.impl.AddBaseURLToMediaRelativeURLFilterTest.class,