1 |
On Sat, 3 Oct 2015 09:15:56 -0700 |
2 |
Zac Medico <zmedico@g.o> wrote: |
3 |
|
4 |
> Use the apply_recursive_permissions function to minimize the number of |
5 |
> chmod calls. |
6 |
> |
7 |
> Also, fix an UnboundLocalError triggered in portage.data._get_global |
8 |
> by chmod-lite. |
9 |
> |
10 |
> X-Gentoo-Bug: 554084 |
11 |
> X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=554084 |
12 |
> --- |
13 |
> [PATCH v4] adds backward compatibility to apply_recursive_permissions |
14 |
> for the case where the given path does not exist |
15 |
> |
16 |
> bin/chmod-lite | 10 +++++ |
17 |
> bin/chmod-lite.py | 30 ++++++++++++++ |
18 |
> bin/phase-helpers.sh | 2 +- |
19 |
> pym/portage/data.py | 2 +- |
20 |
> pym/portage/util/__init__.py | 93 |
21 |
> ++++++++++++++++++++++++-------------------- 5 files changed, 92 |
22 |
> insertions(+), 45 deletions(-) create mode 100755 bin/chmod-lite |
23 |
> create mode 100755 bin/chmod-lite.py |
24 |
> |
25 |
> diff --git a/bin/chmod-lite b/bin/chmod-lite |
26 |
> new file mode 100755 |
27 |
> index 0000000..ffa8d4d |
28 |
> --- /dev/null |
29 |
> +++ b/bin/chmod-lite |
30 |
> @@ -0,0 +1,10 @@ |
31 |
> +#!/bin/bash |
32 |
> +# Copyright 2015 Gentoo Foundation |
33 |
> +# Distributed under the terms of the GNU General Public License v2 |
34 |
> + |
35 |
> +export __PORTAGE_HELPER_CWD=${PWD} |
36 |
> + |
37 |
> +# Use safe cwd, avoiding unsafe import for bug #469338. |
38 |
> +cd "${PORTAGE_PYM_PATH}" || exit 1 |
39 |
> +PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ |
40 |
> + exec "${PORTAGE_PYTHON:-/usr/bin/python}" |
41 |
> "$PORTAGE_BIN_PATH/chmod-lite.py" "$@" diff --git a/bin/chmod-lite.py |
42 |
> b/bin/chmod-lite.py new file mode 100755 |
43 |
> index 0000000..177be7e |
44 |
> --- /dev/null |
45 |
> +++ b/bin/chmod-lite.py |
46 |
> @@ -0,0 +1,30 @@ |
47 |
> +#!/usr/bin/python -b |
48 |
> +# Copyright 2015 Gentoo Foundation |
49 |
> +# Distributed under the terms of the GNU General Public License v2 |
50 |
> + |
51 |
> +import os |
52 |
> +import sys |
53 |
> + |
54 |
> +from portage.util import apply_recursive_permissions |
55 |
> + |
56 |
> +# Change back to original cwd _after_ all imports (bug #469338). |
57 |
> +os.chdir(os.environ["__PORTAGE_HELPER_CWD"]) |
58 |
> + |
59 |
> +def main(files): |
60 |
> + |
61 |
> + if sys.hexversion >= 0x3000000: |
62 |
> + # We can't trust that the filesystem encoding |
63 |
> (locale dependent) |
64 |
> + # correctly matches the arguments, so use |
65 |
> surrogateescape to |
66 |
> + # pass through the original argv bytes for Python 3. |
67 |
> + fs_encoding = sys.getfilesystemencoding() |
68 |
> + files = [x.encode(fs_encoding, 'surrogateescape') |
69 |
> for x in files] + |
70 |
> + for filename in files: |
71 |
> + # Emulate 'chmod -fR a+rX,u+w,g-w,o-w' with minimal |
72 |
> chmod calls. |
73 |
> + apply_recursive_permissions(filename, filemode=0o644, |
74 |
> + filemask=0o022, dirmode=0o755, dirmask=0o022) |
75 |
> + |
76 |
> + return os.EX_OK |
77 |
> + |
78 |
> +if __name__ == "__main__": |
79 |
> + sys.exit(main(sys.argv[1:])) |
80 |
> diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh |
81 |
> index efd2cfa..0c25ffe 100644 |
82 |
> --- a/bin/phase-helpers.sh |
83 |
> +++ b/bin/phase-helpers.sh |
84 |
> @@ -532,7 +532,7 @@ unpack() { |
85 |
> # Do not chmod '.' since it's probably ${WORKDIR} and |
86 |
> PORTAGE_WORKDIR_MODE # should be preserved. |
87 |
> find . -mindepth 1 -maxdepth 1 ! -type l -print0 | \ |
88 |
> - ${XARGS} -0 chmod -fR a+rX,u+w,g-w,o-w |
89 |
> + ${XARGS} -0 "${PORTAGE_BIN_PATH}/chmod-lite" |
90 |
> } |
91 |
> |
92 |
> econf() { |
93 |
> diff --git a/pym/portage/data.py b/pym/portage/data.py |
94 |
> index 2fd287d..2c99548 100644 |
95 |
> --- a/pym/portage/data.py |
96 |
> +++ b/pym/portage/data.py |
97 |
> @@ -139,7 +139,7 @@ def _get_global(k): |
98 |
> v = 2 |
99 |
> elif unprivileged: |
100 |
> v = 2 |
101 |
> - elif portage_gid in os.getgroups(): |
102 |
> + elif _get_global('portage_gid') in os.getgroups(): |
103 |
> v = 1 |
104 |
> |
105 |
> elif k in ('portage_gid', 'portage_uid'): |
106 |
> diff --git a/pym/portage/util/__init__.py |
107 |
> b/pym/portage/util/__init__.py index c0b509b..2b7ff8d 100644 |
108 |
> --- a/pym/portage/util/__init__.py |
109 |
> +++ b/pym/portage/util/__init__.py |
110 |
> @@ -17,9 +17,9 @@ from copy import deepcopy |
111 |
> import errno |
112 |
> import io |
113 |
> try: |
114 |
> - from itertools import filterfalse |
115 |
> + from itertools import chain, filterfalse |
116 |
> except ImportError: |
117 |
> - from itertools import ifilterfalse as filterfalse |
118 |
> + from itertools import chain, ifilterfalse as filterfalse |
119 |
> import logging |
120 |
> import re |
121 |
> import shlex |
122 |
> @@ -1041,6 +1041,23 @@ def unique_everseen(iterable, key=None): |
123 |
> seen_add(k) |
124 |
> yield element |
125 |
> |
126 |
> +def _do_stat(filename, follow_links=True): |
127 |
> + try: |
128 |
> + if follow_links: |
129 |
> + return os.stat(filename) |
130 |
> + else: |
131 |
> + return os.lstat(filename) |
132 |
> + except OSError as oe: |
133 |
> + func_call = "stat('%s')" % filename |
134 |
> + if oe.errno == errno.EPERM: |
135 |
> + raise OperationNotPermitted(func_call) |
136 |
> + elif oe.errno == errno.EACCES: |
137 |
> + raise PermissionDenied(func_call) |
138 |
> + elif oe.errno == errno.ENOENT: |
139 |
> + raise FileNotFound(filename) |
140 |
> + else: |
141 |
> + raise |
142 |
> + |
143 |
> def apply_permissions(filename, uid=-1, gid=-1, mode=-1, mask=-1, |
144 |
> stat_cached=None, follow_links=True): |
145 |
> """Apply user, group, and mode bits to a file if the |
146 |
> existing bits do not @@ -1058,21 +1075,7 @@ def |
147 |
> apply_permissions(filename, uid=-1, gid=-1, mode=-1, mask=-1, gid = |
148 |
> int(gid) |
149 |
> if stat_cached is None: |
150 |
> - try: |
151 |
> - if follow_links: |
152 |
> - stat_cached = os.stat(filename) |
153 |
> - else: |
154 |
> - stat_cached = os.lstat(filename) |
155 |
> - except OSError as oe: |
156 |
> - func_call = "stat('%s')" % filename |
157 |
> - if oe.errno == errno.EPERM: |
158 |
> - raise |
159 |
> OperationNotPermitted(func_call) |
160 |
> - elif oe.errno == errno.EACCES: |
161 |
> - raise PermissionDenied(func_call) |
162 |
> - elif oe.errno == errno.ENOENT: |
163 |
> - raise FileNotFound(filename) |
164 |
> - else: |
165 |
> - raise |
166 |
> + stat_cached = _do_stat(filename, |
167 |
> follow_links=follow_links) |
168 |
> if (uid != -1 and uid != stat_cached.st_uid) or \ |
169 |
> (gid != -1 and gid != stat_cached.st_gid): |
170 |
> @@ -1177,22 +1180,40 @@ def apply_recursive_permissions(top, uid=-1, |
171 |
> gid=-1, else: |
172 |
> raise |
173 |
> |
174 |
> + # For bug 554084, always apply permissions to a directory |
175 |
> before |
176 |
> + # that directory is traversed. |
177 |
> all_applied = True |
178 |
> - for dirpath, dirnames, filenames in os.walk(top): |
179 |
> - try: |
180 |
> - applied = apply_secpass_permissions(dirpath, |
181 |
> - uid=uid, gid=gid, mode=dirmode, |
182 |
> mask=dirmask, |
183 |
> - follow_links=follow_links) |
184 |
> - if not applied: |
185 |
> - all_applied = False |
186 |
> - except PortageException as e: |
187 |
> + |
188 |
> + try: |
189 |
> + stat_cached = _do_stat(top, |
190 |
> follow_links=follow_links) |
191 |
> + except FileNotFound: |
192 |
> + # backward compatibility |
193 |
> + return True |
194 |
> + |
195 |
> + if stat.S_ISDIR(stat_cached.st_mode): |
196 |
> + mode = dirmode |
197 |
> + mask = dirmask |
198 |
> + else: |
199 |
> + mode = filemode |
200 |
> + mask = filemask |
201 |
> + |
202 |
> + try: |
203 |
> + applied = apply_secpass_permissions(top, |
204 |
> + uid=uid, gid=gid, mode=mode, mask=mask, |
205 |
> + stat_cached=stat_cached, |
206 |
> follow_links=follow_links) |
207 |
> + if not applied: |
208 |
> all_applied = False |
209 |
> - onerror(e) |
210 |
> + except PortageException as e: |
211 |
> + all_applied = False |
212 |
> + onerror(e) |
213 |
> |
214 |
> - for name in filenames: |
215 |
> + for dirpath, dirnames, filenames in os.walk(top): |
216 |
> + for name, mode, mask in chain( |
217 |
> + ((x, filemode, filemask) for x in filenames), |
218 |
> + ((x, dirmode, dirmask) for x in dirnames)): |
219 |
> try: |
220 |
> applied = |
221 |
> apply_secpass_permissions(os.path.join(dirpath, name), |
222 |
> - uid=uid, gid=gid, |
223 |
> mode=filemode, mask=filemask, |
224 |
> + uid=uid, gid=gid, mode=mode, |
225 |
> mask=mask, follow_links=follow_links) |
226 |
> if not applied: |
227 |
> all_applied = False |
228 |
> @@ -1216,21 +1237,7 @@ def apply_secpass_permissions(filename, |
229 |
> uid=-1, gid=-1, mode=-1, mask=-1, unapplied.""" |
230 |
> |
231 |
> if stat_cached is None: |
232 |
> - try: |
233 |
> - if follow_links: |
234 |
> - stat_cached = os.stat(filename) |
235 |
> - else: |
236 |
> - stat_cached = os.lstat(filename) |
237 |
> - except OSError as oe: |
238 |
> - func_call = "stat('%s')" % filename |
239 |
> - if oe.errno == errno.EPERM: |
240 |
> - raise |
241 |
> OperationNotPermitted(func_call) |
242 |
> - elif oe.errno == errno.EACCES: |
243 |
> - raise PermissionDenied(func_call) |
244 |
> - elif oe.errno == errno.ENOENT: |
245 |
> - raise FileNotFound(filename) |
246 |
> - else: |
247 |
> - raise |
248 |
> + stat_cached = _do_stat(filename, |
249 |
> follow_links=follow_links) |
250 |
> all_applied = True |
251 |
> |
252 |
|
253 |
LGTM |
254 |
|
255 |
-- |
256 |
Brian Dolbec <dolsen> |