@@ -169,7 +169,18 @@ def symlink(source, destination, force=False):
"""Create a symbolic link"""
try:
if force:
- remove(destination)
+ # Remove the exact destination path. Do not route this through
+ # remove(), which treats its argument as a glob pattern: a
+ # destination containing glob metacharacters (for example a
+ # '[' in the name) could fail to match, or match and delete
+ # unrelated files.
+ try:
+ os.unlink(destination)
+ except OSError as exc:
+ if exc.errno == errno.EISDIR:
+ shutil.rmtree(destination)
+ elif exc.errno != errno.ENOENT:
+ raise
os.symlink(source, destination)
except OSError as e:
if e.errno != errno.EEXIST or os.readlink(destination) != source:
symlink(source, destination, force=True) cleared an existing destination by calling remove(destination). remove() treats its argument as a glob pattern (it iterates glob.glob(path)), so a destination whose name contains glob metacharacters is mishandled: a name such as "foo[bar]" may fail to match itself and be left in place, or a pattern could match and delete unrelated files. Remove the literal destination instead: unlink it directly, and fall back to rmtree() for a directory, ignoring ENOENT. This keeps the force=True semantics without passing the path through glob. AI-Generated: codex/claude-opus 4.8 (xhigh) Signed-off-by: Trevor Woerner <twoerner@gmail.com> --- meta/lib/oe/path.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)