Don't copy mode and attrs for existing dirs (e.g. /tmp), closes #6

This commit is contained in:
Disassembler 2020-04-26 12:28:04 +02:00
parent ba9baa9362
commit 4f33d97386
No known key found for this signature in database
GPG Key ID: 524BD33A0EE29499

View File

@ -112,10 +112,10 @@ class ImageBuilder:
unpack_http_archive(src, dst)
else:
src = os.path.join(self.builddir, src)
if not os.path.isdir(src):
shutil.copy2(src, dst)
if os.path.isdir(src):
copy_tree(src, dst)
else:
shutil.copytree(src, dst, symlinks=True, ignore_dangling_symlinks=True, dirs_exist_ok=True)
shutil.copy2(src, dst)
# Shift UID/GID of the files to the unprivileged range
shift_uid(dst, os.stat(dst, follow_symlinks=False))
@ -141,6 +141,22 @@ def unpack_http_archive(src, dst):
with tarfile.open(fileobj=tmp_archive) as tar:
tar.extractall(dst, numeric_owner=True)
def copy_tree(src, dst):
# Copy directory tree from host to container, leaving the existing modes and attributed unchanged,
# which is crucial e.g. whenever anything is copied into /tmp
# This function is a stripped and customized variant of shutil.copytree()
for srcentry in os.scandir(src):
dstname = os.path.join(dst, srcentry.name)
is_new = not os.path.exists(dstname)
if srcentry.is_dir():
if is_new:
os.mkdir(dstname)
copy_tree(srcentry, dstname)
else:
shutil.copy2(srcentry, dstname)
if is_new:
shutil.copystat(srcentry, dstname, follow_symlinks=False)
def shift_uid(path, path_stat):
# Shifts UID/GID of a file or a directory and its contents to the unprivileged range
# The function parameters could arguably be more friendly, but os.scandir() already calls stat() on the entires,