From 2d010727ed6657cb53d5043032417e0a9035e117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Aug 2018 04:12:29 +0200 Subject: minstall: never try to set chmod on symlinks It's only supported by few platforms when the linked file exists, while it would cause an error otherwise. In any case just implement this via an helper set_chmod function that will handle the case where follow_symlinks is not supported by the platform and will just not set any mod for the link itself (as it would otherwise apply to the linked file). Fixes #3914 --- mesonbuild/minstall.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'mesonbuild/minstall.py') diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index f08a6b3..5ac1279 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -79,13 +79,20 @@ def append_to_log(lf, line): lf.write('\n') lf.flush() +def set_chmod(path, mode, dir_fd=None, follow_symlinks=True): + try: + os.chmod(path, mode, dir_fd=dir_fd, follow_symlinks=follow_symlinks) + except (NotImplementedError, OSError, SystemError) as e: + if not os.path.islink(path): + os.chmod(path, mode, dir_fd=dir_fd) + def sanitize_permissions(path, umask): if umask is None: return new_perms = 0o777 if is_executable(path) else 0o666 new_perms &= ~umask try: - os.chmod(path, new_perms) + set_chmod(path, new_perms, follow_symlinks=False) except PermissionError as e: msg = '{!r}: Unable to set permissions {!r}: {}, ignoring...' print(msg.format(path, new_perms, e.strerror)) @@ -116,7 +123,7 @@ def set_mode(path, mode, default_umask): # NOTE: On Windows you can set read/write perms; the rest are ignored if mode.perms_s is not None: try: - os.chmod(path, mode.perms) + set_chmod(path, mode.perms, follow_symlinks=False) except PermissionError as e: msg = '{!r}: Unable to set permissions {!r}: {}, ignoring...' print(msg.format(path, mode.perms_s, e.strerror)) -- cgit v1.1 From 5de2a7910aafb39940789f5dbed244c230624917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Aug 2018 04:19:16 +0200 Subject: minstall: never follow symlinks when setting ownership Since we're supposed to call this for each installed path, we only should go through what we've installed and not what this point to, as it might be outside our scope or not existent. To do this, since shutil.chown doesn't expose the follow_symlink that os.chown has, we can temporarily replace os.chown with a lambda that acutually passes all the values as we want them, and then restore it to the built-in functions. Not the nicest way, but fixes the issue without having to reimplement what shutil does. Fixes #3914 --- mesonbuild/minstall.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'mesonbuild/minstall.py') diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index 5ac1279..3ae1199 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -79,6 +79,24 @@ def append_to_log(lf, line): lf.write('\n') lf.flush() +def set_chown(path, user=None, group=None, dir_fd=None, follow_symlinks=True): + # shutil.chown will call os.chown without passing all the parameters + # and particularly follow_symlinks, thus we replace it temporary + # with a lambda with all the parameters so that follow_symlinks will + # be actually passed properly. + # Not nice, but better than actually rewriting shutil.chown until + # this python bug is fixed: https://bugs.python.org/issue18108 + real_os_chown = os.chown + try: + os.chown = lambda p, u, g: real_os_chown(p, u, g, + dir_fd=dir_fd, + follow_symlinks=follow_symlinks) + shutil.chown(path, user, group) + except: + raise + finally: + os.chown = real_os_chown + def set_chmod(path, mode, dir_fd=None, follow_symlinks=True): try: os.chmod(path, mode, dir_fd=dir_fd, follow_symlinks=follow_symlinks) @@ -105,7 +123,7 @@ def set_mode(path, mode, default_umask): # No chown() on Windows, and must set one of owner/group if not is_windows() and (mode.owner or mode.group) is not None: try: - shutil.chown(path, mode.owner, mode.group) + set_chown(path, mode.owner, mode.group, follow_symlinks=False) except PermissionError as e: msg = '{!r}: Unable to set owner {!r} and group {!r}: {}, ignoring...' print(msg.format(path, mode.owner, mode.group, e.strerror)) -- cgit v1.1 From abf65c92af298683fa9ffa5e360ce6c836a1d2fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 17 Aug 2018 04:02:23 +0200 Subject: minstall: use follow_symlinks to check executable This could happen when setting an default install mode but with broken symlinks. Fixes #3914 --- mesonbuild/minstall.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'mesonbuild/minstall.py') diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index 3ae1199..748f06b 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -69,9 +69,9 @@ class DirMaker: for d in self.dirs: append_to_log(self.lf, d) -def is_executable(path): +def is_executable(path, follow_symlinks=False): '''Checks whether any of the "x" bits are set in the source file mode.''' - return bool(os.stat(path).st_mode & 0o111) + return bool(os.stat(path, follow_symlinks=follow_symlinks).st_mode & 0o111) def append_to_log(lf, line): lf.write(line) @@ -107,7 +107,7 @@ def set_chmod(path, mode, dir_fd=None, follow_symlinks=True): def sanitize_permissions(path, umask): if umask is None: return - new_perms = 0o777 if is_executable(path) else 0o666 + new_perms = 0o777 if is_executable(path, follow_symlinks=False) else 0o666 new_perms &= ~umask try: set_chmod(path, new_perms, follow_symlinks=False) -- cgit v1.1