From f8aa659ddd55a7f1e40d713678cfd99e09434158 Mon Sep 17 00:00:00 2001 From: Gautham Banasandra Date: Sat, 28 Jun 2025 23:14:04 +0530 Subject: [PATCH] HADOOP-19599. Fix file permission errors as per the platform * The file permission denial error message in Linux systems end with `(Permission denied)` particularly. * However, an error message in the same scenario on Windows ends with an `(Access is denied)` error. * This PR fixes the resulting bug in `org.apache.hadoop.fs.ChecksumFileSystem.ChecksumFSInputChecker` and also fixes the unit test failure `org.apache.hadoop.fs.TestFsShellCopy#testPutSrcFileNoPerm` by making the appropriate check in accordance with the platform. --- .../apache/hadoop/fs/ChecksumFileSystem.java | 20 +++++++++++++++++-- .../org/apache/hadoop/fs/TestFsShellCopy.java | 19 ++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ChecksumFileSystem.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ChecksumFileSystem.java index 66d9b628fa3f2..b6341ff3479c6 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ChecksumFileSystem.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ChecksumFileSystem.java @@ -205,8 +205,7 @@ public ChecksumFSInputChecker(ChecksumFileSystem fs, Path file, int bufferSize) } catch (IOException e) { // mincing the message is terrible, but java throws permission // exceptions as FNF because that's all the method signatures allow! - if (!(e instanceof FileNotFoundException) || - e.getMessage().endsWith(" (Permission denied)")) { + if (!(e instanceof FileNotFoundException) || isPermissionDenied(e)) { LOG.warn("Problem opening checksum file: "+ file + ". Ignoring exception: " , e); } @@ -214,6 +213,23 @@ public ChecksumFSInputChecker(ChecksumFileSystem fs, Path file, int bufferSize) } } + /** + * Check if the exception is a permission denied error. + * This is used to differentiate between a missing checksum file + * and a permission denied error when trying to read it. + * + * @param e the IOException to check + * @return true if the exception indicates a permission denied error + */ + private static boolean isPermissionDenied(IOException e) { + String errorMessage = e.getMessage(); + if (Path.WINDOWS) { + return errorMessage.endsWith(" (Access is denied)"); + } + + return errorMessage.endsWith(" (Permission denied)"); + } + private long getChecksumFilePos( long dataPos ) { return HEADER_LENGTH + FSInputChecker.CHECKSUM_SIZE*(dataPos/bytesPerSum); } diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFsShellCopy.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFsShellCopy.java index 319ae0e2d8a5b..c51b7add06078 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFsShellCopy.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFsShellCopy.java @@ -676,14 +676,29 @@ public void testPutSrcFileNoPerm() System.setErr(new PrintStream(err)); shellRun(1, "-put", src.toString(), dst.toString()); System.setErr(oldErr); - System.err.print(err.toString()); - assertTrue(err.toString().contains("(Permission denied)")); + System.err.print(err); + assertPermissionDenied(err); } finally { // make sure the test file can be deleted lfs.setPermission(src, new FsPermission((short)0755)); } } + /** + * Assert that the error message contains the expected permission denied + * message, which varies by platform. + * + * @param err the ByteArrayOutputStream containing the error output + */ + private static void assertPermissionDenied(ByteArrayOutputStream err) { + String errorMessage = err.toString(); + if (Path.WINDOWS) { + assertTrue(errorMessage.contains("(Access is denied)")); + } else { + assertTrue(errorMessage.contains("(Permission denied)")); + } + } + @Test public void testLazyPersistDirectOverwrite() throws Exception { Path testRoot = new Path(testRootDir, "testLazyPersistDirectOverwrite");