Gentoo Archives: gentoo-portage-dev

From: Brian Dolbec <dolsen@g.o>
To: gentoo-portage-dev@l.g.o
Subject: Re: [gentoo-portage-dev] [PATCH v4] unpack: use chmod-lite helper for bug 554084
Date: Sat, 03 Oct 2015 16:25:55
Message-Id: 20151003092455.54a9500a.dolsen@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH v4] unpack: use chmod-lite helper for bug 554084 by Zac Medico
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>