diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFile.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFile.java index 57307c69d68..b59b96afc19 100644 --- a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFile.java +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFile.java @@ -18,16 +18,39 @@ *******************************************************************************/ package org.eclipse.core.internal.filesystem.local; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.URI; -import java.nio.file.*; -import org.eclipse.core.filesystem.*; +import java.nio.file.AccessDeniedException; +import java.nio.file.DirectoryNotEmptyException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.core.filesystem.IFileSystem; import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.filesystem.provider.FileInfo; import org.eclipse.core.filesystem.provider.FileStore; -import org.eclipse.core.internal.filesystem.*; -import org.eclipse.core.runtime.*; +import org.eclipse.core.internal.filesystem.FileStoreUtil; +import org.eclipse.core.internal.filesystem.Messages; +import org.eclipse.core.internal.filesystem.Policy; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; import org.eclipse.osgi.util.NLS; /** @@ -134,9 +157,7 @@ public void delete(int options, IProgressMonitor monitor) throws CoreException { monitor = new InfiniteProgress(monitor); try { monitor.beginTask(NLS.bind(Messages.deleting, this), 200); - String message = Messages.deleteProblem; - MultiStatus result = new MultiStatus(Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, message, null); - internalDelete(file, filePath, result, monitor); + IStatus result = internalDelete(file, filePath, monitor); if (!result.isOK()) throw new CoreException(result); } finally { @@ -212,7 +233,7 @@ public int hashCode() { * the provided status object. The filePath is passed as a parameter * to optimize java.io.File object creation. */ - private boolean internalDelete(File target, String pathToDelete, MultiStatus status, IProgressMonitor monitor) { + private IStatus internalDelete(File target, String pathToDelete, IProgressMonitor monitor) { if (monitor.isCanceled()) { throw new OperationCanceledException(); } @@ -220,23 +241,26 @@ private boolean internalDelete(File target, String pathToDelete, MultiStatus sta try { // First try to delete - this should succeed for files and symbolic links to directories. Files.deleteIfExists(target.toPath()); - return true; + return Status.OK_STATUS; } catch (AccessDeniedException e) { // If the file is read only, it can't be deleted via Files.deleteIfExists() // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=500306 if (target.delete()) { - return true; + return Status.OK_STATUS; } throw e; } } catch (DirectoryNotEmptyException e) { + // The target is a directory and it's not empty monitor.subTask(NLS.bind(Messages.deleting, target)); - String[] list = target.list(); - if (list == null) - list = EMPTY_STRING_ARRAY; + String[] directoryElements = target.list(); + if (directoryElements == null) + directoryElements = EMPTY_STRING_ARRAY; int parentLength = pathToDelete.length(); - boolean failedRecursive = false; - for (String element : list) { + + // Try to delete all children. + MultiStatus deleteChildrenStatus = new MultiStatus(Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, Messages.deleteProblem, null); + for (String element : directoryElements) { if (monitor.isCanceled()) { throw new OperationCanceledException(); } @@ -246,36 +270,44 @@ private boolean internalDelete(File target, String pathToDelete, MultiStatus sta childBuffer.append(File.separatorChar); childBuffer.append(element); String childName = childBuffer.toString(); - // Try best effort on all children so put logical OR at end. - failedRecursive = !internalDelete(new java.io.File(childName), childName, status, monitor) || failedRecursive; + + deleteChildrenStatus.add(internalDelete(new java.io.File(childName), childName, monitor)); + monitor.worked(1); } + + // Abort if one of the children couldn't be deleted. + if (!deleteChildrenStatus.isOK()) + return deleteChildrenStatus; + + // Try to delete the root directory try { - // Don't try to delete the root if one of the children failed. - if (!failedRecursive && Files.deleteIfExists(target.toPath())) - return true; + if (Files.deleteIfExists(target.toPath())) + return Status.OK_STATUS; } catch (Exception e1) { // We caught a runtime exception so log it. - String message = NLS.bind(Messages.couldnotDelete, target.getAbsolutePath()); - status.add(new Status(IStatus.ERROR, Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, message, e1)); - return false; + return createErrorStatus(target, Messages.couldnotDelete, e1); } + // If we got this far, we failed. - String message = null; if (fetchInfo().getAttribute(EFS.ATTRIBUTE_READ_ONLY)) { - message = NLS.bind(Messages.couldnotDeleteReadOnly, target.getAbsolutePath()); - } else { - message = NLS.bind(Messages.couldnotDelete, target.getAbsolutePath()); + return createErrorStatus(target, Messages.couldnotDeleteReadOnly, null); } - status.add(new Status(IStatus.ERROR, Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, message, null)); - return false; + + // This is the worst-case scenario: something failed but we don't know what. The children were + // deleted successfully and the directory is NOT read-only... there's nothing else to report. + return createErrorStatus(target, Messages.couldnotDelete, null); + } catch (IOException e) { - String message = NLS.bind(Messages.couldnotDelete, target.getAbsolutePath()); - status.add(new Status(IStatus.ERROR, Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, message, e)); - return false; + return createErrorStatus(target, Messages.couldnotDelete, e); } } + private IStatus createErrorStatus(File target, String msg, Exception e) { + String message = NLS.bind(msg, target.getAbsolutePath()); + return new Status(IStatus.ERROR, Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, message, e); + } + @Override public boolean isParentOf(IFileStore other) { if (!(other instanceof LocalFile))