Patchwork [bitbake-devel] siggen.py: Insure .siginfo files writes into shared sstate cache are atomic

login
register
mail settings
Submitter Jeffrey Honig
Date July 17, 2012, 12:48 a.m.
Message ID <1342486137-9149-1-git-send-email-jeffrey.honig@windriver.com>
Download mbox | patch
Permalink /patch/32193/
State New
Headers show

Comments

Jeffrey Honig - July 17, 2012, 12:48 a.m.
Use tempfile.mkstemp to create a temporary file in the sstate dir and move it
   into place after closing.  The previous code would fail in the chmod() if two
   users were running jobs that touched the same signature file.

Signed-off-by: Jeffrey C Honig <jeffrey.honig@windriver.com>
---
 lib/bb/siggen.py |   19 +++++++++++++++----
 1 files changed, 15 insertions(+), 4 deletions(-)
Richard Purdie - July 17, 2012, 9:53 a.m.
On Mon, 2012-07-16 at 20:48 -0400, Jeffrey C Honig wrote:
> Use tempfile.mkstemp to create a temporary file in the sstate dir and move it
>    into place after closing.  The previous code would fail in the chmod() if two
>    users were running jobs that touched the same signature file.
> 
> Signed-off-by: Jeffrey C Honig <jeffrey.honig@windriver.com>
> ---
>  lib/bb/siggen.py |   19 +++++++++++++++----
>  1 files changed, 15 insertions(+), 4 deletions(-)

Merged to master, thanks.

Richard

Patch

diff --git a/lib/bb/siggen.py b/lib/bb/siggen.py
index edd98fc..02a4268 100644
--- a/lib/bb/siggen.py
+++ b/lib/bb/siggen.py
@@ -2,6 +2,7 @@  import hashlib
 import logging
 import os
 import re
+import tempfile
 import bb.data
 
 logger = logging.getLogger('BitBake.SigGen')
@@ -236,10 +237,20 @@  class SignatureGeneratorBasic(SignatureGenerator):
         if taint:
             data['taint'] = taint
 
-        with open(sigfile, "wb") as f:
-            p = pickle.Pickler(f, -1)
-            p.dump(data)
-        os.chmod(sigfile, 0664)
+        fd, tmpfile = tempfile.mkstemp(dir=os.path.dirname(sigfile), prefix="sigtask.")
+        try:
+            with os.fdopen(fd, "wb") as stream:
+                p = pickle.dump(data, stream, -1)
+                stream.flush()
+                os.fsync(fd)
+            os.chmod(tmpfile, 0664)
+            os.rename(tmpfile, sigfile)
+        except (OSError, IOError), err:
+            try:
+                os.unlink(tmpfile)
+            except OSError:
+                pass
+            raise err
 
     def dump_sigs(self, dataCache):
         for fn in self.taskdeps: