[OE-core] [PATCH 1/1] fetch2: Create/replace symbolic links atomically
Peter Kjellerstedt
peter.kjellerstedt at axis.com
Tue Mar 28 12:30:43 UTC 2017
Under rare circumstances, creating symbolic links could fail because
the link already exists. At first glance the code seemed to protect
against this, but there was a small window where two separate tasks
could decide that a symbolic link needed to be created and then the
first task would create it and the second task would fail.
Signed-off-by: Peter Kjellerstedt <peter.kjellerstedt at axis.com>
---
bitbake/lib/bb/fetch2/__init__.py | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/bitbake/lib/bb/fetch2/__init__.py b/bitbake/lib/bb/fetch2/__init__.py
index 464e66b98a..f891e34eab 100644
--- a/bitbake/lib/bb/fetch2/__init__.py
+++ b/bitbake/lib/bb/fetch2/__init__.py
@@ -25,7 +25,7 @@ BitBake build tools.
#
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
-import os, re
+import os, re, tempfile
import signal
import logging
import urllib.request, urllib.parse, urllib.error
@@ -946,6 +946,16 @@ def rename_bad_checksum(ud, suffix):
bb.warn("Renaming %s to %s" % (ud.localpath, new_localpath))
bb.utils.movefile(ud.localpath, new_localpath)
+def atomic_symlink(src, dst):
+ """Create/replace a symbolic link atomically."""
+
+ tmpname = tempfile.mktemp(prefix=dst)
+ os.symlink(src, tmpname)
+ try:
+ os.rename(tmpname, dst)
+ except OSError:
+ os.remove(tmpname)
+ raise
def try_mirror_url(fetch, origud, ud, ld, check = False):
# Return of None or a value means we're finished
@@ -983,7 +993,7 @@ def try_mirror_url(fetch, origud, ud, ld, check = False):
open(ud.donestamp, 'w').close()
dest = os.path.join(dldir, os.path.basename(ud.localpath))
if not os.path.exists(dest):
- os.symlink(ud.localpath, dest)
+ atomic_symlink(ud.localpath, dest)
if not verify_donestamp(origud, ld) or origud.method.need_update(origud, ld):
origud.method.download(origud, ld)
if hasattr(origud.method,"build_mirror_data"):
@@ -991,11 +1001,7 @@ def try_mirror_url(fetch, origud, ud, ld, check = False):
return origud.localpath
# Otherwise the result is a local file:// and we symlink to it
if not os.path.exists(origud.localpath):
- if os.path.islink(origud.localpath):
- # Broken symbolic link
- os.unlink(origud.localpath)
-
- os.symlink(ud.localpath, origud.localpath)
+ atomic_symlink(ud.localpath, origud.localpath)
update_stamp(origud, ld)
return ud.localpath
--
2.12.0
More information about the Openembedded-core
mailing list