[elbe-devel] [RFC PATCH 6/6] efilesystem: Fix copy_filelist to handle symlinks

Torben Hohn torben.hohn at linutronix.de
Wed Apr 15 17:21:14 CEST 2020


On Tue, Apr 07, 2020 at 03:32:46PM -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>
> ---
>  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:

use os.path.isabs()
But... i dont understand the point.
What is different, if the files list contains a relative path ?
why would that not make the logic generate the parent directories ?

why not use os.path.join('/', tmp) ?

> +            files.add('/%s' % tmp)
> +            continue
> +
> +        parts = f.split(os.sep)[1:]
> +        parts.reverse()
> +        path = ""
> +        while parts:
> +            path += "/%s" % parts.pop()
> +            files.add(path)

this seems overly complicated to me.

i suggest:

------------------------------------------------------------------------
>>> files = set()
>>> parts = '/df/fg/df/fg'
>>> while parts != os.sep:
...     files.add(parts)
...     parts, _ = os.path.split(parts)
...     
... 
>>> files
{'/df/fg/df/fg', '/df/fg', '/df/fg/df', '/df'}
>>> 
------------------------------------------------------------------------

> +
> +    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:

os.path.isabs()

> +                # Get the absolute target
> +                tgt = os.path.join(os.sep.join(f.split(os.sep)[:-1]), tgt)

os.path.join(os.path.dirname(f), tgt) 

> +            if not dst.exists(tgt):
> +                # Defer symlink after target

improve comment, this confused me :)
f is the symlink, and tgt is the target, of course.
this would also recursively follow things, right ?

> +                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
> 
> 
> _______________________________________________
> 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