keys.delete-keeper: Only do one pass through the file system.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 15 Jul 2017 17:58:59 +0000 (18:58 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 16 Jul 2017 01:12:33 +0000 (02:12 +0100)
Rather than doing a pass to check that we won't orphan any recovery keys
and then another pass to figure out which recovery keys need modifying,
gather enough information in the first pass that we can do the second
just from the recorded data.

keys.delete-keeper

index 778f696..edcb718 100755 (executable)
@@ -45,8 +45,11 @@ if [ ! -d $keeper ]; then
 fi
 
 ## Make sure that there aren't recovery keys which would be orphaned by
-## deleting this keeper set.
-unset deps
+## deleting this keeper set.  Also, build a data structure of recovery keys
+## and their instances: `$recov' is a space-separated list of recovery key
+## labels, and for each such label R, `$ri_R' is a space-separated list of
+## its instances.
+unset deps; recov=" "
 if [ -d $KEYS/recov ]; then
   cd $KEYS/recov
 
@@ -55,11 +58,18 @@ if [ -d $KEYS/recov ]; then
     r=${r#./}; r=${r%/current}
     if ! expr >/dev/null "Q$r" : "Q$R_LABEL"; then continue; fi
 
+    ## Add the key to our list.
+    recov="$recov$r "
+
     ## Now work through the instances.
+    ii=""
     for ri in $r/*; do
       i=${ri##*/}
       case "$i" in *[!0-9]*) continue ;; esac
 
+      ## Add the instance to our list.
+      ii="$ii $i"
+
       ## For each recovery key, make sure that: either it doesn't depend on
       ## this keeper set, or it also depends on at least one other set.  If
       ## not, add it to the `deps' list.
@@ -70,6 +80,9 @@ if [ -d $KEYS/recov ]; then
       done
       case $this,$others in t,nil) deps="$deps $ri" ;; esac
     done
+
+    ## Record the list of instances.
+    eval "ri_$r=\$ii"
   done
 fi
 
@@ -83,33 +96,23 @@ case "${deps+t}" in
 esac
 
 ## Disentangle the dependent recovery keys from this keeper set.
-if [ -d $KEYS/recov ]; then
-  cd $KEYS/recov
-
-  ## Work through the recovery keys again.
-  for r in $(find . -type l -name current -print); do
-    r=${r#./}; r=${r%/current}
-    if ! expr >/dev/null "Q$r" : "Q$R_LABEL"; then continue; fi
-
-    ## Remove the keeper data from the key's instances.
-    for ri in $i/*; do
-      i=${ri##*/}
-      case "$i" in *[!0-9]*) continue ;; esac
-      rm -f $ri/$keeper.*
-    done
-
-    ## Work through the current keepers, and remove our keeper's name from
-    ## the list.
-    changep=nil
-    while read k rest; do
-      case $k in $keeper) changep=t ;; *) echo "$k $rest" ;; esac
-    done <$r/keepers >$r/keepers.new
-    case $changep in
-      t) mv $r/keepers.new $r/keepers ;;
-      nil) rm $r/keepers.new ;;
-    esac
-  done
-fi
+for r in $recov; do
+
+  ## Remove the keeper data from the key's instances.
+  eval "ii=\$ri_$r"
+  for i in $ii; do rm -f $r/$i/$keeper.*; done
+
+  ## Work through the current keepers, and remove our keeper's name from the
+  ## list.
+  changep=nil
+  while read k rest; do
+    case $k in $keeper) changep=t ;; *) echo "$k $rest" ;; esac
+  done <$r/keepers >$r/keepers.new
+  case $changep in
+    t) mv $r/keepers.new $r/keepers ;;
+    nil) rm $r/keepers.new ;;
+  esac
+done
 
 ## Finally, actually delete the keeper keys.
 cd $KEYS/keeper