Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 678462 - sys-apps/portage: INSTALL_MASK does not filter symlinks to existing dirs
Summary: sys-apps/portage: INSTALL_MASK does not filter symlinks to existing dirs
Status: RESOLVED FIXED
Alias: None
Product: Portage Development
Classification: Unclassified
Component: Core (show other bugs)
Hardware: All Linux
: Normal normal (vote)
Assignee: Portage team
URL: https://crbug.com/924355
Whiteboard:
Keywords: InVCS
Depends on: 837899
Blocks:
  Show dependency tree
 
Reported: 2019-02-21 06:47 UTC by SpanKY
Modified: 2022-07-10 16:31 UTC (History)
1 user (show)

See Also:
Package list:
Runtime testing required: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description SpanKY gentoo-dev 2019-02-21 06:47:52 UTC
reproduction:
src_install() {
    dodir /foo
    dosym / /foo/sym
    dosym /xxx /foo/broken-sym
    touch "${D}/foo/file"
    mkdir "${D}"/foo/dir
}

then install it with INSTALL_MASK=/foo.  the /foo/sym will be left behind.

looks like it's due to os.walk (mis)behavior.  symlinks are placed into dirs/files based on its target (probably using stat) instead of lstat.  you can see:
  mkdir x
  ln -s / x/sym
  ln -s /xxx x/broken-sym
  touch s/file
  python
  >>> import os
  >>> for args in os.walk('./x'):
  ...   print(args)
  ...
  ('./x', ['sym'], ['broken-sym', 'file'])

i tried hacking up install_mask.py, but ran into failures in portage's internal os.unlink wrapper.  so i gave up.

@@ -173,4 +102,15 @@ def install_mask_dir(base_dir, install_m
                        continue
                dir_stack.append(parent)
+
+               # os.walk will return valid symlinks to dirs in dirs.
+               for d in dirs:
+                       try:
+                               tmpd = _unicode_decode(d, errors='strict')
+                       except UnicodeDecodeError:
+                               continue
+                       abs_path = os.path.join(parent, tmpd)
+                       if os.path.islink(abs_path):
+                               files.append(d)
+
                for fname in files:
                        try:

example:
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/portage/dbapi/_MergeProcess.py", line 234, in _spawn
    prev_mtimes=self.prev_mtimes, counter=counter)
  File "/usr/lib64/python2.7/site-packages/portage/dbapi/vartree.py", line 1677, in wrapper
    return f(self, *args, **kwargs)
  File "/usr/lib64/python2.7/site-packages/portage/dbapi/vartree.py", line 5167, in merge
    counter=counter)
  File "/usr/lib64/python2.7/site-packages/portage/dbapi/vartree.py", line 3888, in treewalk
    install_mask_dir(self.settings["ED"], install_mask)
  File "/usr/lib64/python2.7/site-packages/portage/util/install_mask.py", line 98, in install_mask_dir
    for parent, dirs, files in os.walk(base_dir, onerror=onerror):
  File "/usr/lib64/python2.7/os.py", line 296, in walk
    for x in walk(new_path, topdown, onerror, followlinks):
  File "/usr/lib64/python2.7/os.py", line 296, in walk
    for x in walk(new_path, topdown, onerror, followlinks):
  File "/usr/lib64/python2.7/os.py", line 281, in walk
    onerror(err)
  File "/usr/lib64/python2.7/site-packages/portage/util/install_mask.py", line 80, in _raise_exc
    raise wrapper
FileNotFound: [Errno 2] No such file or directory: '/build/elm/tmp/portage/app-eselect/eselect-awk-0.2/image/foo/sym'
Comment 1 Arfrever Frehtes Taifersar Arahesis 2019-02-22 02:06:19 UTC
When adding a symlink to 'files' variable, you forgot to remove it from 'dirs' variable:

            if os.path.islink(abs_path):
                files.append(d)
                dirs.remove(d)

Then your patch would happen to work.
Comment 3 Larry the Git Cow gentoo-dev 2022-04-15 04:26:28 UTC
The bug has been referenced in the following commit(s):

https://gitweb.gentoo.org/proj/portage.git/commit/?id=5cc166489106da93c20ad3c5bb138ba8a359de2c

commit 5cc166489106da93c20ad3c5bb138ba8a359de2c
Author:     Jeff Chase <jnchase@google.com>
AuthorDate: 2021-05-04 17:29:58 +0000
Commit:     Sam James <sam@gentoo.org>
CommitDate: 2022-04-15 04:26:22 +0000

    install_mask: remove masked symlinks to directories (bug 678462)
    
    os.walk() categorizes symlinks to directories as directories so they
    were being ignored by INSTALL_MASK. This change calls os.scandir()
    instead which efficiently provides more control.
    
    [sam: cherry-picked from chromiumos' third_party/portage_tool repo]
    (cherry picked from commit 6473079d07351dda49a906cb89d24a9a39526bf7)
    Bug: https://bugs.gentoo.org/678462
    Signed-off-by: Sam James <sam@gentoo.org>
    Closes: https://github.com/gentoo/portage/pull/820
    Signed-off-by: Sam James <sam@gentoo.org>

 lib/portage/tests/util/test_install_mask.py | 33 +++++++++++++++++++++++++++--
 lib/portage/util/install_mask.py            | 18 ++++++++++------
 2 files changed, 42 insertions(+), 9 deletions(-)