Index: trunk/base/src/registry2.0/portimage.tcl
===================================================================
--- trunk/base/src/registry2.0/portimage.tcl	(revision 118302)
+++ trunk/base/src/registry2.0/portimage.tcl	(revision 118303)
@@ -135,5 +135,4 @@
 
     _activate_contents $requested
-    $requested state installed
 }
 
@@ -202,5 +201,4 @@
 
     _deactivate_contents $requested [$requested files] $force
-    $requested state imaged
 }
 
@@ -542,4 +540,9 @@
                     }
                 }
+
+                # Recording that the port has been activated should be done
+                # here so that this information cannot be inconsistent with the
+                # state of the files on disk.
+                $port state installed
             } catch {{POSIX SIG SIGINT} eCode eMessage} {
                 # Pressing ^C will (often?) print "^C" to the terminal; send
@@ -564,27 +567,37 @@
     } catch {*} {
         # This code must run to completion, or the installation might be left
-        # in an inconsistent state
-        signal block {TERM INT}
-
-        # roll back activation of this port
-        if {[info exists deactivate_this]} {
-            _deactivate_contents $port $rollback_filelist yes yes
-        }
-        # if any errors occurred, move backed-up files back to their original
-        # locations, then rethrow the error. Transaction rollback will take care
-        # of this in the registry.
-        foreach file $backups {
-            ::file rename -force -- "${file}${baksuffix}" $file
-        }
-        # reactivate deactivated ports
-        foreach entry [array names todeactivate] {
-            if {[$entry state] eq "imaged" && ($noexec || ![registry::run_target $entry activate ""])} {
-                activate [$entry name] [$entry version] [$entry revision] [$entry variants] [list ports_activate_no-exec $noexec]
-            }
-        }
-
-        # We've completed all critical operations, re-enable the TERM and INT
-        # signals.
-        signal unblock {TERM INT}
+        # in an inconsistent state. We store the old signal handling state,
+        # block the critical signals and restore to the previous state instead
+        # of unblocking.
+        # Note that this still contains a race condition: A user could press ^C
+        # fast enough so that the second error arrives before the error is
+        # caught, re-thrown and re-caught here. As far as I can see, there's no
+        # easy way around this problem.
+        set osignals [signal get {TERM INT}]
+        try {
+            # Block signals to avoid inconsistiencies.
+            signal block {TERM INT}
+
+            # roll back activation of this port
+            if {[info exists deactivate_this]} {
+                _deactivate_contents $port $rollback_filelist yes yes
+            }
+            # if any errors occurred, move backed-up files back to their original
+            # locations, then rethrow the error. Transaction rollback will take care
+            # of this in the registry.
+            foreach file $backups {
+                ::file rename -force -- "${file}${baksuffix}" $file
+            }
+            # reactivate deactivated ports
+            foreach entry [array names todeactivate] {
+                if {[$entry state] eq "imaged" && ($noexec || ![registry::run_target $entry activate ""])} {
+                    activate [$entry name] [$entry version] [$entry revision] [$entry variants] [list ports_activate_no-exec $noexec]
+                }
+            }
+        } finally {
+            # We've completed all critical operations, re-enable the TERM and
+            # INT signals.
+            signal set $osignals
+        }
 
         # remove temp image dir
@@ -661,16 +674,36 @@
     set files [lsort -decreasing -unique $files]
 
-    # Remove all elements.
-    if {!$rollback} {
-        registry::write {
-            $port deactivate $imagefiles
+    # Avoid interruptions while removing the files and updating the database to
+    # prevent inconsistencies from forming between filesystem and database.
+    set osignals [signal get {TERM INT}]
+
+    try {
+        # Block the TERM and INT signals to avoid being interrupted. Note that
+        # they might already be block at this point because
+        # _deactivate_contents might be called during rollback of
+        # _activate_contents, but because we're storing the old signal state
+        # and returning to that instead of unblocking it doesn't matter.
+        signal block {TERM INT}
+
+        # Remove all elements.
+        if {!$rollback} {
+            registry::write {
+                $port deactivate $imagefiles
+                foreach file $files {
+                    _deactivate_file $file
+                }
+
+                # Update the port's state in the same transaction as the file
+                # delete operations.
+                $port state imaged
+            }
+        } else {
             foreach file $files {
                 _deactivate_file $file
             }
         }
-    } else {
-        foreach file $files {
-            _deactivate_file $file
-        }
+    } finally {
+        # restore the signal block state
+        signal set $osignals
     }
 }
