Skip to content

Commit 63f7d9b

Browse files
committed
Various minor clean-ups, modernizations and improvements in LocalFile
1 parent 6de0efd commit 63f7d9b

File tree

1 file changed

+65
-89
lines changed
  • resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local

1 file changed

+65
-89
lines changed

resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFile.java

Lines changed: 65 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.nio.file.NoSuchFileException;
3535
import java.nio.file.StandardCopyOption;
3636
import java.nio.file.StandardOpenOption;
37+
import java.util.Locale;
3738
import org.eclipse.core.filesystem.EFS;
3839
import org.eclipse.core.filesystem.IFileInfo;
3940
import org.eclipse.core.filesystem.IFileStore;
@@ -50,7 +51,6 @@
5051
import org.eclipse.core.runtime.IStatus;
5152
import org.eclipse.core.runtime.MultiStatus;
5253
import org.eclipse.core.runtime.NullProgressMonitor;
53-
import org.eclipse.core.runtime.OperationCanceledException;
5454
import org.eclipse.core.runtime.Status;
5555
import org.eclipse.core.runtime.SubMonitor;
5656
import org.eclipse.osgi.util.NLS;
@@ -131,19 +131,17 @@ public String[] childNames(int options, IProgressMonitor monitor) {
131131

132132
@Override
133133
public void copy(IFileStore destFile, int options, IProgressMonitor monitor) throws CoreException {
134-
if (destFile instanceof LocalFile) {
135-
File source = file;
136-
File destination = ((LocalFile) destFile).file;
134+
if (destFile instanceof LocalFile destination) {
137135
//handle case variants on a case-insensitive OS, or copying between
138136
//two equivalent files in an environment that supports symbolic links.
139137
//in these nothing needs to be copied (and doing so would likely lose data)
140138
try {
141-
if (isSameFile(source, destination)) {
139+
if (isSameFile(this.file, destination.file)) {
142140
//nothing to do
143141
return;
144142
}
145143
} catch (IOException e) {
146-
String message = NLS.bind(Messages.couldNotRead, source.getAbsolutePath());
144+
String message = NLS.bind(Messages.couldNotRead, this.file.getAbsolutePath());
147145
Policy.error(EFS.ERROR_READ, message, e);
148146
}
149147
}
@@ -179,8 +177,7 @@ public void delete(int options, IProgressMonitor monitor) throws CoreException {
179177
else
180178
monitor = new InfiniteProgress(monitor);
181179
try {
182-
monitor.beginTask(NLS.bind(Messages.deleting, this), 200);
183-
IStatus result = internalDelete(file, filePath, monitor);
180+
IStatus result = internalDelete(file, monitor);
184181
if (!result.isOK())
185182
throw new CoreException(result);
186183
} finally {
@@ -190,13 +187,17 @@ public void delete(int options, IProgressMonitor monitor) throws CoreException {
190187

191188
@Override
192189
public boolean equals(Object obj) {
193-
if (!(obj instanceof LocalFile))
190+
if (this == obj) {
191+
return true;
192+
}
193+
if (!(obj instanceof LocalFile otherFile)) {
194194
return false;
195+
}
195196
//Mac oddity: file.equals returns false when case is different even when
196197
//file system is not case sensitive (Radar bug 3190672)
197-
LocalFile otherFile = (LocalFile) obj;
198-
if (LocalFileSystem.MACOSX)
198+
if (LocalFileSystem.MACOSX) {
199199
return filePath.equalsIgnoreCase(otherFile.filePath);
200+
}
200201
return file.equals(otherFile.file);
201202
}
202203

@@ -247,7 +248,7 @@ public IFileStore getParent() {
247248
@Override
248249
public int hashCode() {
249250
if (LocalFileSystem.MACOSX)
250-
return filePath.toLowerCase().hashCode();
251+
return filePath.toLowerCase(Locale.ENGLISH).hashCode();
251252
return file.hashCode();
252253
}
253254

@@ -256,10 +257,9 @@ public int hashCode() {
256257
* the provided status object. The filePath is passed as a parameter
257258
* to optimize java.io.File object creation.
258259
*/
259-
private IStatus internalDelete(File target, String pathToDelete, IProgressMonitor monitor) {
260-
if (monitor.isCanceled()) {
261-
throw new OperationCanceledException();
262-
}
260+
private IStatus internalDelete(File target, IProgressMonitor monitor) {
261+
SubMonitor subMonitor = SubMonitor.convert(monitor, NLS.bind(Messages.deleting, target), IProgressMonitor.UNKNOWN);
262+
subMonitor.checkCanceled();
263263
try {
264264
try {
265265
// First try to delete - this should succeed for files and symbolic links to directories.
@@ -275,29 +275,15 @@ private IStatus internalDelete(File target, String pathToDelete, IProgressMonito
275275
}
276276
} catch (DirectoryNotEmptyException e) {
277277
// The target is a directory and it's not empty
278-
monitor.subTask(NLS.bind(Messages.deleting, target));
279-
String[] directoryElements = target.list();
278+
File[] directoryElements = target.listFiles();
280279
if (directoryElements == null) {
281-
directoryElements = EMPTY_STRING_ARRAY;
280+
directoryElements = new File[0]; // Unlikely to happen if the directory is not empty
282281
}
283-
int parentLength = pathToDelete.length();
284-
282+
subMonitor.setWorkRemaining(directoryElements.length);
285283
// Try to delete all children.
286284
MultiStatus deleteChildrenStatus = new MultiStatus(Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, Messages.deleteProblem, null);
287-
for (String element : directoryElements) {
288-
if (monitor.isCanceled()) {
289-
throw new OperationCanceledException();
290-
}
291-
// Optimized creation of child path object
292-
StringBuilder childBuffer = new StringBuilder(parentLength + element.length() + 1);
293-
childBuffer.append(pathToDelete);
294-
childBuffer.append(File.separatorChar);
295-
childBuffer.append(element);
296-
String childName = childBuffer.toString();
297-
298-
deleteChildrenStatus.add(internalDelete(new File(childName), childName, monitor));
299-
300-
monitor.worked(1);
285+
for (File element : directoryElements) {
286+
deleteChildrenStatus.add(internalDelete(element, subMonitor.split(1)));
301287
}
302288

303289
// Abort if one of the children couldn't be deleted.
@@ -319,7 +305,7 @@ private IStatus internalDelete(File target, String pathToDelete, IProgressMonito
319305
String message = fetchInfo().getAttribute(EFS.ATTRIBUTE_READ_ONLY) //
320306
? Messages.couldnotDeleteReadOnly
321307

322-
// This is the worst-case scenario: something failed but we don't know what. The children were
308+
// This is the worst-case scenario: something failed but we don't know what. The children were
323309
// deleted successfully and the directory is NOT read-only... there's nothing else to report.
324310
: Messages.couldnotDelete;
325311

@@ -337,21 +323,25 @@ private IStatus createErrorStatus(File target, String msg, Exception e) {
337323

338324
@Override
339325
public boolean isParentOf(IFileStore other) {
340-
if (!(other instanceof LocalFile))
326+
if (!(other instanceof LocalFile otherFile)) {
341327
return false;
328+
}
342329
String thisPath = filePath;
343-
String thatPath = ((LocalFile) other).filePath;
330+
String thatPath = otherFile.filePath;
344331
int thisLength = thisPath.length();
345332
int thatLength = thatPath.length();
346333
//if equal then not a parent
347-
if (thisLength >= thatLength)
334+
if (thisLength >= thatLength) {
348335
return false;
336+
}
349337
if (getFileSystem().isCaseSensitive()) {
350-
if (thatPath.indexOf(thisPath) != 0)
338+
if (!thatPath.startsWith(thisPath)) {
351339
return false;
340+
}
352341
} else {
353-
if (thatPath.toLowerCase().indexOf(thisPath.toLowerCase()) != 0)
342+
if (!thatPath.toLowerCase(Locale.ENGLISH).startsWith(thisPath.toLowerCase(Locale.ENGLISH))) {
354343
return false;
344+
}
355345
}
356346
//The common portion must end with a separator character for this to be a parent of that
357347
return thisPath.charAt(thisLength - 1) == File.separatorChar || thatPath.charAt(thisLength) == File.separatorChar;
@@ -397,12 +387,12 @@ public IFileStore mkdir(int options, IProgressMonitor monitor) throws CoreExcept
397387

398388
@Override
399389
public void move(IFileStore destFile, int options, IProgressMonitor monitor) throws CoreException {
400-
if (!(destFile instanceof LocalFile)) {
390+
if (!(destFile instanceof LocalFile destinationFile)) {
401391
super.move(destFile, options, monitor);
402392
return;
403393
}
404394
File source = file;
405-
File destination = ((LocalFile) destFile).file;
395+
File destination = destinationFile.file;
406396
boolean overwrite = (options & EFS.OVERWRITE) != 0;
407397
SubMonitor subMonitor = SubMonitor.convert(monitor, NLS.bind(Messages.moving, source.getAbsolutePath()), 1);
408398
try {
@@ -462,8 +452,8 @@ private boolean isSameFile(File source, File destination) throws IOException {
462452
// avoid NoSuchFileException for performance reasons
463453
return false;
464454
}
465-
// isSameFile is faster then using getCanonicalPath
466-
return java.nio.file.Files.isSameFile(source.toPath(), destination.toPath());
455+
// isSameFile is faster then using getCanonicalPath
456+
return Files.isSameFile(source.toPath(), destination.toPath());
467457
} catch (NoSuchFileException e) {
468458
// ignore - it is the normal case that the destination does not exist.
469459
// slowest path though
@@ -477,17 +467,7 @@ public InputStream openInputStream(int options, IProgressMonitor monitor) throws
477467
try {
478468
return new FileInputStream(file);
479469
} catch (FileNotFoundException e) {
480-
String message;
481-
if (!file.exists()) {
482-
message = NLS.bind(Messages.fileNotFound, filePath);
483-
Policy.error(EFS.ERROR_NOT_EXISTS, message, e);
484-
} else if (file.isDirectory()) {
485-
message = NLS.bind(Messages.notAFile, filePath);
486-
Policy.error(EFS.ERROR_WRONG_TYPE, message, e);
487-
} else {
488-
message = NLS.bind(Messages.couldNotRead, filePath);
489-
Policy.error(EFS.ERROR_READ, message, e);
490-
}
470+
handleReadIOException(e);
491471
return null;
492472
}
493473
}
@@ -498,37 +478,31 @@ public byte[] readAllBytes(int options, IProgressMonitor monitor) throws CoreExc
498478
try {
499479
return Files.readAllBytes(file.toPath());
500480
} catch (IOException e) {
501-
String message;
502-
if (!file.exists()) {
503-
message = NLS.bind(Messages.fileNotFound, filePath);
504-
Policy.error(EFS.ERROR_NOT_EXISTS, message, e);
505-
} else if (file.isDirectory()) {
506-
message = NLS.bind(Messages.notAFile, filePath);
507-
Policy.error(EFS.ERROR_WRONG_TYPE, message, e);
508-
} else {
509-
message = NLS.bind(Messages.couldNotRead, filePath);
510-
Policy.error(EFS.ERROR_READ, message, e);
511-
}
481+
handleReadIOException(e);
512482
return null;
513483
}
514484
}
515485

486+
private void handleReadIOException(IOException e) throws CoreException {
487+
if (!file.exists()) {
488+
String message = NLS.bind(Messages.fileNotFound, filePath);
489+
Policy.error(EFS.ERROR_NOT_EXISTS, message, e);
490+
} else if (file.isDirectory()) {
491+
String message = NLS.bind(Messages.notAFile, filePath);
492+
Policy.error(EFS.ERROR_WRONG_TYPE, message, e);
493+
} else {
494+
String message = NLS.bind(Messages.couldNotRead, filePath);
495+
Policy.error(EFS.ERROR_READ, message, e);
496+
}
497+
}
498+
516499
/** @see #write(byte[], int, IProgressMonitor) */
517500
@Override
518501
public OutputStream openOutputStream(int options, IProgressMonitor monitor) throws CoreException {
519502
try {
520503
return new FileOutputStream(file, (options & EFS.APPEND) != 0);
521504
} catch (FileNotFoundException e) {
522-
checkReadOnlyParent(file, e);
523-
String message;
524-
String path = filePath;
525-
if (file.isDirectory()) {
526-
message = NLS.bind(Messages.notAFile, path);
527-
Policy.error(EFS.ERROR_WRONG_TYPE, message, e);
528-
} else {
529-
message = NLS.bind(Messages.couldNotWrite, path);
530-
Policy.error(EFS.ERROR_WRITE, message, e);
531-
}
505+
handleWriteIOException(e);
532506
return null;
533507
}
534508
}
@@ -544,16 +518,18 @@ public void write(byte[] content, int options, IProgressMonitor monitor) throws
544518
Files.write(file.toPath(), content); // default uses StandardOpenOption.TRUNCATE_EXISTING
545519
}
546520
} catch (IOException e) {
547-
checkReadOnlyParent(file, e);
548-
String message;
549-
String path = filePath;
550-
if (file.isDirectory()) {
551-
message = NLS.bind(Messages.notAFile, path);
552-
Policy.error(EFS.ERROR_WRONG_TYPE, message, e);
553-
} else {
554-
message = NLS.bind(Messages.couldNotWrite, path);
555-
Policy.error(EFS.ERROR_WRITE, message, e);
556-
}
521+
handleWriteIOException(e);
522+
}
523+
}
524+
525+
private void handleWriteIOException(IOException e) throws CoreException {
526+
checkReadOnlyParent(file, e);
527+
if (file.isDirectory()) {
528+
String message = NLS.bind(Messages.notAFile, filePath);
529+
Policy.error(EFS.ERROR_WRONG_TYPE, message, e);
530+
} else {
531+
String message = NLS.bind(Messages.couldNotWrite, filePath);
532+
Policy.error(EFS.ERROR_WRITE, message, e);
557533
}
558534
}
559535

@@ -592,11 +568,11 @@ public URI toURI() {
592568

593569
@Override
594570
public int compareTo(IFileStore other) {
595-
if (other instanceof LocalFile) {
571+
if (other instanceof LocalFile otherFile) {
596572
// We can compare paths in the local file implementation, because LocalFile don't have a query string, port, or authority
597573
// We use `toURI` here because it performs file normalisation e.g. /a/b/../c -> /a/c
598574
// The URI is cached by the LocalFile after normalisation so this effectively results in a straight lookup
599-
return FileStoreUtil.comparePathSegments(this.toURI().getPath(), ((LocalFile) other).toURI().getPath());
575+
return FileStoreUtil.comparePathSegments(this.toURI().getPath(), otherFile.toURI().getPath());
600576
}
601577
return super.compareTo(other);
602578
}

0 commit comments

Comments
 (0)