diff options
Diffstat (limited to 'meta/lib/oe/path.py')
-rw-r--r-- | meta/lib/oe/path.py | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/meta/lib/oe/path.py b/meta/lib/oe/path.py index ea58bedc8b..0b34cebdab 100644 --- a/meta/lib/oe/path.py +++ b/meta/lib/oe/path.py | |||
@@ -2,6 +2,7 @@ import errno | |||
2 | import glob | 2 | import glob |
3 | import shutil | 3 | import shutil |
4 | import subprocess | 4 | import subprocess |
5 | import os.path | ||
5 | 6 | ||
6 | def join(*paths): | 7 | def join(*paths): |
7 | """Like os.path.join but doesn't treat absolute RHS specially""" | 8 | """Like os.path.join but doesn't treat absolute RHS specially""" |
@@ -161,3 +162,89 @@ def find(dir, **walkoptions): | |||
161 | for root, dirs, files in os.walk(dir, **walkoptions): | 162 | for root, dirs, files in os.walk(dir, **walkoptions): |
162 | for file in files: | 163 | for file in files: |
163 | yield os.path.join(root, file) | 164 | yield os.path.join(root, file) |
165 | |||
166 | |||
167 | ## realpath() related functions | ||
168 | def __is_path_below(file, root): | ||
169 | return (file + os.path.sep).startswith(root) | ||
170 | |||
171 | def __realpath_rel(start, rel_path, root, loop_cnt): | ||
172 | """Calculates real path of symlink 'start' + 'rel_path' below | ||
173 | 'root'; no part of 'start' below 'root' must contain symlinks. """ | ||
174 | have_dir = True | ||
175 | |||
176 | for d in rel_path.split(os.path.sep): | ||
177 | if not have_dir: | ||
178 | raise OSError(errno.ENOENT, "no such directory %s" % start) | ||
179 | |||
180 | if d == os.path.pardir: # '..' | ||
181 | if len(start) >= len(root): | ||
182 | # do not follow '..' before root | ||
183 | start = os.path.dirname(start) | ||
184 | else: | ||
185 | # emit warning? | ||
186 | pass | ||
187 | else: | ||
188 | (start, have_dir) = __realpath(os.path.join(start, d), | ||
189 | root, loop_cnt) | ||
190 | |||
191 | assert(__is_path_below(start, root)) | ||
192 | |||
193 | return start | ||
194 | |||
195 | def __realpath(file, root, loop_cnt): | ||
196 | while os.path.islink(file) and len(file) >= len(root): | ||
197 | if loop_cnt == 0: | ||
198 | raise OSError(errno.ELOOP, file) | ||
199 | |||
200 | loop_cnt -= 1 | ||
201 | target = os.path.normpath(os.readlink(file)) | ||
202 | |||
203 | if not os.path.isabs(target): | ||
204 | tdir = os.path.dirname(file) | ||
205 | assert(__is_path_below(tdir, root)) | ||
206 | else: | ||
207 | tdir = root | ||
208 | |||
209 | file = __realpath_rel(tdir, target, root, loop_cnt) | ||
210 | |||
211 | try: | ||
212 | is_dir = os.path.isdir(file) | ||
213 | except: | ||
214 | is_dir = false | ||
215 | |||
216 | return (file, is_dir) | ||
217 | |||
218 | def realpath(file, root, use_physdir = True, loop_cnt = 100): | ||
219 | """ Returns the canonical path of 'file' with assuming a toplevel | ||
220 | 'root' directory. When 'use_physdir' is set, all preceding path | ||
221 | components of 'file' will be resolved first; this flag should be | ||
222 | set unless it is guaranteed that there is no symlink in the path.""" | ||
223 | |||
224 | root = os.path.normpath(root) | ||
225 | file = os.path.normpath(file) | ||
226 | |||
227 | if not root.endswith(os.path.sep): | ||
228 | # letting root end with '/' makes some things easier | ||
229 | root = root + os.path.sep | ||
230 | |||
231 | if not __is_path_below(file, root): | ||
232 | raise OSError(errno.EINVAL, "file '%s' is not below root" % file) | ||
233 | |||
234 | try: | ||
235 | if use_physdir: | ||
236 | file = __realpath_rel(root, file[(len(root) - 1):], root, loop_cnt) | ||
237 | else: | ||
238 | file = __realpath(file, root, loop_cnt)[0] | ||
239 | except OSError, e: | ||
240 | if e.errno == errno.ELOOP: | ||
241 | # make ELOOP more readable; without catching it, there will | ||
242 | # be printed a backtrace with 100s of OSError exceptions | ||
243 | # else | ||
244 | raise OSError(errno.ELOOP, | ||
245 | "too much recursions while resolving '%s'; loop in '%s'" % | ||
246 | (file, e.strerror)) | ||
247 | |||
248 | raise | ||
249 | |||
250 | return file | ||