[elbe-devel] [RFC PATCH 6/6] efilesystem: Fix copy_filelist to handle symlinks
Olivier Dion
dion at linutronix.de
Tue Apr 7 21:32:46 CEST 2020
The algorithm is divided in 3 parts:
1. Construct a set of path to copy. Make it a list, sort it and
reverse it.
2. Iterate over all paths, ensure that directories exist. If a path
is a symlink, ensure that the target of the link exists, otherwise
defer the copy of the symlink after the construction of the target.
NOTE! There's no cycle detection here!
3. Copy stat for directories that aren't symlink since copying file
to it result in utime being changed.
Signed-off-by: Olivier Dion <dion at linutronix.de>
---
elbepack/efilesystem.py | 61 +++++++++++++++++++++++++++++++++--------
1 file changed, 49 insertions(+), 12 deletions(-)
diff --git a/elbepack/efilesystem.py b/elbepack/efilesystem.py
index 15074db2..3c0f64de 100644
--- a/elbepack/efilesystem.py
+++ b/elbepack/efilesystem.py
@@ -27,25 +27,62 @@ from elbepack.shellhelper import (system,
get_command_out)
-def copy_filelist(src, filelist, dst):
- for f in filelist:
- f = f.rstrip("\n")
- if src.isdir(f) and not src.islink(f):
+def copy_filelist(src, file_lst, dst):
+
+ files = set()
+
+ for f in file_lst:
+ tmp = f.rstrip('\n')
+
+ # Relative to root
+ if tmp[0] != os.sep:
+ files.add('/%s' % tmp)
+ continue
+
+ parts = f.split(os.sep)[1:]
+ parts.reverse()
+ path = ""
+ while parts:
+ path += "/%s" % parts.pop()
+ files.add(path)
+
+ files = list(files)
+ files.sort()
+ files.reverse()
+
+ copied = set()
+
+ while files:
+
+ f = files.pop()
+ copied.add(f)
+
+ if src.islink(f):
+ tgt = src.readlink(f)
+ # Relative?
+ if tgt[0] != os.path.sep:
+ # Get the absolute target
+ tgt = os.path.join(os.sep.join(f.split(os.sep)[:-1]), tgt)
+ if not dst.exists(tgt):
+ # Defer symlink after target
+ files.append(f)
+ files.append(tgt)
+ else:
+ dst.symlink(tgt, f)
+
+ elif src.isdir(f):
if not dst.isdir(f):
dst.mkdir(f)
st = src.stat(f)
dst.chown(f, st.st_uid, st.st_gid)
+
else:
- if src.isdir(f) and src.islink(f):
- tgt = src.readlink(f)
- if not dst.isdir(tgt):
- dst.mkdir(tgt)
- system('cp -a --reflink=auto "%s" "%s"' % (src.fname(f),
- dst.fname(f)))
+ system('cp -a --reflink=auto "%s" "%s"' % (src.realpath(f),
+ dst.realpath(f)))
+
# update utime which will change after a file has been copied into
# the directory
- for f in filelist:
- f = f.rstrip("\n")
+ for f in copied:
if src.isdir(f) and not src.islink(f):
shutil.copystat(src.fname(f), dst.fname(f))
--
2.26.0
More information about the elbe-devel
mailing list