This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-io.git

commit c5e0254d88863d6e0808269a5e9bd3bd98e225ac
Author: Gary Gregory <gardgreg...@gmail.com>
AuthorDate: Mon Sep 27 09:24:24 2021 -0400

    PathUtils.setReadOnly(Path, boolean, LinkOption...) readOnly argument is
    always assumed true on POSIX.
---
 src/changes/changes.xml                            |  3 +
 .../java/org/apache/commons/io/file/PathUtils.java | 17 ++---
 .../commons/io/file/PathUtilsDeleteFileTest.java   | 72 +++++++++++++++++++---
 3 files changed, 77 insertions(+), 15 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 971ff45..5fbe961 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -104,6 +104,9 @@ The <action> type attribute can be add,update,fix,remove.
       <action issue="IO-638" dev="ggregory" type="fix" due-to="Gary Gregory">
         PathUtils.setReadOnly(Path, boolean, LinkOption...) should add READ_* 
file attributes when using POSIX.
       </action>
+      <action issue="IO-638" dev="ggregory" type="fix" due-to="Gary Gregory">
+        PathUtils.setReadOnly(Path, boolean, LinkOption...) readOnly argument 
is always assumed true on POSIX.
+      </action>
       <!-- ADD -->
       <action dev="ggregory" type="add" due-to="Gary Gregory">
         Add BrokenReader.INSTANCE.
diff --git a/src/main/java/org/apache/commons/io/file/PathUtils.java 
b/src/main/java/org/apache/commons/io/file/PathUtils.java
index 06131a2..f1bc728 100644
--- a/src/main/java/org/apache/commons/io/file/PathUtils.java
+++ b/src/main/java/org/apache/commons/io/file/PathUtils.java
@@ -1154,27 +1154,30 @@ public final class PathUtils {
         final List<Exception> causeList = new ArrayList<>(2);
         final DosFileAttributeView fileAttributeView = 
Files.getFileAttributeView(path, DosFileAttributeView.class, linkOptions);
         if (fileAttributeView != null) {
+            // Windows 10
             try {
                 fileAttributeView.setReadOnly(readOnly);
                 return path;
             } catch (final IOException e) {
-                // ignore for now, retry with PosixFileAttributeView
+                // Remember and retry with PosixFileAttributeView
                 causeList.add(e);
             }
         }
         final PosixFileAttributeView posixFileAttributeView = 
Files.getFileAttributeView(path, PosixFileAttributeView.class, linkOptions);
         if (posixFileAttributeView != null) {
-            // Works on Windows but not on Ubuntu:
-            // Files.setAttribute(path, "unix:readonly", readOnly, options);
-            // java.lang.IllegalArgumentException: 'unix:readonly' not 
recognized
+            // Not Windows 10
             final PosixFileAttributes readAttributes = 
posixFileAttributeView.readAttributes();
             final Set<PosixFilePermission> permissions = 
readAttributes.permissions();
             permissions.add(PosixFilePermission.OWNER_READ);
             permissions.add(PosixFilePermission.GROUP_READ);
             permissions.add(PosixFilePermission.OTHERS_READ);
-            permissions.remove(PosixFilePermission.OWNER_WRITE);
-            permissions.remove(PosixFilePermission.GROUP_WRITE);
-            permissions.remove(PosixFilePermission.OTHERS_WRITE);
+            List<PosixFilePermission> writePermissions = 
Arrays.asList(PosixFilePermission.OWNER_WRITE, PosixFilePermission.GROUP_WRITE,
+                PosixFilePermission.OTHERS_WRITE);
+            if (readOnly) {
+                permissions.removeAll(writePermissions);
+            } else {
+                permissions.addAll(writePermissions);
+            }
             try {
                 return Files.setPosixFilePermissions(path, permissions);
             } catch (final IOException e) {
diff --git 
a/src/test/java/org/apache/commons/io/file/PathUtilsDeleteFileTest.java 
b/src/test/java/org/apache/commons/io/file/PathUtilsDeleteFileTest.java
index badc727..06505de 100644
--- a/src/test/java/org/apache/commons/io/file/PathUtilsDeleteFileTest.java
+++ b/src/test/java/org/apache/commons/io/file/PathUtilsDeleteFileTest.java
@@ -18,17 +18,23 @@
 package org.apache.commons.io.file;
 
 import static org.apache.commons.io.file.CounterAssertions.assertCounts;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assumptions.assumeFalse;
 
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.LinkOption;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.attribute.DosFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Set;
 
 import org.apache.commons.io.file.Counters.PathCounters;
 import org.apache.commons.lang3.SystemUtils;
@@ -79,8 +85,7 @@ public class PathUtilsDeleteFileTest {
     @Test
     public void testDeleteFileDirectory1FileSize0() throws IOException {
         final String fileName = "file-size-0.bin";
-        PathUtils.copyFileToDirectory(
-                
Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-0/" + 
fileName), tempDir);
+        
PathUtils.copyFileToDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-0/"
 + fileName), tempDir);
         assertCounts(0, 1, 0, PathUtils.deleteFile(tempDir.resolve(fileName)));
         // This will throw if not empty.
         Files.deleteIfExists(tempDir);
@@ -92,8 +97,7 @@ public class PathUtilsDeleteFileTest {
     @Test
     public void testDeleteFileDirectory1FileSize1() throws IOException {
         final String fileName = "file-size-1.bin";
-        PathUtils.copyFileToDirectory(
-                
Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1/" + 
fileName), tempDir);
+        
PathUtils.copyFileToDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1/"
 + fileName), tempDir);
         assertCounts(0, 1, 1, PathUtils.deleteFile(tempDir.resolve(fileName)));
         // This will throw if not empty.
         Files.deleteIfExists(tempDir);
@@ -129,8 +133,7 @@ public class PathUtilsDeleteFileTest {
     @Test
     public void testDeleteReadOnlyFileDirectory1FileSize1() throws IOException 
{
         final String fileName = "file-size-1.bin";
-        PathUtils.copyFileToDirectory(
-            
Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1/" + 
fileName), tempDir);
+        
PathUtils.copyFileToDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1/"
 + fileName), tempDir);
         final Path resolved = tempDir.resolve(fileName);
         PathUtils.setReadOnly(resolved, true);
         if (SystemUtils.IS_OS_WINDOWS) {
@@ -143,14 +146,67 @@ public class PathUtilsDeleteFileTest {
         Files.deleteIfExists(tempDir);
     }
 
+    @Test
+    public void testSetReadOnlyFile() throws IOException {
+        final Path resolved = tempDir.resolve("testSetReadOnlyFile.txt");
+
+        // TEMP HACK
+        assertTrue(Files.getFileAttributeView(resolved, 
DosFileAttributeView.class) != null);
+        assertTrue(Files.getFileAttributeView(resolved, 
PosixFileAttributeView.class) == null);
+
+        PathUtils.writeString(resolved, "test", StandardCharsets.UTF_8);
+        final boolean readable = Files.isReadable(resolved);
+        final boolean writable = Files.isWritable(resolved);
+        final boolean regularFile = Files.isRegularFile(resolved);
+        final boolean executable = Files.isExecutable(resolved);
+        final boolean hidden = Files.isHidden(resolved);
+        final boolean directory = Files.isDirectory(resolved);
+        final boolean symbolicLink = Files.isSymbolicLink(resolved);
+        // Sanity checks
+        assertTrue(readable);
+        assertTrue(writable);
+        // Test A
+        PathUtils.setReadOnly(resolved, false);
+        assertEquals(true, Files.isReadable(resolved));
+        assertEquals(true, Files.isWritable(resolved));
+        assertEquals(regularFile, Files.isReadable(resolved));
+        assertEquals(executable, Files.isExecutable(resolved));
+        assertEquals(hidden, Files.isHidden(resolved));
+        assertEquals(directory, Files.isDirectory(resolved));
+        assertEquals(symbolicLink, Files.isSymbolicLink(resolved));
+        // Test B
+        PathUtils.setReadOnly(resolved, true);
+        assertEquals(true, Files.isReadable(resolved));
+        assertEquals(false, Files.isWritable(resolved));
+        final DosFileAttributeView dosFileAttributeView = 
Files.getFileAttributeView(resolved, DosFileAttributeView.class);
+        if (dosFileAttributeView != null) {
+            assertTrue(dosFileAttributeView.readAttributes().isReadOnly());
+        }
+        final PosixFileAttributeView posixFileAttributeView = 
Files.getFileAttributeView(resolved, PosixFileAttributeView.class);
+        if (posixFileAttributeView != null) {
+            // Not Windows
+            final Set<PosixFilePermission> permissions = 
posixFileAttributeView.readAttributes().permissions();
+            assertFalse(permissions.contains(PosixFilePermission.GROUP_WRITE), 
() -> permissions.toString());
+            
assertFalse(permissions.contains(PosixFilePermission.OTHERS_WRITE), () -> 
permissions.toString());
+            assertFalse(permissions.contains(PosixFilePermission.OWNER_WRITE), 
() -> permissions.toString());
+        }
+        assertEquals(regularFile, Files.isReadable(resolved));
+        assertEquals(executable, Files.isExecutable(resolved));
+        assertEquals(hidden, Files.isHidden(resolved));
+        assertEquals(directory, Files.isDirectory(resolved));
+        assertEquals(symbolicLink, Files.isSymbolicLink(resolved));
+        //
+        PathUtils.setReadOnly(resolved, false);
+        PathUtils.deleteFile(resolved);
+    }
+
     /**
      * Tests a directory with one file of size 1.
      */
     @Test
     public void testSetReadOnlyFileDirectory1FileSize1() throws IOException {
         final String fileName = "file-size-1.bin";
-        PathUtils.copyFileToDirectory(
-            
Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1/" + 
fileName), tempDir);
+        
PathUtils.copyFileToDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1/"
 + fileName), tempDir);
         final Path resolved = tempDir.resolve(fileName);
         PathUtils.setReadOnly(resolved, true);
         if (SystemUtils.IS_OS_WINDOWS) {

Reply via email to