[elbe-devel] [PATCH v2 7/9] efilesystem: Fix copy_filelist to handle symlinks

Torben Hohn torben.hohn at linutronix.de
Wed May 13 14:10:30 CEST 2020


On Mon, May 04, 2020 at 02:00:10PM -0400, Olivier Dion wrote:
> 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>

Reviewed-by: Torben Hohn <torben.hohn at linutronix.de>

> ---
>  elbepack/efilesystem.py | 65 +++++++++++++++++++++++++++++++++--------
>  1 file changed, 53 insertions(+), 12 deletions(-)
> 
> diff --git a/elbepack/efilesystem.py b/elbepack/efilesystem.py
> index 15074db2..b74f0ac3 100644
> --- a/elbepack/efilesystem.py
> +++ b/elbepack/efilesystem.py
> @@ -27,25 +27,66 @@ 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()
> +    copied = set()
> +
> +    # Make sure to copy parent directories
> +    #
> +    # For example, if file_lst = ['/usr/bin/bash'],
> +    # we might get {'/usr/bin', '/usr', '/usr/bin/bash'}
> +    for f in file_lst:
> +        parts = f.rstrip('\n')
> +        while parts != os.sep:
> +            files.add(parts)
> +            parts, _ = os.path.split(parts)
> +
> +    # Start from closest to root first
> +    files = list(files)
> +    files.sort()
> +    files.reverse()
> +
> +    while files:
> +
> +        f = files.pop()
> +        copied.add(f)
> +
> +        if src.islink(f):
> +
> +            tgt = src.readlink(f)
> +
> +            # If the target of the symlink is relative, we need the
> +            # absolute path of it
> +            if not os.path.isabs(tgt):
> +                tgt = os.path.join(os.path.dirname(f), tgt)
> +
> +            # If the target is not yet in the destination RFS, we need
> +            # to defer the copy of the symlink after the target is
> +            # resolved.  Thus, we put the symlink back on the stack
> +            # and we add the target to resolve on top of it.
> +            #
> +            # Not that this will result in an infinite loop for
> +            # circular symlinks
> +            if not dst.lexists(tgt):
> +                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.2
> 
> 
> _______________________________________________
> elbe-devel mailing list
> elbe-devel at linutronix.de
> https://lists.linutronix.de/mailman/listinfo/elbe-devel

-- 
Torben Hohn
Linutronix GmbH | Bahnhofstrasse 3 | D-88690 Uhldingen-Mühlhofen
Phone: +49 7556 25 999 18; Fax.: +49 7556 25 999 99

Hinweise zum Datenschutz finden Sie hier (Informations on data privacy 
can be found here): https://linutronix.de/kontakt/Datenschutz.php

Linutronix GmbH | Firmensitz (Registered Office): Uhldingen-Mühlhofen | 
Registergericht (Registration Court): Amtsgericht Freiburg i.Br., HRB700 
806 | Geschäftsführer (Managing Directors): Heinz Egger, Thomas Gleixner



More information about the elbe-devel mailing list