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

rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat-jakartaee-migration.git


The following commit(s) were added to refs/heads/main by this push:
     new 303afc5  Avoid possible side effects on errors
303afc5 is described below

commit 303afc5c685f0c98bf28d4f2d778836aad604e7b
Author: remm <remm@meteor>
AuthorDate: Mon Sep 7 11:20:53 2026 +0200

    Avoid possible side effects on errors
    
    From further code review.
    Co authored with OpenCode.
---
 .../org/apache/tomcat/jakartaee/Migration.java     | 41 +++++++++++++++-------
 1 file changed, 28 insertions(+), 13 deletions(-)

diff --git a/src/main/java/org/apache/tomcat/jakartaee/Migration.java 
b/src/main/java/org/apache/tomcat/jakartaee/Migration.java
index 7c695cb..dbace17 100644
--- a/src/main/java/org/apache/tomcat/jakartaee/Migration.java
+++ b/src/main/java/org/apache/tomcat/jakartaee/Migration.java
@@ -257,7 +257,7 @@ public class Migration {
                 destination.getAbsolutePath(), profile.toString()));
 
         long t1 = System.nanoTime();
-        boolean failed = false;
+        boolean completed = false;
         try {
             if (source.isDirectory()) {
                 if (!destination.exists()) {
@@ -280,11 +280,14 @@ public class Migration {
                 }
                 migrateFile(source, destination);
             }
-        } catch (IOException e) {
-            failed = true;
-            throw e;
+            completed = true;
         } finally {
-            state = failed ? State.NOT_STARTED : State.COMPLETE;
+            // The migration only counts as complete if it ran to completion.
+            // Any exception that escapes (including unchecked exceptions, for
+            // example from a malformed class file) must leave the state as
+            // NOT_STARTED so a failed migration is never reported as having
+            // completed.
+            state = completed ? State.COMPLETE : State.NOT_STARTED;
 
             // Finalize cache operations (save metadata and prune expired 
entries).
             // A failure here must not mask a migration failure or cause a
@@ -362,15 +365,27 @@ public class Migration {
                 }
             }
         } else {
-            try (InputStream is = new FileInputStream(src);
-                    OutputStream os = new FileOutputStream(dest)) {
-                if (migrateStream(src.getAbsolutePath(), is, os)) {
-                    converted = true;
+            try (InputStream is = new FileInputStream(src)) {
+                final OutputStream os;
+                try {
+                    os = new FileOutputStream(dest);
+                } catch (IOException | RuntimeException e) {
+                    // The destination could not be opened. Any existing
+                    // destination file has not been modified and must be
+                    // left in place.
+                    throw e;
+                }
+                // The destination has now been created (and truncated). If
+                // it cannot be written completely, remove the partial file
+                // rather than leaving corrupted output behind.
+                try (OutputStream destStream = os) {
+                    if (migrateStream(src.getAbsolutePath(), is, destStream)) {
+                        converted = true;
+                    }
+                } catch (IOException | RuntimeException e) {
+                    dest.delete();
+                    throw e;
                 }
-            } catch (IOException e) {
-                // Remove the partially written destination file
-                dest.delete();
-                throw e;
             }
         }
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to