Skip to content

Commit f50fb8f

Browse files
committed
Extract NIO to IO exception conversion into a helper method
1 parent c6fc42a commit f50fb8f

File tree

2 files changed

+70
-42
lines changed

2 files changed

+70
-42
lines changed

src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@
3030
import java.io.InputStreamReader;
3131
import java.io.OutputStream;
3232
import java.nio.channels.SeekableByteChannel;
33+
import java.nio.file.AccessDeniedException;
34+
import java.nio.file.DirectoryNotEmptyException;
3335
import java.nio.file.FileAlreadyExistsException;
36+
import java.nio.file.FileSystemException;
37+
import java.nio.file.NoSuchFileException;
38+
import java.nio.file.NotDirectoryException;
39+
import java.nio.file.NotLinkException;
3440
import java.security.SecureRandom;
3541
import java.util.Collection;
3642
import java.util.Iterator;
@@ -45,6 +51,15 @@ public abstract class FileSystem {
4551
// canonicalizing a path before it gives up and throws a FileSymlinkLoopException.
4652
public static final int MAX_SYMLINKS = 32;
4753

54+
// Standard error message suffixes to be used for consistency across different FileSystem
55+
// implementations.
56+
protected static final String ERR_DIRECTORY_NOT_EMPTY = " (Directory not empty)";
57+
protected static final String ERR_FILE_EXISTS = " (File exists)";
58+
protected static final String ERR_IS_DIRECTORY = " (Is a directory)";
59+
protected static final String ERR_NOT_A_DIRECTORY = " (Not a directory)";
60+
protected static final String ERR_NO_SUCH_FILE_OR_DIR = " (No such file or directory)";
61+
protected static final String ERR_PERMISSION_DENIED = " (Permission denied)";
62+
4863
private final DigestHashFunction digestFunction;
4964

5065
public FileSystem(DigestHashFunction digestFunction) {
@@ -797,6 +812,55 @@ public java.nio.file.Path getNioPath(PathFragment path) {
797812
"getNioPath() not supported for " + getClass().getName());
798813
}
799814

815+
/**
816+
* Translates common java.nio.file IOExceptions into the equivalent java.io IOExceptions with
817+
* consistent error messages.
818+
*/
819+
protected static IOException translateNioToIoException(PathFragment path, IOException e) {
820+
if (!(e instanceof FileSystemException fileSystemException)) {
821+
return e;
822+
}
823+
String prefix = "";
824+
if (fileSystemException.getFile() != null) {
825+
prefix = fileSystemException.getFile();
826+
}
827+
if (fileSystemException.getOtherFile() != null) {
828+
prefix += " -> " + fileSystemException.getOtherFile();
829+
}
830+
return switch (e) {
831+
case AccessDeniedException unused -> {
832+
FileAccessException newException = new FileAccessException(prefix + ERR_PERMISSION_DENIED);
833+
newException.initCause(e);
834+
yield newException;
835+
}
836+
case DirectoryNotEmptyException unused ->
837+
new IOException(prefix + ERR_DIRECTORY_NOT_EMPTY, e);
838+
case FileAlreadyExistsException unused -> new IOException(prefix + ERR_FILE_EXISTS, e);
839+
case NoSuchFileException unused -> {
840+
FileNotFoundException newException =
841+
new FileNotFoundException(prefix + ERR_NO_SUCH_FILE_OR_DIR);
842+
newException.initCause(e);
843+
yield newException;
844+
}
845+
case NotDirectoryException unused -> new IOException(prefix + ERR_NOT_A_DIRECTORY, e);
846+
case NotLinkException unused -> new NotASymlinkException(path, e);
847+
// Rewrite exception messages to be identical to the ones produced by the native Unix
848+
// filesystem implementation. Bazel forces the root locale for the JVM, so the error messages
849+
// should be stable. Some of the exceptions caught above can also appear as untyped
850+
// FileSystemExceptions, so we need to catch those as well.
851+
case FileSystemException unused
852+
when fileSystemException.getReason().equals("Is a directory") ->
853+
new IOException(prefix + ERR_IS_DIRECTORY, e);
854+
case FileSystemException unused
855+
when fileSystemException.getReason().equals("Not a directory") ->
856+
new IOException(prefix + ERR_NOT_A_DIRECTORY, e);
857+
case FileSystemException unused
858+
when fileSystemException.getReason().equals("Directory not empty") ->
859+
new IOException(prefix + ERR_DIRECTORY_NOT_EMPTY, e);
860+
default -> fileSystemException;
861+
};
862+
}
863+
800864
/**
801865
* Returns the path of a new temporary directory with the given prefix created under the given
802866
* parent path, but <b>not</b> necessarily with secure permissions.

src/main/java/com/google/devtools/build/lib/vfs/JavaIoFileSystem.java

Lines changed: 6 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,9 @@
2424
import java.io.File;
2525
import java.io.FileNotFoundException;
2626
import java.io.IOException;
27-
import java.nio.file.AccessDeniedException;
28-
import java.nio.file.FileSystemException;
2927
import java.nio.file.Files;
3028
import java.nio.file.InvalidPathException;
3129
import java.nio.file.LinkOption;
32-
import java.nio.file.NoSuchFileException;
3330
import java.nio.file.Paths;
3431
import java.nio.file.StandardCopyOption;
3532
import java.nio.file.attribute.BasicFileAttributes;
@@ -54,12 +51,6 @@ public class JavaIoFileSystem extends AbstractFileSystem {
5451

5552
private final Clock clock;
5653

57-
protected static final String ERR_IS_DIRECTORY = " (Is a directory)";
58-
protected static final String ERR_DIRECTORY_NOT_EMPTY = " (Directory not empty)";
59-
protected static final String ERR_FILE_EXISTS = " (File exists)";
60-
protected static final String ERR_NO_SUCH_FILE_OR_DIR = " (No such file or directory)";
61-
protected static final String ERR_NOT_A_DIRECTORY = " (Not a directory)";
62-
6354
public JavaIoFileSystem(DigestHashFunction hashFunction) {
6455
super(hashFunction);
6556
this.clock = new JavaClock();
@@ -289,12 +280,8 @@ public void createSymbolicLink(
289280
Files.createSymbolicLink(
290281
nioPath,
291282
Paths.get(StringEncoding.internalToPlatform(targetFragment.getSafePathString())));
292-
} catch (java.nio.file.FileAlreadyExistsException e) {
293-
throw new IOException(linkPath + ERR_FILE_EXISTS, e);
294-
} catch (java.nio.file.AccessDeniedException e) {
295-
throw new IOException(linkPath + ERR_PERMISSION_DENIED, e);
296-
} catch (java.nio.file.NoSuchFileException e) {
297-
throw new FileNotFoundException(linkPath + ERR_NO_SUCH_FILE_OR_DIR);
283+
} catch (IOException e) {
284+
throw translateNioToIoException(linkPath, e);
298285
}
299286
}
300287

@@ -305,10 +292,8 @@ public PathFragment readSymbolicLink(PathFragment path) throws IOException {
305292
try {
306293
String link = Files.readSymbolicLink(nioPath).toString();
307294
return PathFragment.create(StringEncoding.platformToInternal(link));
308-
} catch (java.nio.file.NotLinkException e) {
309-
throw new NotASymlinkException(path, e);
310-
} catch (java.nio.file.NoSuchFileException e) {
311-
throw new FileNotFoundException(path + ERR_NO_SUCH_FILE_OR_DIR);
295+
} catch (IOException e) {
296+
throw translateNioToIoException(path, e);
312297
} finally {
313298
profiler.logSimpleTask(startTime, ProfilerTask.VFS_READLINK, path.getPathString());
314299
}
@@ -318,32 +303,11 @@ public PathFragment readSymbolicLink(PathFragment path) throws IOException {
318303
public void renameTo(PathFragment sourcePath, PathFragment targetPath) throws IOException {
319304
java.nio.file.Path source = getNioPath(sourcePath);
320305
java.nio.file.Path target = getNioPath(targetPath);
321-
// Replace NIO exceptions with the types used by the native Unix filesystem implementation where
322-
// necessary.
323306
try {
324307
Files.move(
325308
source, target, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
326-
} catch (NoSuchFileException originalException) {
327-
FileNotFoundException newException =
328-
new FileNotFoundException(originalException.getMessage() + ERR_NO_SUCH_FILE_OR_DIR);
329-
newException.initCause(originalException);
330-
throw newException;
331-
} catch (AccessDeniedException originalException) {
332-
FileAccessException newException =
333-
new FileAccessException(originalException.getMessage() + ERR_PERMISSION_DENIED);
334-
newException.initCause(originalException);
335-
throw newException;
336-
} catch (FileSystemException e) {
337-
// Rewrite exception messages to be identical to the ones produced by the native Unix
338-
// filesystem implementation. Bazel forces the root locale for the JVM, so the error messages
339-
// should be stable.
340-
String filesPart = sourcePath + " -> " + targetPath;
341-
throw switch (e.getReason()) {
342-
case "Directory not empty" -> new IOException(filesPart + ERR_DIRECTORY_NOT_EMPTY, e);
343-
case "Not a directory" -> new IOException(filesPart + ERR_NOT_A_DIRECTORY, e);
344-
case "Is a directory" -> new IOException(filesPart + ERR_IS_DIRECTORY, e);
345-
default -> e;
346-
};
309+
} catch (IOException e) {
310+
throw translateNioToIoException(sourcePath, e);
347311
}
348312
}
349313

0 commit comments

Comments
 (0)