diff --git a/src/main/java/org/olat/core/commons/controllers/linkchooser/FileLinkChooserController.java b/src/main/java/org/olat/core/commons/controllers/linkchooser/FileLinkChooserController.java
index d3c3ba4abf7f02e0a0ef3319d8e9495255b14b1f..64cf8755bf5eb75d862d3af5a551203f2abd5123 100644
--- a/src/main/java/org/olat/core/commons/controllers/linkchooser/FileLinkChooserController.java
+++ b/src/main/java/org/olat/core/commons/controllers/linkchooser/FileLinkChooserController.java
@@ -48,6 +48,7 @@ import org.olat.core.util.FileUtils;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.vfs.Quota;
+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;
@@ -127,8 +128,7 @@ public class FileLinkChooserController extends BasicController {
 		VFSItemFilter customFilter = null;
 		VFSItemFilter dirFilter = new VFSItemExcludePrefixFilter(dirFilters);
 		if (suffixes != null) {
-			VFSItemFileTypeFilter typeFilter = new VFSItemFileTypeFilter(
-					suffixes);
+			VFSItemFileTypeFilter typeFilter = new VFSItemFileTypeFilter(suffixes);
 			typeFilter.setCompositeFilter(dirFilter);
 			customFilter = typeFilter;
 		} else {
@@ -144,7 +144,7 @@ public class FileLinkChooserController extends BasicController {
 		// convert file endings to mime types as needed by file upload controller
 		Set<String> mimeTypes = null;
 		if (suffixes != null) {
-			mimeTypes = new HashSet<String>();
+			mimeTypes = new HashSet<>();
 			for (String suffix : suffixes) {
 				String mimeType = WebappHelper.getMimeType("dummy." + suffix);
 				if (mimeType != null) {
@@ -152,27 +152,28 @@ public class FileLinkChooserController extends BasicController {
 				}
 			}
 		}
-		
-		long remainingSpace = Quota.UNLIMITED;
-		long uploadLimit = FolderConfig.getLimitULKB();
-		if( fileUploadBase.getLocalSecurityCallback() != null && fileUploadBase.getLocalSecurityCallback().getQuota() != null) {
-			Long space = fileUploadBase.getLocalSecurityCallback().getQuota().getRemainingSpace();
-			if(space != null) {
-				remainingSpace = space.longValue();
-			}
-			Long limit = fileUploadBase.getLocalSecurityCallback().getQuota().getUlLimitKB();
-			if(limit != null) {
-				uploadLimit = limit.longValue();
+
+		if(fileUploadBase.canWrite() == VFSConstants.YES) {
+			long remainingSpace = Quota.UNLIMITED;
+			long uploadLimit = FolderConfig.getLimitULKB();
+			if( fileUploadBase.getLocalSecurityCallback() != null && fileUploadBase.getLocalSecurityCallback().getQuota() != null) {
+				Long space = fileUploadBase.getLocalSecurityCallback().getQuota().getRemainingSpace();
+				if(space != null) {
+					remainingSpace = space.longValue();
+				}
+				Long limit = fileUploadBase.getLocalSecurityCallback().getQuota().getUlLimitKB();
+				if(limit != null) {
+					uploadLimit = limit.longValue();
+				}
 			}
+			
+			uploadCtr = new FileUploadController(wControl, fileUploadBase, ureq, uploadLimit, remainingSpace, mimeTypes,
+					true, false, true, true, false);
+			listenTo(uploadCtr);
+			// set specific upload path
+			uploadCtr.setUploadRelPath(uploadRelPath);
+			mainVC.put("uploader", uploadCtr.getInitialComponent());
 		}
-		uploadCtr = new FileUploadController(wControl, fileUploadBase, ureq, uploadLimit, remainingSpace, mimeTypes,
-				true, false, true, true, false);
-		
-		listenTo(uploadCtr);
-		// set specific upload path
-		uploadCtr.setUploadRelPath(uploadRelPath);
-
-		mainVC.put("uploader", uploadCtr.getInitialComponent());
 
 		putInitialPanel(mainVC);
 	}
@@ -264,7 +265,7 @@ public class FileLinkChooserController extends BasicController {
 			// no defined suffixes => all allowed
 			return true;
 		} else {
-			// check if siffix one of allowed suffixes
+			// check if suffix one of allowed suffixes
 			String suffix = getSuffix(filename);
 			for (String allowedSuffix : suffixes) {
 				if (allowedSuffix.equals(suffix)) {
@@ -282,12 +283,9 @@ public class FileLinkChooserController extends BasicController {
 			allowedSuffixes.append(allowedSuffix);
 		}
 		String suffix = getSuffix(fileName);
-		getWindowControl().setError(
-				getTranslator()
-						.translate(
-								"upload.error.incorrect.filetype",
-								new String[] { "." + suffix,
-										allowedSuffixes.toString() }));
+		getWindowControl().setError(getTranslator()
+				.translate("upload.error.incorrect.filetype",
+						new String[] { "." + suffix,allowedSuffixes.toString() }));
 	}
 
 	private String getSuffix(String filename) {
diff --git a/src/main/java/org/olat/core/commons/controllers/linkchooser/_content/filechooser.html b/src/main/java/org/olat/core/commons/controllers/linkchooser/_content/filechooser.html
index dc7781de0908228465b6d9519465190c4a952a07..55dbaf00c04a483aaa8e3890dcc6b8cc799c3fd5 100644
--- a/src/main/java/org/olat/core/commons/controllers/linkchooser/_content/filechooser.html
+++ b/src/main/java/org/olat/core/commons/controllers/linkchooser/_content/filechooser.html
@@ -1,12 +1,16 @@
 <div id="o_fc_select" class="clearfix" >
-	<a href="#o_top" class="btn btn-default pull-right" onclick="jQuery('#o_fc_select').fadeOut(300, function(){ jQuery('#o_fc_upload').fadeIn(300); });">
-		<span>$r.translate("filechooser.upload.title")</span></a>
-	<h3>$r.translate("filechooser.select.title")</h3>
+	#if($r.available("uploader"))
+		<a href="#o_top" class="btn btn-default pull-right" onclick="jQuery('#o_fc_select').fadeOut(300, function(){ jQuery('#o_fc_upload').fadeIn(300); });">
+			<span>$r.translate("filechooser.upload.title")</span></a>
+		<h3>$r.translate("filechooser.select.title")</h3>
+	#end
 	$r.render("stTree")
 </div>
+#if($r.available("uploader"))
 <div id="o_fc_upload" class="clearfix" style="display: none">
 	<a href="#o_top" class="btn btn-default pull-right" onclick="jQuery('#o_fc_upload').fadeOut(300, function() { jQuery('#o_fc_select').fadeIn(300); });">
 		<span>$r.translate("filechooser.select.title")</span></a>
 	<h3>$r.translate("filechooser.upload.title")</h3>
 	$r.render("uploader")
-</div>
\ No newline at end of file
+</div>
+#end
\ No newline at end of file
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 8cc58b77b91c756cae58f2baecf8d338d2e2e69d..e44be4aef6e4c0b0d30aa0bff805b6c34f6a7331 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
@@ -364,11 +364,11 @@ public class FileCopyController extends LinkChooserController {
 				String description = translate("ul.tooManyRevisions.description", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size())});
 				
 				removeAsListenerAndDispose(revisionListCtr);
-				revisionListCtr = new RevisionListController(ureq, getWindowControl(), versionable, title, description, false);
+				revisionListCtr = new RevisionListController(ureq, getWindowControl(), versionable, null, description, false);
 				listenTo(revisionListCtr);
 				
 				removeAsListenerAndDispose(revisionListDialogBox);
-				revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent());
+				revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent(), true, title);
 				listenTo(revisionListDialogBox);
 				
 				revisionListDialogBox.activate();
diff --git a/src/main/java/org/olat/core/commons/modules/bc/FileSelection.java b/src/main/java/org/olat/core/commons/modules/bc/FileSelection.java
index 604a4c6c8313b17d8fa1923f920671a111f4fdc0..88f5aec34f12b43f1791b5045b9bbf6aabaa5f23 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/FileSelection.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/FileSelection.java
@@ -28,11 +28,11 @@ package org.olat.core.commons.modules.bc;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Iterator;
 import java.util.List;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.util.FileUtils;
+import org.olat.core.util.StringHelper;
 
 public class FileSelection {
 
@@ -86,12 +86,12 @@ public class FileSelection {
 	 * @return HTML Fragment.
 	 */
 	public String renderAsHtml() {
-		StringBuilder sb = new StringBuilder();
+		StringBuilder sb = new StringBuilder(255);
 		sb.append("<ul>");
-		for (Iterator<String> iter = files.iterator(); iter.hasNext();) {
-			sb.append("<li>");
-			sb.append(currentContainerRelPath + "/" + iter.next());
-			sb.append("</li>");
+		for (String filename:files) {
+			sb.append("<li>")
+			  .append(currentContainerRelPath).append("/").append(StringHelper.escapeHtml(filename))
+			  .append("</li>");
 		}
 		sb.append("</ul>");
 		return sb.toString();
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 0a361a0dd2c5df13749420b7505f9c33e3eb7e1b..7597003e4e80ef71b629495084949777f45a0bd5 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
@@ -30,14 +30,12 @@ import static java.util.Arrays.asList;
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Set;
 import java.util.regex.Pattern;
 
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.commands.FolderCommandStatus;
 import org.olat.core.commons.modules.bc.meta.MetaInfo;
 import org.olat.core.commons.modules.bc.meta.MetaInfoFactory;
@@ -47,6 +45,7 @@ import org.olat.core.commons.modules.bc.version.VersionCommentController;
 import org.olat.core.commons.modules.bc.vfs.OlatRootFileImpl;
 import org.olat.core.commons.services.image.ImageService;
 import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.FileElement;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
@@ -54,6 +53,7 @@ import org.olat.core.gui.components.form.flexible.elements.StaticTextElement;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.Form;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -78,6 +78,7 @@ import org.olat.core.util.vfs.VFSLockManager;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.version.Versionable;
 import org.olat.core.util.vfs.version.Versions;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * <h3>Description</h3>
@@ -113,12 +114,11 @@ public class FileUploadController extends FormBasicController {
 	private VersionCommentController unlockCtr;
 	private DialogBoxController overwriteDialog;
 	private DialogBoxController lockedFileDialog;
-	private VFSLeaf newFile = null;
-	private VFSItem existingVFSItem = null;
+	private VFSLeaf newFile;
+	private VFSItem existingVFSItem;
 	private long uploadLimitKB;
 	private long remainingQuotKB;
 	private Set<String> mimeTypes;
-	private FilesInfoMBean fileInfoMBean;
 	//
 	// Form elements
 	private FileElement fileEl;
@@ -139,9 +139,15 @@ public class FileUploadController extends FormBasicController {
 	
 	private static Pattern imageExtPattern = Pattern.compile("\\b.(jpg|jpeg|png)\\b");
 	private static final Pattern validSubPathPattern = Pattern.compile("[\\p{Alnum}-_\\./]*");		
-	
-	private final VFSLockManager vfsLockManager;
 
+	@Autowired
+	private ImageService imageHelper;
+	@Autowired
+	private FilesInfoMBean fileInfoMBean;
+	@Autowired
+	private VFSLockManager vfsLockManager;
+	@Autowired
+	private MetaInfoFactory metaInfoFactory;
 
 	private String subfolderPath;
 	private TextElement targetSubPath ;
@@ -176,17 +182,13 @@ public class FileUploadController extends FormBasicController {
 	public FileUploadController(WindowControl wControl, VFSContainer curContainer, UserRequest ureq, long upLimitKB, long remainingQuotKB,
 			Set<String> mimeTypesRestriction, boolean showTargetPath, boolean showMetadata, boolean resizeImg, boolean showCancel, boolean showTitle, String subfolderPath) {
 		super(ureq, wControl, "file_upload");
-		vfsLockManager = CoreSpringFactory.getImpl(VFSLockManager.class);
 		setVariables(curContainer, upLimitKB, remainingQuotKB, mimeTypesRestriction, showTargetPath, showMetadata, resizeImg, showCancel, showTitle, subfolderPath);
 		initForm(ureq);
 	}
 	
-	
-	
 	private void setVariables(VFSContainer curContainer, long upLimitKB, long remainingQuotKB, Set<String> mimeTypesRestriction, boolean showTargetPath,
 			boolean showMetadata, boolean resizeImg, boolean showCancel, boolean showTitle, String subfolderPath) {
 		this.currentContainer = curContainer;
-		this.fileInfoMBean = (FilesInfoMBean) CoreSpringFactory.getBean(FilesInfoMBean.class.getCanonicalName());
 		this.mimeTypes = mimeTypesRestriction;
 		this.showTitle = showTitle;
 		this.showTargetPath = showTargetPath;
@@ -239,8 +241,8 @@ public class FileUploadController extends FormBasicController {
 			}
 		}
 
-		
 		fileEl = uifactory.addFileElement(getWindowControl(), "fileEl", "ul.file", fileUpload);
+		fileEl.addActionListener(FormEvent.ONCHANGE);
 		
 		setMaxUploadSizeKB((uploadLimitKB < remainingQuotKB ? uploadLimitKB : remainingQuotKB));
 		fileEl.setMandatory(true, "NoFileChoosen");
@@ -296,161 +298,35 @@ public class FileUploadController extends FormBasicController {
 	}
 
 	@Override
-	protected void formOK(UserRequest ureq) {
-		if(targetSubPath != null) setUploadRelPath(targetSubPath.getValue());
-		if ( fileEl.isUploadSuccess()) {
-			// check for available space
-			if (remainingQuotKB != -1) {
-				if (fileEl.getUploadFile().length() / 1024 > remainingQuotKB) {
-					fileEl.setErrorKey("QuotaExceeded", null);
-					fileEl.getUploadFile().delete();
-					return;
-				}				
-			}
-			String fileName = fileEl.getUploadFileName();
-			
-			File uploadedFile = fileEl.getUploadFile();
-			if(resizeImg && fileName != null && imageExtPattern.matcher(fileName.toLowerCase()).find()
-					&& resizeEl.isSelected(0)) {
-				String extension = FileUtils.getFileSuffix(fileName);
-				File imageScaled = new File(uploadedFile.getParentFile(), "scaled_" + uploadedFile.getName() + "." + extension);
-				ImageService imageHelper = CoreSpringFactory.getImpl(ImageService.class);
-				if(imageHelper.scaleImage(uploadedFile, extension, imageScaled, 1280, 1280, false) != null) {
-					//problem happen, special GIF's (see bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6358674)
-					//don't try to scale if not all ok 
-					uploadedFile = imageScaled;
-				}
-			}
-			
-			// check if such a filename does already exist
-			existingVFSItem = uploadVFSContainer.resolve(fileName);
-			if (existingVFSItem == null) {
-				// save file and finish
-				newFile = uploadVFSContainer.createChildLeaf(fileName);
-				
-				boolean success = true;
-				if(newFile == null) {
-					// FXOLAT-409 somehow "createChildLeaf" did not succeed...
-					// if so, there is alread a error-msg in log (vfsContainer.createChildLeaf)
-					success = false;
-				} else {
-					try(InputStream in = new FileInputStream(uploadedFile);
-						OutputStream out = newFile.getOutputStream(false)) {
-						FileUtils.bcopy(in, out, "uploadTmpFileToDestFile");
-						uploadedFile.delete();
-					} catch (IOException e) {
-						success = false;
-					}
-				}
-				
-				if (success) {
-					String filePath = (uploadRelPath == null ? "" : uploadRelPath + "/") + newFile.getName();
-					finishSuccessfullUpload(filePath, newFile, ureq);
-					fileInfoMBean.logUpload(newFile.getSize());
-					fireEvent(ureq, Event.DONE_EVENT);										
-				} else {
-					showError("failed");
-					status = FolderCommandStatus.STATUS_FAILED;
-					fireEvent(ureq, Event.FAILED_EVENT);					
-				}
-			} else {
-				// file already exists... upload anyway with new filename and
-				// in the folder manager status.
-				// rename file and ask user what to do
-				if ( ! (existingVFSItem instanceof LocalImpl)) {
-					throw new AssertException("Can only LocalImpl VFS items, don't know what to do with file of type::" + existingVFSItem.getClass().getCanonicalName());
-				}
-
-				String renamedFilename = VFSManager.rename(uploadVFSContainer, existingVFSItem.getName());
-				newFile = uploadVFSContainer.createChildLeaf(renamedFilename);
-
-				// Copy content to tmp file
-				InputStream in = null;
-				BufferedOutputStream out = null;
-				boolean success = false;
-				try {
-					in = new FileInputStream(uploadedFile);
-					out = new BufferedOutputStream(newFile.getOutputStream(false));
-					if (in != null) {
-						success = FileUtils.copy(in, out);					
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(fileEl == source) {
+			if(metaDataCtr != null) {
+				String filename = fileEl.getUploadFileName();
+				if(!FileUtils.validateFilename(filename)) {
+					String suffix = FileUtils.getFileSuffix(filename);
+					if(suffix != null && suffix.length() > 0) {
+						filename = filename.substring(0, filename.length() - suffix.length() - 1);
 					}
-					uploadedFile.delete();
-				} catch (FileNotFoundException e) {
-					success = false;
-				} finally {
-					FileUtils.closeSafely(in);
-					FileUtils.closeSafely(out);
-				}
-				
-				if (success) {
-					boolean locked = vfsLockManager.isLockedForMe(existingVFSItem, getIdentity(), ureq.getUserSession().getRoles());
-					if (locked) {
-						//the file is locked and cannot be overwritten
-						removeAsListenerAndDispose(lockedFileDialog);
-						lockedFileDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.lockedFile.title"), translate("ul.lockedFile.text", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel")));
-						listenTo(lockedFileDialog);
-						
-						lockedFileDialog.activate();
-					}
-					else if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
-						Versionable versionable = (Versionable)existingVFSItem;
-						Versions versions = versionable.getVersions();
-						String relPath = null;
-						if(existingVFSItem instanceof OlatRootFileImpl) {
-							relPath = ((OlatRootFileImpl)existingVFSItem).getRelPath();
-						}
-						int maxNumOfRevisions = FolderConfig.versionsAllowed(relPath);
-						if(maxNumOfRevisions == 0) {
-							//it's possible if someone change the configuration
-							// let calling method decide what to do.
-							removeAsListenerAndDispose(overwriteDialog);
-							overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.overwrite.threeoptions.title"), translate("ul.overwrite.threeoptions.text", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.overwrite"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel")));
-							listenTo(overwriteDialog);
-							
-							overwriteDialog.activate();
-							
-						} else if(versions.getRevisions().isEmpty() || maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) {
-							// let calling method decide what to do.
-							removeAsListenerAndDispose(overwriteDialog);
-							overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.overwrite.threeoptions.title"), translate("ul.versionoroverwrite", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.newVersion"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel")));
-							listenTo(overwriteDialog);
-							
-							overwriteDialog.activate();
-							
-						} else {
-						
-							String title = translate("ul.tooManyRevisions.title", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size())});
-							String description = translate("ul.tooManyRevisions.description", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size())});
-							
-							removeAsListenerAndDispose(revisionListCtr);
-							revisionListCtr = new RevisionListController(ureq, getWindowControl(), versionable, title, description, false);
-							listenTo(revisionListCtr);
-							
-							removeAsListenerAndDispose(revisionListDialogBox);
-							revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent());
-							listenTo(revisionListDialogBox);
-							
-							revisionListDialogBox.activate();
-						}
-					} else {
-						// let calling method decide what to do.
-						// for this, we put a list with "existing name" and "new name"
-						overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.overwrite.threeoptions.title"), translate("ul.overwrite.threeoptions.text", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.overwrite"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel")));
-						listenTo(overwriteDialog);
-						overwriteDialog.activate();
-					}
-				} else {
-					showError("failed");
-					status = FolderCommandStatus.STATUS_FAILED;
-					fireEvent(ureq, Event.FAILED_EVENT);					
+					filename = FileUtils.normalizeFilename(filename) + "." + suffix;
+					metaDataCtr.getFilenameEl().setExampleKey("mf.filename.warning", null);
 				}
+				metaDataCtr.setFilename(filename);
 			}
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		if(targetSubPath != null) setUploadRelPath(targetSubPath.getValue());
+		if ( fileEl.isUploadSuccess()) {
+			doUpload(ureq);
 		} else {
 			if (mainForm.getLastRequestError() == Form.REQUEST_ERROR_GENERAL ) {
 				showError("failed");				
 			} else if (mainForm.getLastRequestError() == Form.REQUEST_ERROR_FILE_EMPTY ) {
 				showError("failed");				
-			}else if (mainForm.getLastRequestError() == Form.REQUEST_ERROR_UPLOAD_LIMIT_EXCEEDED) {
+			} else if (mainForm.getLastRequestError() == Form.REQUEST_ERROR_UPLOAD_LIMIT_EXCEEDED) {
 				showError("QuotaExceeded");				
 			}
 			status = FolderCommandStatus.STATUS_FAILED;
@@ -473,120 +349,35 @@ public class FileUploadController extends FormBasicController {
 	@Override
 	public void event(UserRequest ureq, Controller source, Event event) {
 		if (source == overwriteDialog) {
-			
 			if (event instanceof ButtonClickedEvent) {
 				ButtonClickedEvent buttonClickedEvent = (ButtonClickedEvent) event;
 				if (buttonClickedEvent.getPosition() == 0) { //ok
-					if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
-						//new version
-						String relPath = null;
-						if(existingVFSItem instanceof OlatRootFileImpl) {
-							relPath = ((OlatRootFileImpl)existingVFSItem).getRelPath();
-						}
-						int maxNumOfRevisions = FolderConfig.versionsAllowed(relPath);
-						if(maxNumOfRevisions == 0) {
-							//someone play with the configuration
-							// Overwrite...
-							String fileName = existingVFSItem.getName();
-							existingVFSItem.delete();
-							newFile.rename(fileName);
-							
-							// ... and notify listeners.
-							finishUpload(ureq);
-						} else {
-							removeAsListenerAndDispose(commentVersionCtr);
-							removeAsListenerAndDispose(commentVersionDialogBox);
-							
-							boolean locked = vfsLockManager.isLocked(existingVFSItem);
-							commentVersionCtr = new VersionCommentController(ureq, getWindowControl(), locked, true);
-							listenTo(commentVersionCtr);
-							commentVersionDialogBox = new CloseableModalController(getWindowControl(), translate("save"), commentVersionCtr.getInitialComponent());
-							listenTo(commentVersionDialogBox);
-							commentVersionDialogBox.activate();
-						}
-					} else {
-						//if the file is locked, ask for unlocking it
-						if(vfsLockManager.isLocked(existingVFSItem)) {
-							removeAsListenerAndDispose(unlockCtr);
-							unlockCtr = new VersionCommentController(ureq,getWindowControl(), true, false);
-							listenTo(unlockCtr);
-							
-							removeAsListenerAndDispose(unlockDialogBox);
-							unlockDialogBox = new CloseableModalController(getWindowControl(), translate("ok"), unlockCtr.getInitialComponent());
-							listenTo(unlockDialogBox);
-							
-							unlockDialogBox.activate();
-							
-						} else {
-							// Overwrite...
-							String fileName = existingVFSItem.getName();
-							existingVFSItem.delete();
-							newFile.rename(fileName);
-							
-							// ... and notify listeners.
-							finishUpload(ureq);
-						}
-					}
+					doFinishOverwrite(ureq);
 				} else if (buttonClickedEvent.getPosition() == 1) { //not ok
 					// Upload renamed. Since we've already uploaded the file with a changed name, don't do anything much here...
-					this.fileOverwritten = true;
-
+					fileOverwritten = true;
 					// ... and notify listeners.
 					finishUpload(ureq);
 				} else if (buttonClickedEvent.getPosition() == 2) { // cancel
 					// Cancel. Remove the new file since it has already been uploaded. Note that we don't have to explicitly close the
 					// dialog box since it closes itself whenever something gets clicked.
-					newFile.deleteSilently();
-				} else {
-					throw new RuntimeException("Unknown button number " + buttonClickedEvent.getPosition());
+					doCancel(ureq);
 				}
 			}
 		} else if (source == lockedFileDialog) {
-
 			if (event instanceof ButtonClickedEvent) {
 				ButtonClickedEvent buttonClickedEvent = (ButtonClickedEvent) event;
-				switch(buttonClickedEvent.getPosition()) {
-					case 0: {
-						//upload the file with a new name
-						this.fileOverwritten = true;
-						// ... and notify listeners.
-						finishUpload(ureq);
-						break;
-					}
-					case 1: {//cancel
-						newFile.deleteSilently();
-						fireEvent(ureq, Event.CANCELLED_EVENT);
-						break;
-					}
-					default:
-						throw new RuntimeException("Unknown button number " + buttonClickedEvent.getPosition());
+				if(buttonClickedEvent.getPosition() == 0) {
+					//upload the file with a new name
+					fileOverwritten = true;
+					// ... and notify listeners.
+					finishUpload(ureq);
+				} else if(buttonClickedEvent.getPosition() == 1) {
+					doCancel(ureq);
 				}
 			}
 		} else if (source == commentVersionCtr) {
-			String comment = commentVersionCtr.getComment();
-			
-			Roles roles = ureq.getUserSession().getRoles();
-			boolean locked = vfsLockManager.isLocked(existingVFSItem);
-			if(locked && !commentVersionCtr.keepLocked()) {
-				vfsLockManager.unlock(existingVFSItem, getIdentity(), roles);
-			}
-			
-			commentVersionDialogBox.deactivate();
-			if(revisionListDialogBox != null) {
-				revisionListDialogBox.deactivate();
-			}
-			
-			//ok, new version of the file
-			Versionable existingVersionableItem = (Versionable)existingVFSItem;
-			boolean ok = existingVersionableItem.getVersions().addVersion(ureq.getIdentity(), comment, newFile.getInputStream());
-			if(ok) {
-				newFile.deleteSilently();
-				//what can i do if existingVFSItem is a container
-				if(existingVFSItem instanceof VFSLeaf) {
-					newFile = (VFSLeaf)existingVFSItem;
-				}
-			}
-			finishUpload(ureq);
+			doFinishComment(ureq);
 		} else if (source == unlockCtr) {
 			// Overwrite...
 			String fileName = existingVFSItem.getName();
@@ -597,7 +388,6 @@ public class FileUploadController extends FormBasicController {
 			
 			existingVFSItem.delete();
 			newFile.rename(fileName);
-
 			// ... and notify listeners.
 			finishUpload(ureq);
 			
@@ -606,61 +396,304 @@ public class FileUploadController extends FormBasicController {
 			revisionListCtr = null;
 			removeAsListenerAndDispose(revisionListDialogBox);
 			revisionListDialogBox = null;
-			
-			//remove the file
-			newFile.deleteSilently();
+			doCancel(ureq);
 		} else if (source == revisionListCtr) {
+			revisionListDialogBox.deactivate();
+			removeAsListenerAndDispose(revisionListDialogBox);
+			revisionListDialogBox = null;
+			
 			if(FolderCommandStatus.STATUS_CANCELED == revisionListCtr.getStatus()) {
-
-				revisionListDialogBox.deactivate();
-				removeAsListenerAndDispose(revisionListDialogBox);
-				revisionListDialogBox = null;
-
 				//don't want to delete revisions, clean the temporary file
-				if(newFile != null) {
-					newFile.deleteSilently();
-				}
+				doCancel(ureq);
+			} else if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
+				doFinishRevisionList(ureq);
+			}
+		}
+	}
+	
+	/**
+	 * Delete the uploaded file and send cancel event
+	 * @param ureq
+	 */
+	private void doCancel(UserRequest ureq) {
+		if(newFile != null) {
+			newFile.deleteSilently();
+		}
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+	
+	private void doFinishOverwrite(UserRequest ureq) {
+		if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
+			//new version
+			int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem();
+			if(maxNumOfRevisions == 0) {
+				//someone play with the configuration
+				// Overwrite...
+				String fileName = existingVFSItem.getName();
+				existingVFSItem.delete();
+				newFile.rename(fileName);
+				
+				// ... and notify listeners.
+				finishUpload(ureq);
 			} else {
-				if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
-
-					revisionListDialogBox.deactivate();
-					removeAsListenerAndDispose(revisionListDialogBox);
-					revisionListDialogBox = null;
-					
-					if(existingVFSItem.getParentContainer() != null) {
-						existingVFSItem = existingVFSItem.getParentContainer().resolve(existingVFSItem.getName());
-					}
-					
-					Versionable versionable = (Versionable)existingVFSItem;
-					Versions versions = versionable.getVersions();
-					int maxNumOfRevisions = FolderConfig.versionsAllowed(null);
-					if(maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) {
-						removeAsListenerAndDispose(commentVersionCtr);
-						removeAsListenerAndDispose(commentVersionDialogBox);
+				askForComment(ureq);
+			}
+		} else {
+			//if the file is locked, ask for unlocking it
+			if(vfsLockManager.isLocked(existingVFSItem)) {
+				askForUnlock(ureq);
+				
+			} else {
+				// Overwrite...
+				String fileName = existingVFSItem.getName();
+				existingVFSItem.delete();
+				newFile.rename(fileName);
+				
+				// ... and notify listeners.
+				finishUpload(ureq);
+			}
+		}
+	}
+	
+	private void doFinishComment(UserRequest ureq) {
+		String comment = commentVersionCtr.getComment();
+		
+		Roles roles = ureq.getUserSession().getRoles();
+		boolean locked = vfsLockManager.isLocked(existingVFSItem);
+		if(locked && !commentVersionCtr.keepLocked()) {
+			vfsLockManager.unlock(existingVFSItem, getIdentity(), roles);
+		}
+		
+		commentVersionDialogBox.deactivate();
+		if(revisionListDialogBox != null) {
+			revisionListDialogBox.deactivate();
+		}
+		
+		//ok, new version of the file
+		Versionable existingVersionableItem = (Versionable)existingVFSItem;
+		boolean ok = existingVersionableItem.getVersions().addVersion(ureq.getIdentity(), comment, newFile.getInputStream());
+		if(ok) {
+			newFile.deleteSilently();
+			//what can i do if existingVFSItem is a container
+			if(existingVFSItem instanceof VFSLeaf) {
+				newFile = (VFSLeaf)existingVFSItem;
+			}
+		}
+		finishUpload(ureq);
+	}
+	
+	private void doFinishRevisionList(UserRequest ureq) {
+		if(existingVFSItem.getParentContainer() != null) {
+			existingVFSItem = existingVFSItem.getParentContainer().resolve(existingVFSItem.getName());
+		}
+		
+		Versionable versionable = (Versionable)existingVFSItem;
+		Versions versions = versionable.getVersions();
+		int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem();
+		if(maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) {
+			askForComment(ureq);
+		} else {
+			askToReduceRevisionList(ureq, versionable);
+		}
+	}
+	
+	private int getMaxNumOfRevisionsOfExistingVFSItem() {
+		String relPath = null;
+		if(existingVFSItem instanceof OlatRootFileImpl) {
+			relPath = ((OlatRootFileImpl)existingVFSItem).getRelPath();
+		}
+		return FolderConfig.versionsAllowed(relPath);
+	}
+	
+	private void askToReduceRevisionList(UserRequest ureq, Versionable versionable) {
+		removeAsListenerAndDispose(revisionListCtr);
+		removeAsListenerAndDispose(revisionListDialogBox);
+		
+		Versions versions = versionable.getVersions();
+		int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem();
+		String[] params = new String[]{ Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size()) };
+		String title = translate("ul.tooManyRevisions.title", params);
+		String description = translate("ul.tooManyRevisions.description", params);
+		
+		revisionListCtr = new RevisionListController(ureq, getWindowControl(), versionable, null, description, false);
+		listenTo(revisionListCtr);
+		
+		revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent(), true, title);
+		listenTo(revisionListDialogBox);
+		revisionListDialogBox.activate();
+	}
+	
+	private void askForUnlock(UserRequest ureq) {
+		removeAsListenerAndDispose(unlockCtr);
+		removeAsListenerAndDispose(unlockDialogBox);
+		
+		unlockCtr = new VersionCommentController(ureq,getWindowControl(), true, false);
+		listenTo(unlockCtr);
+		String title = unlockCtr.getAndRemoveFormTitle();
+		unlockDialogBox = new CloseableModalController(getWindowControl(), translate("ok"), unlockCtr.getInitialComponent(), true, title);
+		listenTo(unlockDialogBox);
+		unlockDialogBox.activate();
+	}
+	
+	private void askForComment(UserRequest ureq) {
+		removeAsListenerAndDispose(commentVersionCtr);
+		removeAsListenerAndDispose(commentVersionDialogBox);
+
+		boolean locked = vfsLockManager.isLocked(existingVFSItem);
+		commentVersionCtr = new VersionCommentController(ureq, getWindowControl(), locked, true);
+		listenTo(commentVersionCtr);
+		String title = commentVersionCtr.getAndRemoveFormTitle();
+		commentVersionDialogBox = new CloseableModalController(getWindowControl(), translate("save"), commentVersionCtr.getInitialComponent(), true, title);
+		listenTo(commentVersionDialogBox);
+		commentVersionDialogBox.activate();
+	}
+	
+	private void doUpload(UserRequest ureq) {
+		// check for available space
+		if (remainingQuotKB != -1 && (fileEl.getUploadFile().length() / 1024 > remainingQuotKB)) {
+			fileEl.setErrorKey("QuotaExceeded", null);
+			fileEl.getUploadFile().delete();
+			return;			
+		}
+		
+		String fileName = fileEl.getUploadFileName();
+		if(metaDataCtr != null && StringHelper.containsNonWhitespace(metaDataCtr.getFilename())) {
+			fileName = metaDataCtr.getFilename();
+		}
+		
+		File uploadedFile = fileEl.getUploadFile();
+		if(resizeImg && fileName != null && imageExtPattern.matcher(fileName.toLowerCase()).find()
+				&& resizeEl.isSelected(0)) {
+			String extension = FileUtils.getFileSuffix(fileName);
+			File imageScaled = new File(uploadedFile.getParentFile(), "scaled_" + uploadedFile.getName() + "." + extension);
+			if(imageHelper.scaleImage(uploadedFile, extension, imageScaled, 1280, 1280, false) != null) {
+				//problem happen, special GIF's (see bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6358674)
+				//don't try to scale if not all ok 
+				uploadedFile = imageScaled;
+			}
+		}
+		
+		// check if such a filename does already exist
+		existingVFSItem = uploadVFSContainer.resolve(fileName);
+		if (existingVFSItem == null) {
+			uploadNewFile(ureq, uploadedFile, fileName);
+		} else {
+			// file already exists... upload anyway with new filename and
+			// in the folder manager status.
+			// rename file and ask user what to do
+			if ( ! (existingVFSItem instanceof LocalImpl)) {
+				throw new AssertException("Can only LocalImpl VFS items, don't know what to do with file of type::" + existingVFSItem.getClass().getCanonicalName());
+			}
 
-						boolean locked = vfsLockManager.isLocked(existingVFSItem);
-						commentVersionCtr = new VersionCommentController(ureq,getWindowControl(), locked, true);
-						listenTo(commentVersionCtr);
-						commentVersionDialogBox = new CloseableModalController(getWindowControl(), translate("save"), commentVersionCtr.getInitialComponent());
-						listenTo(commentVersionDialogBox);
-						commentVersionDialogBox.activate();
-					} else {
-						
-						removeAsListenerAndDispose(revisionListCtr);
-						revisionListCtr = new RevisionListController(ureq,getWindowControl(),versionable, false);
-						listenTo(revisionListCtr);
-						
-						removeAsListenerAndDispose(revisionListDialogBox);
-						revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent());
-						listenTo(revisionListDialogBox);
-						
-						revisionListDialogBox.activate();
-					}
+			String renamedFilename = VFSManager.rename(uploadVFSContainer, existingVFSItem.getName());
+			newFile = uploadVFSContainer.createChildLeaf(renamedFilename);
+
+			// Copy content to tmp file
+			boolean success = false;
+			try(InputStream in = new FileInputStream(uploadedFile);
+					BufferedOutputStream out = new BufferedOutputStream(newFile.getOutputStream(false)))  {
+				success = FileUtils.copy(in, out);					
+				uploadedFile.delete();
+			} catch (IOException e) {
+				success = false;
+			}
+			
+			if (success) {
+				boolean locked = vfsLockManager.isLockedForMe(existingVFSItem, getIdentity(), ureq.getUserSession().getRoles());
+				if (locked) {
+					//the file is locked and cannot be overwritten
+					lockedFileDialog(ureq, renamedFilename);
+				} else if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
+					uploadVersionedFile(ureq, renamedFilename);
+				} else {
+					askOverwriteOrRename(ureq, renamedFilename);
 				}
+			} else {
+				showError("failed");
+				status = FolderCommandStatus.STATUS_FAILED;
+				fireEvent(ureq, Event.FAILED_EVENT);					
 			}
 		}
 	}
 	
+	private void lockedFileDialog(UserRequest ureq, String renamedFilename) {
+		removeAsListenerAndDispose(lockedFileDialog);
+		String title = translate("ul.lockedFile.title");
+		String text = translate("ul.lockedFile.text", new String[] { existingVFSItem.getName(), renamedFilename} );
+		lockedFileDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), title, text,
+				asList(translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel")));
+		listenTo(lockedFileDialog);
+		lockedFileDialog.activate();
+	}
+	
+	private void uploadVersionedFile(UserRequest ureq, String renamedFilename) {
+		Versionable versionable = (Versionable)existingVFSItem;
+		Versions versions = versionable.getVersions();
+		int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem();
+		if(maxNumOfRevisions == 0) {
+			//it's possible if someone change the configuration
+			// let calling method decide what to do.
+			askOverwriteOrRename(ureq, renamedFilename);
+		} else if(versions.getRevisions().isEmpty() || maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) {
+			// let calling method decide what to do.
+			askNewVersionOrRename(ureq, renamedFilename);
+		} else {
+			//too many revisions
+			askToReduceRevisionList(ureq, versionable);
+		}
+	}
+	
+	private void askOverwriteOrRename(UserRequest ureq, String renamedFilename) {
+		removeAsListenerAndDispose(overwriteDialog);
+		// let calling method decide what to do.
+		// for this, we put a list with "existing name" and "new name"
+		overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(),
+				translate("ul.overwrite.threeoptions.title"), translate("ul.overwrite.threeoptions.text", new String[] {existingVFSItem.getName(), renamedFilename} ),
+				asList(translate("ul.overwrite.threeoptions.overwrite"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel")));
+		listenTo(overwriteDialog);
+		overwriteDialog.activate();
+	}
+	
+	private void askNewVersionOrRename(UserRequest ureq, String renamedFilename) {
+		removeAsListenerAndDispose(overwriteDialog);
+		overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(),
+				translate("ul.overwrite.threeoptions.title"), translate("ul.versionoroverwrite", new String[] {existingVFSItem.getName(), renamedFilename} ),
+				asList(translate("ul.overwrite.threeoptions.newVersion"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel")));
+		listenTo(overwriteDialog);
+		overwriteDialog.activate();
+	}
+	
+	private void uploadNewFile(UserRequest ureq, File uploadedFile, String filename) {
+		// save file and finish
+		newFile = uploadVFSContainer.createChildLeaf(filename);
+		
+		boolean success = true;
+		if(newFile == null) {
+			// FXOLAT-409 somehow "createChildLeaf" did not succeed...
+			// if so, there is alread a error-msg in log (vfsContainer.createChildLeaf)
+			success = false;
+		} else {
+			try(InputStream in = new FileInputStream(uploadedFile);
+				OutputStream out = newFile.getOutputStream(false)) {
+				FileUtils.bcopy(in, out, "uploadTmpFileToDestFile");
+				uploadedFile.delete();
+			} catch (IOException e) {
+				success = false;
+			}
+		}
+		
+		if (success) {
+			String filePath = (uploadRelPath == null ? "" : uploadRelPath + "/") + newFile.getName();
+			finishSuccessfullUpload(filePath, newFile, ureq);
+			fileInfoMBean.logUpload(newFile.getSize());
+			fireEvent(ureq, Event.DONE_EVENT);										
+		} else {
+			showError("failed");
+			status = FolderCommandStatus.STATUS_FAILED;
+			fireEvent(ureq, Event.FAILED_EVENT);					
+		}
+	}
+	
 	private void finishUpload(UserRequest ureq) {
 		// in both cases the upload must be finished and notified with a FolderEvent
 		String filePath = (uploadRelPath == null ? "" : uploadRelPath + "/") + newFile.getName();
@@ -681,11 +714,11 @@ public class FileUploadController extends FormBasicController {
 		if (item instanceof OlatRootFileImpl) {
 			OlatRootFileImpl relPathItem = (OlatRootFileImpl) item;
 			// create meta data
-			MetaInfo meta = CoreSpringFactory.getImpl(MetaInfoFactory.class).createMetaInfoFor(relPathItem);
+			MetaInfo meta = metaInfoFactory.createMetaInfoFor(relPathItem);
 			if (metaDataCtr != null) {
 				meta = metaDataCtr.getMetaInfo(meta);
 			}
-			meta.setAuthor(ureq.getIdentity());
+			meta.setAuthor(getIdentity());
 			meta.clearThumbnails();//if overwrite an older file
 			meta.write();
 		}
@@ -836,27 +869,37 @@ public class FileUploadController extends FormBasicController {
 				targetSubPath.clearError();
 			}
 		}
-		
 		// Check file name
-		String fileName = fileEl.getUploadFileName();
-		if (!StringHelper.containsNonWhitespace(fileName)) {
-			fileEl.setErrorKey("NoFileChosen", null);
-			return false;
+		if(metaDataCtr != null && StringHelper.containsNonWhitespace(metaDataCtr.getFilename())) {
+			return validateFilename(metaDataCtr.getFilename(), metaDataCtr.getFilenameEl());
+		}
+		String filename = fileEl.getUploadFileName();
+		return validateFilename(filename, fileEl);
+	}
+	
+	private boolean validateFilename(String filename, FormItem itemEl) {
+		itemEl.clearError();
+		
+		
+		boolean allOk = true;
+		if (!StringHelper.containsNonWhitespace(filename)) {
+			itemEl.setErrorKey("NoFileChosen", null);
+			allOk &= false;
 		}
 
-		boolean isFilenameValid = FileUtils.validateFilename(fileName);		
+		boolean isFilenameValid = FileUtils.validateFilename(filename);		
 		if(!isFilenameValid) {
-			fileEl.setErrorKey("cfile.name.notvalid", null);
-			return false;
+			itemEl.setErrorKey("cfile.name.notvalid", null);
+			allOk &= false;
 		}
 		if (remainingQuotKB != -1 
 			&& fileEl.getUploadFile().length() / 1024 > remainingQuotKB) {
-			
 			fileEl.clearError();
 			String supportAddr = WebappHelper.getMailConfig("mailQuota");
 			getWindowControl().setError(translate("ULLimitExceeded", new String[] { Formatter.roundToString((uploadLimitKB+0f) / 1000, 1), supportAddr }));
-			return false;
+			allOk &= false;
 		}
-		return true;
+		
+		return allOk;
 	}
 }
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUpload.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUpload.java
index b782e332be93468a63a0d0f7dbfb8925ff4228e2..f8d16350649da824299dff2b3c93c09756b33736 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUpload.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUpload.java
@@ -75,7 +75,7 @@ public class CmdUpload extends BasicController implements FolderCommand {
 	private String uploadFileName;
 	private VFSLeaf vfsNewFile;
 	private long quotaKB;
-	private int uploadLimitKB;
+	private long uploadLimitKB;
 	private boolean overwritten = false;
 	private FileUploadController fileUploadCtr;
 	private boolean cancelResetsForm;
@@ -93,13 +93,14 @@ public class CmdUpload extends BasicController implements FolderCommand {
 		this.showMetadata = showMetadata;
 	}
 
+	@Override
 	public Controller execute(FolderComponent fc, UserRequest ureq, WindowControl windowControl, Translator trans) {
 		return execute(fc, ureq, trans, false);
 	}
 
-	public Controller execute(FolderComponent fc, UserRequest ureq, Translator trans, boolean cancelResetsForm) {
+	public Controller execute(FolderComponent fc, UserRequest ureq, Translator trans, boolean cancelResetsButton) {
 		this.folderComponent = fc;
-		this.cancelResetsForm = cancelResetsForm;
+		this.cancelResetsForm = cancelResetsButton;
 		
 		setTranslator(trans);
 		currentContainer = folderComponent.getCurrentContainer();
@@ -130,21 +131,25 @@ public class CmdUpload extends BasicController implements FolderCommand {
 			}
 		}		
 		// set wether we have a quota on this folder
-		if (quotaKB == Quota.UNLIMITED) ubar.setIsNoMax(true);
-		else ubar.setMax(quotaKB / 1024);
+		if (quotaKB == Quota.UNLIMITED) {
+			ubar.setIsNoMax(true);
+		} else {
+			ubar.setMax(quotaKB / 1024);
+		}
 		// set default ulLimit if none is defined...
-		if (uploadLimitKB == Quota.UNLIMITED)
-			uploadLimitKB = (int) QuotaManager.getInstance().getDefaultQuotaDependingOnRole(ureq.getIdentity()).getUlLimitKB().longValue();
+		if (uploadLimitKB == Quota.UNLIMITED) {
+			uploadLimitKB = QuotaManager.getInstance().getDefaultQuotaDependingOnRole(ureq.getIdentity()).getUlLimitKB().longValue();
+		}
 		
 		// Add file upload form
-		int remainingQuotaKB = (int) quotaKB - (int) actualUsage;
-		if (quotaKB == Quota.UNLIMITED) remainingQuotaKB = (int) quotaKB;
+		long remainingQuotaKB =  quotaKB - actualUsage;
+		if (quotaKB == Quota.UNLIMITED) remainingQuotaKB = quotaKB;
 		else if (quotaKB - actualUsage < 0) remainingQuotaKB = 0;
-		else remainingQuotaKB = (int) quotaKB - (int) actualUsage;
+		else remainingQuotaKB = quotaKB - actualUsage;
+		
 		removeAsListenerAndDispose(fileUploadCtr);
-
 		fileUploadCtr = new FileUploadController(getWindowControl(), currentContainer, ureq, uploadLimitKB, remainingQuotaKB, null,
-				true, showMetadata, true, showCancel, true);
+				true, showMetadata, true, showCancel, false);
 		listenTo(fileUploadCtr);
 		mainVC.put("fileUploadCtr", fileUploadCtr.getInitialComponent());
 		mainVC.contextPut("showFieldset", Boolean.TRUE);
@@ -201,7 +206,7 @@ public class CmdUpload extends BasicController implements FolderCommand {
 	
 	@Override
 	public String getModalTitle() {
-		return translate("ul.quote");
+		return translate("ul");
 	}
 
 	public void event(UserRequest ureq, Component source, Event event) {
diff --git a/src/main/java/org/olat/core/commons/modules/bc/meta/MetaInfoFormController.java b/src/main/java/org/olat/core/commons/modules/bc/meta/MetaInfoFormController.java
index 7e41c6e7a546563557830c6c684b559be3c4c46e..d1b606f3a4735ab95ef6b90bb778336220526e3d 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/meta/MetaInfoFormController.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/meta/MetaInfoFormController.java
@@ -56,6 +56,7 @@ import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSLockManager;
 import org.olat.core.util.vfs.lock.LockInfo;
 import org.olat.user.UserManager;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * This is the metadata flexiform controller with or without upload capability.
@@ -78,9 +79,13 @@ public class MetaInfoFormController extends FormBasicController {
 	private String resourceUrl;
 	
 	private final Roles roles;
-	private final UserManager userManager;
-	private final VFSLockManager vfsLockManager;
-	private final MetaInfoFactory metaInfoFactory;
+	
+	@Autowired
+	private UserManager userManager;
+	@Autowired
+	private VFSLockManager vfsLockManager;
+	@Autowired
+	private MetaInfoFactory metaInfoFactory;
 
 	/**
 	 * Use this controller for editing meta data of an existing file.
@@ -95,9 +100,6 @@ public class MetaInfoFormController extends FormBasicController {
 		this.resourceUrl = resourceUrl;
 		// load the metainfo
 		roles = ureq.getUserSession().getRoles();
-		userManager = CoreSpringFactory.getImpl(UserManager.class);
-		vfsLockManager = CoreSpringFactory.getImpl(VFSLockManager.class);
-		metaInfoFactory = CoreSpringFactory.getImpl(MetaInfoFactory.class);
 		initForm(ureq);
 	}
 
@@ -112,9 +114,6 @@ public class MetaInfoFormController extends FormBasicController {
 	public MetaInfoFormController(UserRequest ureq, WindowControl control, Form parentForm) {
 		super(ureq, control, FormBasicController.LAYOUT_DEFAULT, null, parentForm);
 		roles = ureq.getUserSession().getRoles();
-		userManager = CoreSpringFactory.getImpl(UserManager.class);
-		vfsLockManager = CoreSpringFactory.getImpl(VFSLockManager.class);
-		metaInfoFactory = CoreSpringFactory.getImpl(MetaInfoFactory.class);
 		isSubform = true;
 		initForm(ureq);
 	}
@@ -132,9 +131,6 @@ public class MetaInfoFormController extends FormBasicController {
 		isSubform = true;
 		this.item = vfsItem;
 		roles = ureq.getUserSession().getRoles();
-		userManager = CoreSpringFactory.getImpl(UserManager.class);
-		vfsLockManager = CoreSpringFactory.getImpl(VFSLockManager.class);
-		metaInfoFactory = CoreSpringFactory.getImpl(MetaInfoFactory.class);
 		initForm(ureq);
 	}
 	
@@ -189,21 +185,19 @@ public class MetaInfoFormController extends FormBasicController {
 			setFormTitle("mf.metadata.title");
 		}
 		setFormContextHelp("Folders#_metadata");
-
-		// filename
-		if (!isSubform) {
-			initialFilename = item.getName();
-			filename = uifactory.addTextElement("filename", "mf.filename", -1, item.getName(), formLayout);
-			filename.setEnabled(item.canRename() == VFSConstants.YES);
-			filename.setNotEmptyCheck("mf.error.empty");
-			filename.setMandatory(true);
-		}
 		
 		MetaInfo meta = item instanceof OlatRelPathImpl ? metaInfoFactory.createMetaInfoFor((OlatRelPathImpl)item) : null;
 
 		// title
 		String titleVal = (meta != null ? meta.getTitle() : null);
 		title = uifactory.addTextElement("title", "mf.title", -1, titleVal, formLayout);
+		
+		// filename
+		initialFilename = (item == null ? null : item.getName());
+		filename = uifactory.addTextElement("filename", "mf.filename", -1, initialFilename, formLayout);
+		filename.setEnabled(item == null || item.canRename() == VFSConstants.YES);
+		filename.setNotEmptyCheck("mf.error.empty");
+		filename.setMandatory(true);
 
 		// comment/description
 		String commentVal = (meta != null ? meta.getComment() : null);
@@ -405,6 +399,14 @@ public class MetaInfoFormController extends FormBasicController {
 		return filename.getValue();
 	}
 	
+	public TextElement getFilenameEl() {
+		return filename;
+	}
+	
+	public void setFilename(String name) {
+		filename.setValue(name);
+	}
+	
 	public MetaInfo getMetaInfo(MetaInfo meta) {
 		meta.setCreator(creator.getValue());
 		meta.setComment(comment.getValue());
diff --git a/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_de.properties
index 11c377813147cc714505b2c7f7bd2b76d4ffd4d8..ea72b9a004f2245d64a3018ee671f5af021a259b 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_de.properties
@@ -14,6 +14,7 @@ mf.error.filename.exists=Ein Objekt mit gleichem Namen existiert bereits.
 mf.error.filename.invalidchars=Der Name des Objektes enth\u00E4lt ung\u00FCltige Zeichen.
 mf.file=Datei
 mf.filename=Dateiname
+mf.filename.warning=<i class="o_icon o_icon_warn"> </i> Dieser Dateiname enth\u00E4lt unzul\u00E4ssige Zeichen und die wurden entfernt.
 mf.header=Metadaten Datei/Ordner
 mf.language=Sprache
 mf.lastModified=Datum letzte \u00C4nderung
diff --git a/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_en.properties
index 8a20a599602914b64b10b6426a4ee91ae2c2fb86..aa2ac8587b1d46c7ca17b1660461a929d3f1a02d 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_en.properties
@@ -14,6 +14,7 @@ mf.error.filename.exists=An object with that name already exists.
 mf.error.filename.invalidchars=The object's name contains invalid characters.
 mf.file=File
 mf.filename=File name
+mf.filename.warning=<i class="o_icon o_icon_warn"> </i> This file name contains invalid characters and they were removed.
 mf.header=Metadata file/folder
 mf.language=Language
 mf.lastModified=Last modified\:
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/VersionCommentController.java b/src/main/java/org/olat/core/commons/modules/bc/version/VersionCommentController.java
index a3687157edd48341bd7f1267ed067a96bb023b0b..b844f1224f4ef1c94acdd06d0e8ab01d4cc433f1 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/VersionCommentController.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/version/VersionCommentController.java
@@ -60,7 +60,7 @@ public class VersionCommentController extends FormBasicController {
 		
 		initForm(ureq);
 	}
-	
+
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		if(comment && lock) {
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_content/revisions.html b/src/main/java/org/olat/core/commons/modules/bc/version/_content/revisions.html
index 1dfcf16e55486f39f44170b14fcd723a7bdb4ab3..cf46480a75b14198b8676913f93d6399a5d78f75 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_content/revisions.html
+++ b/src/main/java/org/olat/core/commons/modules/bc/version/_content/revisions.html
@@ -2,6 +2,6 @@
 	<h5>$title</h5>
 #end
 #if ($description)
-	<p>$description</p>
+	<p class="o_info">$description</p>
 #end
 $r.render("revisionList")
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java
index 3a68043f7fcc0d43fb1afbac44c7ac20eb488d19..e969d7195afb544218b62282926bdb7c6a3475a6 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java
@@ -433,6 +433,14 @@ public abstract class FormBasicController extends BasicController implements IFo
 			}
 		}
 	}
+	
+	public String getAndRemoveFormTitle() {
+		String title = (String)flc.contextGet("off_title");
+		if(title != null) {
+			flc.contextRemove("off_title");
+		}
+		return title;
+	}
 
 	/**
 	 * Set an optional form title that is rendered as a fieldset legend. If you
diff --git a/src/main/java/org/olat/core/util/FileUtils.java b/src/main/java/org/olat/core/util/FileUtils.java
index aae8b418a19a5e675f18cc0c0a33454c3600ad72..420739154cea3b2fbf4201fc932833e235b677c6 100644
--- a/src/main/java/org/olat/core/util/FileUtils.java
+++ b/src/main/java/org/olat/core/util/FileUtils.java
@@ -852,6 +852,8 @@ public class FileUtils {
 		return nameSanitized;
 	}
 	
+	
+	
 	/**
 	 * Creates a new directory in the specified directory, using the given prefix and suffix strings to generate its name.
 	 * It uses File.createTempFile() and should provide a unique name.
diff --git a/src/main/java/org/olat/core/util/vfs/VirtualContainer.java b/src/main/java/org/olat/core/util/vfs/VirtualContainer.java
index 4e7ebc5eddd948213fd6f63db5eb07bab501b54d..bffa9376a2ad6d4d4b0de4522b3df0b4a861eaf1 100644
--- a/src/main/java/org/olat/core/util/vfs/VirtualContainer.java
+++ b/src/main/java/org/olat/core/util/vfs/VirtualContainer.java
@@ -27,7 +27,6 @@
 package org.olat.core.util.vfs;
 
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
@@ -58,16 +57,18 @@ public class VirtualContainer extends AbstractVirtualContainer {
 	}
 	
 	public List<VFSItem> getItems() {
-		return getItems(null);
+		return children;
 	}
 
 	public List<VFSItem> getItems(VFSItemFilter filter) {
-		if (filter == null) return children;
-		else {
-			List<VFSItem> filtered = new ArrayList<VFSItem>();
-			for (Iterator<VFSItem> iter = children.iterator(); iter.hasNext();) {
-				VFSItem vfsItem = iter.next();
-				if (filter.accept(vfsItem)) filtered.add(vfsItem);
+		if (filter == null) {
+			return children;
+		} else {
+			List<VFSItem> filtered = new ArrayList<VFSItem>(children.size());
+			for (VFSItem vfsItem : children) {
+				if (filter.accept(vfsItem)) {
+					filtered.add(vfsItem);
+				}
 			}
 			return filtered;
 		}
diff --git a/src/main/java/org/olat/course/MergedCourseContainer.java b/src/main/java/org/olat/course/MergedCourseContainer.java
index 428e01720d00f3268ceac838cc877cd0dc5b3b99..fd68725036ad78ca152534245560dc21d818ba28 100644
--- a/src/main/java/org/olat/course/MergedCourseContainer.java
+++ b/src/main/java/org/olat/course/MergedCourseContainer.java
@@ -81,41 +81,19 @@ public class MergedCourseContainer extends MergeSource {
 	
 	protected void init(PersistingCourseImpl persistingCourse) {
 		super.init();
-		RepositoryEntry re = null;
 
 		if(identityEnv == null || identityEnv.getRoles().isOLATAdmin()) {
 			addContainersChildren(persistingCourse.getIsolatedCourseFolder(), true);
 		} else {
-			re = persistingCourse.getCourseEnvironment().getCourseGroupManager().getCourseEntry();
+			RepositoryEntry re = persistingCourse.getCourseEnvironment().getCourseGroupManager().getCourseEntry();
 			RepositoryEntrySecurity reSecurity = RepositoryManager.getInstance()
 					.isAllowed(identityEnv.getIdentity(), identityEnv.getRoles(), re);
 			if(reSecurity.isEntryAdmin()) {
 				addContainersChildren(persistingCourse.getIsolatedCourseFolder(), true);
 			}
 		}
-			
-		// grab any shared folder that is configured, but only when in unchecked
-		// security mode (no identity environment) or when the user has course
-		// admin rights
-		OlatRootFolderImpl sharedFolder = null;
-		String sfSoftkey = persistingCourse.getCourseConfig().getSharedFolderSoftkey();
-		if (StringHelper.containsNonWhitespace(sfSoftkey) && !CourseConfig.VALUE_EMPTY_SHAREDFOLDER_SOFTKEY.equals(sfSoftkey)) {
-			if (re == null) {
-				// reuse if already loaded, else load
-				re = persistingCourse.getCourseEnvironment().getCourseGroupManager().getCourseEntry();				
-			}
-			if(identityEnv == null || identityEnv.getRoles().isOLATAdmin() || RepositoryManager.getInstance().isOwnerOfRepositoryEntry(identityEnv.getIdentity(), re)) {
-				OLATResource sharedResource = CoreSpringFactory.getImpl(RepositoryService.class).loadRepositoryEntryResourceBySoftKey(sfSoftkey);
-				if (sharedResource != null) {
-					sharedFolder = SharedFolderManager.getInstance().getSharedFolder(sharedResource);
-					if (sharedFolder != null) {
-						sharedFolder.setLocalSecurityCallback(new ReadOnlyCallback());
-						//add local course folder's children as read/write source and any sharedfolder as subfolder
-						addContainer(new NamedContainerImpl("_sharedfolder", sharedFolder));
-					}
-				}
-			}
-		}
+		
+		initSharedFolder(persistingCourse);
 			
 		// add all course building blocks of type BC to a virtual folder
 		MergeSource nodesContainer = new MergeSource(null, "_courseelementdata");
@@ -138,6 +116,34 @@ public class MergedCourseContainer extends MergeSource {
 		}
 	}
 	
+	/**
+	 * Grab any shared folder that is configured, but only when in unchecked
+	 * security mode (no identity environment) or when the user has course
+	 * admin rights
+	 * 
+	 * @param persistingCourse
+	 */
+	private void initSharedFolder(PersistingCourseImpl persistingCourse) {
+		CourseConfig courseConfig = persistingCourse.getCourseConfig();
+		String sfSoftkey = courseConfig.getSharedFolderSoftkey();
+		if (StringHelper.containsNonWhitespace(sfSoftkey) && !CourseConfig.VALUE_EMPTY_SHAREDFOLDER_SOFTKEY.equals(sfSoftkey)) {
+			RepositoryEntry re = persistingCourse.getCourseEnvironment().getCourseGroupManager().getCourseEntry();
+			if(identityEnv == null || identityEnv.getRoles().isOLATAdmin() || RepositoryManager.getInstance().isOwnerOfRepositoryEntry(identityEnv.getIdentity(), re)) {
+				OLATResource sharedResource = CoreSpringFactory.getImpl(RepositoryService.class).loadRepositoryEntryResourceBySoftKey(sfSoftkey);
+				if (sharedResource != null) {
+					OlatRootFolderImpl sharedFolder = SharedFolderManager.getInstance().getSharedFolder(sharedResource);
+					if (sharedFolder != null) {
+						if(courseConfig.isSharedFolderReadOnlyMount()) {
+							sharedFolder.setLocalSecurityCallback(new ReadOnlyCallback());
+						}
+						//add local course folder's children as read/write source and any sharedfolder as subfolder
+						addContainer(new NamedContainerImpl("_sharedfolder", sharedFolder));
+					}
+				}
+			}
+		}
+	}
+	
 	private void addFolderBuildingBlocks(PersistingCourseImpl course, MergeSource nodesContainer, TreeNode courseNode) {
 		if(courseNode == null) return;
 		
@@ -161,25 +167,26 @@ public class MergedCourseContainer extends MergeSource {
 					// add folder not to merge source. Use name and node id to have unique name
 					VFSContainer rootFolder = null;
 					String subpath = bcNode.getModuleConfiguration().getStringValue(BCCourseNodeEditController.CONFIG_SUBPATH);
-					if(StringHelper.containsNonWhitespace(subpath)){
-						if(bcNode.isSharedFolder()){
+					if(StringHelper.containsNonWhitespace(subpath)) {
+						if(bcNode.isSharedFolder()) {
 							// grab any shared folder that is configured
-							OlatRootFolderImpl sharedFolder = null;
-							String sfSoftkey = course.getCourseConfig().getSharedFolderSoftkey();
+							CourseConfig courseConfig = course.getCourseConfig();
+							String sfSoftkey = courseConfig.getSharedFolderSoftkey();
 							if (StringHelper.containsNonWhitespace(sfSoftkey) && !CourseConfig.VALUE_EMPTY_SHAREDFOLDER_SOFTKEY.equals(sfSoftkey)) {
 								OLATResource sharedResource = CoreSpringFactory.getImpl(RepositoryService.class)
 										.loadRepositoryEntryResourceBySoftKey(sfSoftkey);
 								if (sharedResource != null) {
-									sharedFolder = SharedFolderManager.getInstance().getSharedFolder(sharedResource);
-									VFSContainer courseBase = sharedFolder;
-									sharedFolder.setLocalSecurityCallback(new ReadOnlyCallback());
+									OlatRootFolderImpl sharedFolder = SharedFolderManager.getInstance().getSharedFolder(sharedResource);
+									if(sharedFolder != null && courseConfig.isSharedFolderReadOnlyMount()) {
+										sharedFolder.setLocalSecurityCallback(new ReadOnlyCallback());
+									}
 									subpath = subpath.replaceFirst("/_sharedfolder", "");
-									rootFolder = (VFSContainer) courseBase.resolve(subpath);
+									rootFolder = (VFSContainer) sharedFolder.resolve(subpath);
 								}
 							}
 						} else {
 							VFSContainer courseBase = course.getCourseBaseContainer();
-							rootFolder = (VFSContainer) courseBase.resolve("/coursefolder"+subpath);
+							rootFolder = (VFSContainer)courseBase.resolve("/coursefolder" + subpath);
 						}
 					}
 					if(bcNode.getModuleConfiguration().getBooleanSafe(BCCourseNodeEditController.CONFIG_AUTO_FOLDER)){
@@ -251,7 +258,7 @@ public class MergedCourseContainer extends MergeSource {
 		for (int i = 0; i < courseNode.getChildCount(); i++) {
 			CourseNode child = (CourseNode) courseNode.getChildAt(i);
 			String folderName = RequestUtil.normalizeFilename(child.getShortTitle());
-			MergeSource courseNodeContainer;
+			
 			if (child instanceof BCCourseNode) {
 				final BCCourseNode bcNode = (BCCourseNode) child;
 				bcNode.updateModuleConfigDefaults(false);
@@ -273,14 +280,14 @@ public class MergedCourseContainer extends MergeSource {
 								VFSContainer courseBase = sharedFolder;
 								subpath = subpath.replaceFirst("/_sharedfolder", "");
 								rootFolder = (VFSContainer) courseBase.resolve(subpath);
-								if(rootFolder != null){
+								if(rootFolder != null && course.getCourseConfig().isSharedFolderReadOnlyMount()) {
 									rootFolder.setLocalSecurityCallback(new ReadOnlyCallback());
 								}
 							}
 						}
 					}else{
 						VFSContainer courseBase = course.getCourseBaseContainer();
-						rootFolder = (VFSContainer) courseBase.resolve("/coursefolder"+subpath);
+						rootFolder = (VFSContainer) courseBase.resolve("/coursefolder" + subpath);
 					}
 				}
 				if(bcNode.getModuleConfiguration().getBooleanSafe(BCCourseNodeEditController.CONFIG_AUTO_FOLDER)){
@@ -288,7 +295,6 @@ public class MergedCourseContainer extends MergeSource {
 					rootFolder = new OlatRootFolderImpl(path, null);
 				}
 
-
 				// add node ident if multiple files have same name
 				if (nodesContainer.getItems(new VFSItemFilter() {
 					@Override
@@ -302,7 +308,7 @@ public class MergedCourseContainer extends MergeSource {
  				if(rootFolder != null){
  					// Create a container for this node content and wrap it with a merge source which is attached to tree
  					VFSContainer nodeContentContainer = new NamedContainerImpl(folderName, rootFolder);
- 					courseNodeContainer = new MergeSource(nodesContainer, folderName);
+ 					MergeSource courseNodeContainer = new MergeSource(nodesContainer, folderName);
  					courseNodeContainer.addContainersChildren(nodeContentContainer, true);
  					nodesContainer.addContainer(courseNodeContainer);	
  					// Do recursion for all children
@@ -310,7 +316,7 @@ public class MergedCourseContainer extends MergeSource {
  				}
 			} else {
 				// For non-folder course nodes, add merge source (no files to show) ...
-				courseNodeContainer = new MergeSource(null, folderName);
+				MergeSource courseNodeContainer = new MergeSource(null, folderName);
 				// , then do recursion for all children ...
 				addFolderBuildingBlocks(course, courseNodeContainer, child);
 				// ... but only add this container if it contains any children with at least one BC course node
diff --git a/src/main/java/org/olat/course/config/CourseConfig.java b/src/main/java/org/olat/course/config/CourseConfig.java
index 1fa12a1573a4a41b143f76528f65be832ba42407..2b02c7ce23c3d72641ae8c928b91fe75c694b27c 100644
--- a/src/main/java/org/olat/course/config/CourseConfig.java
+++ b/src/main/java/org/olat/course/config/CourseConfig.java
@@ -125,6 +125,10 @@ public class CourseConfig implements Serializable, Cloneable {
 	 * 
 	 */
 	transient public static final String KEY_SHAREDFOLDER_SOFTKEY = "SHAREDFOLDER_SOFTKEY";
+	/**
+	 * 
+	 */
+	transient public static final String KEY_SHAREDFOLDER_READONLY = "SHAREDFOLDER_RO";
 	/**
 	 * current key set
 	 */
@@ -384,6 +388,15 @@ public class CourseConfig implements Serializable, Cloneable {
 	public boolean hasCustomSharedFolder() {
 		return !(VALUE_EMPTY_SHAREDFOLDER_SOFTKEY.equals(getSharedFolderSoftkey()));
 	}
+	
+	public boolean isSharedFolderReadOnlyMount() {
+		Object obj = configuration.get(KEY_SHAREDFOLDER_READONLY);
+		return (obj == null || !Boolean.FALSE.equals(obj));
+	}
+	
+	public void setSharedFolderReadOnlyMount(boolean mount) {
+		configuration.put(KEY_SHAREDFOLDER_READONLY, new Boolean(mount));
+	}
 
 	/**
 	 * @param b
@@ -537,6 +550,7 @@ public class CourseConfig implements Serializable, Cloneable {
 		clone.setEfficencyStatementIsEnabled(isEfficencyStatementEnabled());
 		clone.setGlossarySoftKey(getGlossarySoftKey());
 		clone.setSharedFolderSoftkey(getSharedFolderSoftkey());
+		clone.setSharedFolderReadOnlyMount(isSharedFolderReadOnlyMount());
 		clone.setAutomaticCertificationEnabled(isAutomaticCertificationEnabled());
 		clone.setManualCertificationEnabled(isManualCertificationEnabled());
 		clone.setCertificateTemplate(getCertificateTemplate());
@@ -556,11 +570,12 @@ public class CourseConfig implements Serializable, Cloneable {
 	public boolean equals(Object obj) {
 		try {
 			CourseConfig aCourseConfig = (CourseConfig) obj;
-			boolean sameCalendarSettings = aCourseConfig.isCalendarEnabled() == this.isCalendarEnabled();
-			boolean sameChatSettings = aCourseConfig.isChatEnabled() == this.isChatEnabled();
-			boolean sameCssLayout = aCourseConfig.getCssLayoutRef().equals(this.getCssLayoutRef());
-			boolean sameEfficiencyStatementSettings = aCourseConfig.isEfficencyStatementEnabled() == this.isEfficencyStatementEnabled();
-			boolean sameSharedFolderSettings = aCourseConfig.getSharedFolderSoftkey().equals(this.getSharedFolderSoftkey());
+			boolean sameCalendarSettings = aCourseConfig.isCalendarEnabled() == isCalendarEnabled();
+			boolean sameChatSettings = aCourseConfig.isChatEnabled() == isChatEnabled();
+			boolean sameCssLayout = aCourseConfig.getCssLayoutRef().equals(getCssLayoutRef());
+			boolean sameEfficiencyStatementSettings = aCourseConfig.isEfficencyStatementEnabled() == isEfficencyStatementEnabled();
+			boolean sameSharedFolderSettings = aCourseConfig.getSharedFolderSoftkey().equals(getSharedFolderSoftkey())
+					&& aCourseConfig.isSharedFolderReadOnlyMount() == isSharedFolderReadOnlyMount();
 
 			boolean sameGlossarySettings = false;
 			if (aCourseConfig.getGlossarySoftKey() != null && this.getGlossarySoftKey() != null) {
diff --git a/src/main/java/org/olat/course/config/ui/CourseOptionsController.java b/src/main/java/org/olat/course/config/ui/CourseOptionsController.java
index 5062e954576b0a2ece7847a08ad96422f5e49a91..627a7cf223ff5895c96e0af588c821645db8f82a 100644
--- a/src/main/java/org/olat/course/config/ui/CourseOptionsController.java
+++ b/src/main/java/org/olat/course/config/ui/CourseOptionsController.java
@@ -28,6 +28,7 @@ import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
 import org.olat.core.gui.components.form.flexible.elements.SelectionElement;
 import org.olat.core.gui.components.form.flexible.elements.StaticTextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
@@ -69,6 +70,7 @@ import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryManagedFlag;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.controllers.ReferencableEntriesSearchController;
+import org.olat.repository.model.RepositoryEntrySecurity;
 import org.olat.resource.references.Reference;
 import org.olat.resource.references.ReferenceManager;
 import org.olat.util.logging.activity.LoggingResourceable;
@@ -92,10 +94,11 @@ public class CourseOptionsController extends FormBasicController {
 	private FormLink addGlossaryCommand, removeGlossaryCommand;
 	private StaticTextElement glossaryNameEl;
 	private FormLink saveButton;
-	private FormLayoutContainer saveCont, calendarCont, chatCont, glossaryCont;
+	private FormLayoutContainer saveCont, calendarCont, chatCont, glossaryCont, sharedFolderCont;
 	
 	private FormLink addFolderCommand, removeFolderCommand;
 	private StaticTextElement folderNameEl;
+	private MultipleSelectionElement folderReadOnlyEl;
 	
 	private final boolean editable;
 	private CourseConfig courseConfig;
@@ -160,10 +163,15 @@ public class CourseOptionsController extends FormBasicController {
 				folderNameEl.setValue(StringHelper.escapeHtml(repoEntry.getDisplayname()));
 				folderNameEl.setUserObject(repoEntry);
 				removeFolderCommand.setVisible(editable && !managedFolder);
+				
+				RepositoryEntrySecurity reSecurity = repositoryService.isAllowed(ureq, repoEntry);
+				folderReadOnlyEl.setVisible(true);
+				folderReadOnlyEl.setEnabled(reSecurity.isEntryAdmin());
 			}
 		} else if(editable && !managedFolder) {
 			removeFolderCommand.setVisible(false);
 			addFolderCommand.setVisible(true);
+			folderReadOnlyEl.setVisible(false);
 		}
 	}
 	
@@ -240,7 +248,7 @@ public class CourseOptionsController extends FormBasicController {
 		
 		//shared folder
 		boolean managedFolder = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.resourcefolder);
-		FormLayoutContainer sharedFolderCont = FormLayoutContainer.createDefaultFormLayout("sharedfolder", getTranslator());
+		sharedFolderCont = FormLayoutContainer.createDefaultFormLayout("sharedfolder", getTranslator());
 		sharedFolderCont.setRootForm(mainForm);
 		formLayout.add(sharedFolderCont);
 
@@ -248,9 +256,19 @@ public class CourseOptionsController extends FormBasicController {
 				translate("sf.notconfigured"), sharedFolderCont);
 		folderNameEl.setHelpText(translate("sf.resourcetitle.helptext"));
 		folderNameEl.setHelpUrlForManualPage("Course Settings#_detail_ressourcen");
-
+		
+		String[] readOnlyValues = new String[]{ translate("sf.resource.readonly") };
+		folderReadOnlyEl = uifactory.addCheckboxesHorizontal("sf.resource.readonly", sharedFolderCont, onKeys, readOnlyValues);
+		folderReadOnlyEl.addActionListener(FormEvent.ONCHANGE);
+		folderReadOnlyEl.setLabel(null, null);
+		folderReadOnlyEl.setEnabled(false);
+		if(courseConfig.isSharedFolderReadOnlyMount()) {
+			folderReadOnlyEl.select(onKeys[0], true);
+		}
+		
 		FormLayoutContainer buttons2Cont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
 		sharedFolderCont.add(buttons2Cont);
+		
 		removeFolderCommand = uifactory.addFormLink("sf.unselectsfresource", buttons2Cont, Link.BUTTON);
 		removeFolderCommand.setVisible(editable && !managedFolder);
 		addFolderCommand = uifactory.addFormLink("sf.changesfresource", buttons2Cont, Link.BUTTON);
@@ -284,7 +302,7 @@ public class CourseOptionsController extends FormBasicController {
 			cmc.deactivate();
 			if (event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) {
 				RepositoryEntry repoEntry = folderSearchCtr.getSelectedEntry();
-				doSelectSharedFolder(repoEntry);
+				doSelectSharedFolder(ureq, repoEntry);
 				setSaveButtonDirty();
 			}
 			cleanUp();
@@ -345,9 +363,9 @@ public class CourseOptionsController extends FormBasicController {
 			}
 			updateToolbar();
 			setSaveButtonDirty();
-		} else if (source instanceof SelectionElement) {
+		} else if (source instanceof SelectionElement || source == folderReadOnlyEl) {
 			setSaveButtonDirty();
-		} else if(saveButton == source) {
+		}  else if(saveButton == source) {
 			doSave(ureq);
 		}
 	}
@@ -456,8 +474,11 @@ public class CourseOptionsController extends FormBasicController {
 				|| (currentFolderSoftKey != null && !currentFolderSoftKey.equals(newFolderSoftKey));
 
 		courseConfig.setSharedFolderSoftkey(newFolderSoftKey);
-		
-		
+		if(folderReadOnlyEl.isEnabled()) {
+			courseConfig.setSharedFolderReadOnlyMount(folderReadOnlyEl.isAtLeastSelected(1));
+		} else {
+			courseConfig.setSharedFolderReadOnlyMount(true);
+		}
 
 		CourseFactory.setCourseConfig(course.getResourceableId(), courseConfig);
 		CourseFactory.closeCourseEditSession(course.getResourceableId(), true);
@@ -559,16 +580,23 @@ public class CourseOptionsController extends FormBasicController {
 		removeGlossaryCommand.setVisible(false);
 	}
 	
-	private void doSelectSharedFolder(RepositoryEntry repoEntry) {
+	private void doSelectSharedFolder(UserRequest ureq, RepositoryEntry repoEntry) {
 		folderNameEl.setValue(StringHelper.escapeHtml(repoEntry.getDisplayname()));
 		folderNameEl.setUserObject(repoEntry);
 		removeFolderCommand.setVisible(true);
+		
+		RepositoryEntrySecurity reSecurity = repositoryService.isAllowed(ureq, repoEntry);
+		folderReadOnlyEl.setVisible(true);
+		folderReadOnlyEl.setEnabled(reSecurity.isEntryAdmin());
+		folderReadOnlyEl.select(onKeys[0], true);
+		sharedFolderCont.setDirty(true);
 	}
 	
 	private void doRemoveSharedFolder() {			
 		folderNameEl.setValue(translate("sf.notconfigured"));
 		folderNameEl.setUserObject(null);
 		removeFolderCommand.setVisible(false);
+		folderReadOnlyEl.setVisible(false);
 	}
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties
index 3cb45eb758e792c451ad84affbee788c9f021d4a..3051034c7984861964893f5ec7414f317c22f235 100644
--- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties
@@ -25,6 +25,7 @@ sf.changesfresource=Auswechseln
 sf.notconfigured=<i>Kein Ressourcenordner ausgew\u00E4hlt</i>
 sf.resourcetitle=Gew\u00E4hlter Ressourcenordner
 sf.resourcetitle.helptext=Die im Ressourcenordner abgelegten Dateien finden Sie im Ablageordner des Kurses im Unterordner \u201E_sharedfolder\u201C.
+sf.resource.readonly=Schreibgesch\u00FCtzt
 sf.selectsfresource=Ausw\u00E4hlen
 sf.unselectsfresource=Auswahl l\u00F6schen
 tab.calendar.title=Einstellungen
diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties
index 51cfa61939eb04ae6b3a958ce94b13841308f804..a0000291ec1ae698dd7ad34aa60e0efd4117c2c7 100644
--- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties
@@ -25,6 +25,7 @@ sf.changesfresource=Replace
 sf.notconfigured=<i>No resource folder selected</i>
 sf.resourcetitle=Selected recource folder
 sf.resourcetitle.helptext=The files stored there can be found in the storage folder of your course when selecting the sub-folder "_sharedfolder".
+sf.resource.readonly=Read only
 sf.selectsfresource=Select
 sf.unselectsfresource=Deselect
 tab.calendar.title=Settings
diff --git a/src/main/java/org/olat/course/nodes/bc/BCCourseNodeEditForm.java b/src/main/java/org/olat/course/nodes/bc/BCCourseNodeEditForm.java
index 592a13320f9f117ddf744272e0acf5577be596c4..56131f0c3238effb2704819cbe11def1317fae0d 100644
--- a/src/main/java/org/olat/course/nodes/bc/BCCourseNodeEditForm.java
+++ b/src/main/java/org/olat/course/nodes/bc/BCCourseNodeEditForm.java
@@ -112,9 +112,9 @@ public class BCCourseNodeEditForm extends FormBasicController implements Control
 
 
 		}
-		if(node.isSharedFolder()){
-			sharedFolderInfo.setVisible(true);
-		}else{
+		if(node.isSharedFolder()) {
+			sharedFolderInfo.setVisible(course.getCourseConfig().isSharedFolderReadOnlyMount());
+		} else {
 			sharedFolderInfo.setVisible(false);
 		}
 
@@ -143,8 +143,8 @@ public class BCCourseNodeEditForm extends FormBasicController implements Control
 			}else{
 				sharedFolderWarning.setVisible(false);
 			}
-			if(node.isSharedFolder()){
-				sharedFolderInfo.setVisible(true);
+			if(node.isSharedFolder()) {
+				sharedFolderInfo.setVisible(course.getCourseConfig().isSharedFolderReadOnlyMount());
 			}else{
 				sharedFolderInfo.setVisible(false);
 			}
diff --git a/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java b/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java
index f4b19bd830bf8af55aac168a7ad0d751471f08ee..26117bedcf0e7655f95a4045a281557eaac83712 100644
--- a/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java
+++ b/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java
@@ -86,15 +86,16 @@ public class SharedFolderManager {
 
 	public OlatRootFolderImpl getSharedFolder(OLATResourceable res) {
 		OlatRootFolderImpl rootFolderImpl = (OlatRootFolderImpl)FileResourceManager.getInstance().getFileResourceRootImpl(res).resolve(SharedFolderManager.FOLDER_NAME);
-		if (rootFolderImpl == null) return null;
-		rootFolderImpl.setLocalSecurityCallback(new SharedFolderSecurityCallback(rootFolderImpl.getRelPath()));
+		if (rootFolderImpl != null) {
+			rootFolderImpl.setLocalSecurityCallback(new SharedFolderSecurityCallback(rootFolderImpl.getRelPath()));
+		}
 		return rootFolderImpl;
 	}
 
 	public MediaResource getAsMediaResource(OLATResourceable res) {
 		String exportFileName = res.getResourceableId() + ".zip";
 		File fExportZIP = new File(WebappHelper.getTmpDir() + "/" + exportFileName);
-		VFSContainer sharedFolder = SharedFolderManager.getInstance().getSharedFolder(res);
+		VFSContainer sharedFolder = getSharedFolder(res);
 		
 		//OLAT-5368: do intermediate commit to avoid transaction timeout
 		// discussion intermediatecommit vs increased transaction timeout: