From a4e7c4e9b7fbefdc1bf00a75e68dc0262c622bd3 Mon Sep 17 00:00:00 2001 From: Raven Kopelman Date: Tue, 27 Oct 2020 13:39:32 -0700 Subject: [PATCH] Prevent files from being partially read from the cache --- SCons/CacheDir.py | 17 +++++++++++++++-- SCons/Taskmaster.py | 7 +++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/SCons/CacheDir.py b/SCons/CacheDir.py index 879c21bd73..cf8156319f 100644 --- a/SCons/CacheDir.py +++ b/SCons/CacheDir.py @@ -55,7 +55,20 @@ def CacheRetrieveFunc(target, source, env): if fs.islink(cachefile): fs.symlink(fs.readlink(cachefile), t.get_internal_path()) else: - env.copy_from_cache(cachefile, t.get_internal_path()) + try: + env.copy_from_cache(cachefile, t.get_internal_path()) + except: + try: + # In case file was partially retrieved (and now corrupt) + # delete it to avoid poisoning commands like 'ar' that + # read from the initial state of the file they are writing + # to. + t.fs.unlink(t.get_internal_path()) + except: + pass + + raise + try: os.utime(cachefile, None) except OSError: @@ -70,7 +83,7 @@ def CacheRetrieveString(target, source, env): cd = env.get_CacheDir() cachedir, cachefile = cd.cachepath(t) if t.fs.exists(cachefile): - return "Retrieved `%s' from cache" % t.get_internal_path() + return "Retrieving `%s' from cache" % t.get_internal_path() return None CacheRetrieve = SCons.Action.Action(CacheRetrieveFunc, CacheRetrieveString) diff --git a/SCons/Taskmaster.py b/SCons/Taskmaster.py index a1358e0476..59b15141e9 100644 --- a/SCons/Taskmaster.py +++ b/SCons/Taskmaster.py @@ -223,10 +223,13 @@ def execute(self): cached_targets.append(t) if len(cached_targets) < len(self.targets): # Remove targets before building. It's possible that we - # partially retrieved targets from the cache, leaving - # them in read-only mode. That might cause the command + # retrieved a subset of targets from the cache, leaving + # them in an inconsistent state. That might cause the command # to fail. # + # Note that retrieve_from_cache() ensures no single target can + # be partially retrieved (file left in corrupt state). + # for t in cached_targets: try: t.fs.unlink(t.get_internal_path())