From 43b748f2541ea77b2aa7b2f7eb4e0e8387beecca Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 17 Apr 2015 12:50:31 +0100 Subject: 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 --- updater/blockimg.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) (limited to 'updater/blockimg.c') 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 @@ lsout: } 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 @@ static int WriteStash(const char* base, const char* id, int blocks, uint8_t* buf 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 @@ static int SaveStash(const char* base, char** wordsave, uint8_t** buffer, size_t } 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 @@ static int LoadSrcTgtVersion3(CommandParameters* params, RangeSet** tgt, int* sr 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 @@ static int LoadSrcTgtVersion3(CommandParameters* params, RangeSet** tgt, int* sr 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 @@ static int LoadSrcTgtVersion3(CommandParameters* params, RangeSet** tgt, int* sr if (*overlap && LoadStash(params->stashbase, srchash, 1, NULL, ¶ms->buffer, ¶ms->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; } -- cgit v1.1