You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by bo...@apache.org on 2023/03/18 09:47:29 UTC

[ant] branch master updated: try to preserve file permissions of exisiting target when renaming

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

bodewig pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ant.git


The following commit(s) were added to refs/heads/master by this push:
     new bb02a4d80 try to preserve file permissions of exisiting target when renaming
bb02a4d80 is described below

commit bb02a4d806652d6e01e8eb1b74fc74d5c94b3317
Author: Stefan Bodewig <bo...@apache.org>
AuthorDate: Sat Mar 18 10:42:58 2023 +0100

    try to preserve file permissions of exisiting target when renaming
    
    https://bz.apache.org/bugzilla/show_bug.cgi?id=66522
---
 WHATSNEW                                           |  4 +++
 .../org/apache/tools/ant/taskdefs/FixCRLF.java     |  2 +-
 .../org/apache/tools/ant/taskdefs/Replace.java     |  2 +-
 .../tools/ant/taskdefs/optional/ReplaceRegExp.java |  2 +-
 src/main/org/apache/tools/ant/util/FileUtils.java  | 33 +++++++++++++++++++++
 .../org/apache/tools/ant/util/FileUtilsTest.java   | 34 ++++++++++++++++++++++
 6 files changed, 74 insertions(+), 3 deletions(-)

diff --git a/WHATSNEW b/WHATSNEW
index cd2d2bcfc..267b0d549 100644
--- a/WHATSNEW
+++ b/WHATSNEW
@@ -18,6 +18,10 @@ Fixed bugs:
    This is now fixed.
    Bugzilla Report 66468
 
+ * <fixcrlf>, <replace> and <replaceregexp> now try to preserve the
+   file permissions of the files they modify.
+   Bugzilla Report 66522
+
 Other changes:
 --------------
 
diff --git a/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java b/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java
index cff7ed820..82f7843ba 100644
--- a/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java
+++ b/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java
@@ -372,7 +372,7 @@ public class FixCRLF extends MatchingTask implements ChainableReader {
                     Project.MSG_DEBUG);
             }
             if (destIsWrong) {
-                FILE_UTILS.rename(tmpFile, destFile);
+                FILE_UTILS.rename(tmpFile, destFile, true);
                 if (preserveLastModified) {
                     log("preserved lastModified for " + destFile,
                         Project.MSG_DEBUG);
diff --git a/src/main/org/apache/tools/ant/taskdefs/Replace.java b/src/main/org/apache/tools/ant/taskdefs/Replace.java
index 66cdef43b..a7daa0370 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Replace.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Replace.java
@@ -670,7 +670,7 @@ public class Replace extends MatchingTask {
                 if (changes) {
                     fileCount++;
                     long origLastModified = src.lastModified();
-                    FILE_UTILS.rename(temp, src);
+                    FILE_UTILS.rename(temp, src, true);
                     if (preserveLastModified) {
                         FILE_UTILS.setFileLastModified(src, origLastModified);
                     }
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java b/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java
index 5b7e3e695..c5b9d7d43 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java
@@ -434,7 +434,7 @@ public class ReplaceRegExp extends Task {
                 log("File has changed; saving the updated file", Project.MSG_VERBOSE);
                 try {
                     long origLastModified = f.lastModified();
-                    FILE_UTILS.rename(temp, f);
+                    FILE_UTILS.rename(temp, f, true);
                     if (preserveLastModified) {
                         FILE_UTILS.setFileLastModified(f, origLastModified);
                     }
diff --git a/src/main/org/apache/tools/ant/util/FileUtils.java b/src/main/org/apache/tools/ant/util/FileUtils.java
index 0deecaa7c..150bf5f85 100644
--- a/src/main/org/apache/tools/ant/util/FileUtils.java
+++ b/src/main/org/apache/tools/ant/util/FileUtils.java
@@ -40,6 +40,7 @@ import java.nio.file.attribute.FileAttribute;
 import java.nio.file.attribute.PosixFileAttributeView;
 import java.nio.file.attribute.PosixFilePermission;
 import java.nio.file.attribute.PosixFilePermissions;
+import java.lang.UnsupportedOperationException;
 import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -48,6 +49,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Optional;
 import java.util.Random;
+import java.util.Set;
 import java.util.Stack;
 import java.util.StringTokenizer;
 import java.util.Vector;
@@ -1450,6 +1452,27 @@ public class FileUtils {
      * @since Ant 1.6
      */
     public void rename(File from, File to) throws IOException {
+        rename(from, to, false);
+    }
+
+    /**
+     * Renames a file, even if that involves crossing file system boundaries.
+     *
+     * <p>This will remove <code>to</code> (if it exists), ensure that
+     * <code>to</code>'s parent directory exists and move
+     * <code>from</code>, which involves deleting <code>from</code> as
+     * well.</p>
+     *
+     * @param from the file to move.
+     * @param to the new file name.
+     * @param keepTargetFilePermissions keep target file permissions
+     * @throws IOException if anything bad happens during this
+     * process.  Note that <code>to</code> may have been deleted
+     * already when this happens.
+     * @since Ant 1.6
+     */
+    public void rename(File from, File to, boolean keepTargetFilePermissions) throws IOException {
+        Set<PosixFilePermission> existingFilePermissions = null;
         // identical logic lives in Move.renameFile():
         from = normalize(from.getAbsolutePath()).getCanonicalFile();
         to = normalize(to.getAbsolutePath());
@@ -1461,6 +1484,13 @@ public class FileUtils {
             System.err.println("Rename of " + from + " to " + to + " is a no-op.");
             return;
         }
+        if (keepTargetFilePermissions) {
+            try {
+                existingFilePermissions = Files.getPosixFilePermissions(to.toPath());
+            } catch (UnsupportedOperationException | IOException exc) {
+                //ignore
+            }
+        }
         if (to.exists() && !(areSame(from, to) || tryHardToDelete(to))) {
             throw new IOException("Failed to delete " + to + " while trying to rename " + from);
         }
@@ -1476,6 +1506,9 @@ public class FileUtils {
                 throw new IOException("Failed to delete " + from + " while trying to rename it.");
             }
         }
+        if (existingFilePermissions != null) {
+            Files.setPosixFilePermissions(to.toPath(), existingFilePermissions);
+        }
     }
 
     /**
diff --git a/src/tests/junit/org/apache/tools/ant/util/FileUtilsTest.java b/src/tests/junit/org/apache/tools/ant/util/FileUtilsTest.java
index 555916cac..5a168a514 100644
--- a/src/tests/junit/org/apache/tools/ant/util/FileUtilsTest.java
+++ b/src/tests/junit/org/apache/tools/ant/util/FileUtilsTest.java
@@ -26,6 +26,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.attribute.PosixFileAttributeView;
 import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
 import java.util.Locale;
 import java.util.Optional;
 import java.util.Set;
@@ -119,6 +120,39 @@ public class FileUtilsTest {
         assertNotEquals(thirdModTime, secondModTime);
     }
 
+    /**
+     * test file permissions for FileUtils#rename.
+     * Since Ant1.10.7, ant uses FileUtils#rename for various tasks (eg. ReplaceRegExp).
+     * Test that file permission set stays the same.
+     * @see FileUtils#rename(java.io.File, java.io.File, boolean)
+     * @throws IOException if something goes wrong
+     */
+    @Test
+    public void testFilePermissions() throws IOException {
+        assumeFalse("Test doesn't run on DOS", Os.isFamily("dos"));
+        File removeThis = getFileUtils().createTempFile("permis", "sion", folder.getRoot(), true, true);
+        File toBeMoved1 = getFileUtils().createTempFile("permis", "sion", folder.getRoot(), true, true);
+        File toBeMoved2 = getFileUtils().createTempFile("permis", "sion", folder.getRoot(), true, true);
+        try (FileOutputStream fos = new FileOutputStream(removeThis)) {
+            fos.write(new byte[0]);
+        }
+        try (FileOutputStream fos = new FileOutputStream(toBeMoved1)) {
+            fos.write(new byte[0]);
+        }
+        try (FileOutputStream fos = new FileOutputStream(toBeMoved2)) {
+            fos.write(new byte[0]);
+        }
+        Set<PosixFilePermission> allAllowed = PosixFilePermissions.fromString("rwxrwxrwx");
+        Files.setPosixFilePermissions(removeThis.toPath(), allAllowed);
+
+        getFileUtils().rename(toBeMoved1, removeThis, true);
+        assertEquals(allAllowed,Files.getPosixFilePermissions(removeThis.toPath()));
+
+        Set<PosixFilePermission> tempAllowed = Files.getPosixFilePermissions(toBeMoved2.toPath());
+        getFileUtils().rename(toBeMoved2, removeThis);
+        assertEquals(tempAllowed,Files.getPosixFilePermissions(removeThis.toPath()));
+    }
+
     @Test
     public void testResolveFilePosix() {
         assumeTrue("DOS or NetWare", !Os.isFamily("dos") && !Os.isFamily("netware"));