Don't remove existing explicitly stashed blocks

When automatically stashing overlapping blocks, should the stash
file already exist due to an explicit stash command, it's not safe
to remove the stash file after the command has completed.

Note that it is safe to assume that the stash file will remain in
place during the execution of the next command, so we don't have
take other measures to preserve overlapping blocks.

The stash file itself will be removed by a free command when it's
no longer needed.

Bug: 20297065
Change-Id: I8ff1a798b94086adff183c5aac03260eb947ae2c
diff --git a/updater/blockimg.c b/updater/blockimg.c
index 90b55b2..d5344f9 100644
--- a/updater/blockimg.c
+++ b/updater/blockimg.c
@@ -635,12 +635,13 @@
 }
 
 static int WriteStash(const char* base, const char* id, int blocks, uint8_t* buffer,
-        int checkspace) {
+        int checkspace, int *exists) {
     char *fn = NULL;
     char *cn = NULL;
     int fd = -1;
     int rc = -1;
     int res;
+    struct stat st;
 
     if (base == NULL || buffer == NULL) {
         goto wsout;
@@ -658,6 +659,22 @@
         goto wsout;
     }
 
+    if (exists) {
+        res = stat(cn, &st);
+
+        if (res == 0) {
+            // The file already exists and since the name is the hash of the contents,
+            // it's safe to assume the contents are identical (accidental hash collisions
+            // are unlikely)
+            fprintf(stderr, " skipping %d existing blocks in %s\n", blocks, cn);
+            *exists = 1;
+            rc = 0;
+            goto wsout;
+        }
+
+        *exists = 0;
+    }
+
     fprintf(stderr, " writing %d blocks to %s\n", blocks, cn);
 
     fd = TEMP_FAILURE_RETRY(open(fn, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, STASH_FILE_MODE));
@@ -821,7 +838,7 @@
     }
 
     fprintf(stderr, "stashing %d blocks to %s\n", blocks, id);
-    return WriteStash(base, id, blocks, *buffer, 0);
+    return WriteStash(base, id, blocks, *buffer, 0, NULL);
 }
 
 static int FreeStash(const char* base, const char* id) {
@@ -997,6 +1014,7 @@
                               int onehash, int* overlap) {
     char* srchash = NULL;
     char* tgthash = NULL;
+    int stash_exists = 0;
     int overlap_blocks = 0;
     int rc = -1;
     uint8_t* tgtbuffer = NULL;
@@ -1052,13 +1070,16 @@
             fprintf(stderr, "stashing %d overlapping blocks to %s\n", *src_blocks,
                 srchash);
 
-            if (WriteStash(params->stashbase, srchash, *src_blocks, params->buffer, 1) != 0) {
+            if (WriteStash(params->stashbase, srchash, *src_blocks, params->buffer, 1,
+                    &stash_exists) != 0) {
                 fprintf(stderr, "failed to stash overlapping source blocks\n");
                 goto v3out;
             }
 
             // Can be deleted when the write has completed
-            params->freestash = srchash;
+            if (!stash_exists) {
+                params->freestash = srchash;
+            }
         }
 
         // Source blocks have expected content, command can proceed
@@ -1068,12 +1089,9 @@
 
     if (*overlap && LoadStash(params->stashbase, srchash, 1, NULL, &params->buffer,
                         &params->bufsize, 1) == 0) {
-        // Overlapping source blocks were previously stashed, command can proceed
-        if (params->canwrite) {
-            // We didn't create the stash, so delete after write only if we will
-            // actually perform the write
-            params->freestash = srchash;
-        }
+        // Overlapping source blocks were previously stashed, command can proceed.
+        // We are recovering from an interrupted command, so we don't know if the
+        // stash can safely be deleted after this command.
         rc = 0;
         goto v3out;
     }