diff options
Diffstat (limited to 'setuptools/sandbox.py')
-rwxr-xr-x | setuptools/sandbox.py | 71 |
1 files changed, 53 insertions, 18 deletions
diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py index 4c5e7129..e026ff13 100755 --- a/setuptools/sandbox.py +++ b/setuptools/sandbox.py @@ -1,8 +1,13 @@ import os, sys, __builtin__, tempfile, operator, pkg_resources -_os = sys.modules[os.name] +if os.name == "java": + import org.python.modules.posix.PosixModule as _os +else: + _os = sys.modules[os.name] +try: + _file = file +except NameError: + _file = None _open = open -_file = file - from distutils.errors import DistutilsError from pkg_resources import working_set @@ -38,7 +43,6 @@ __all__ = [ - def run_setup(setup_script, args): """Run a distutils setup script, sandboxed in its directory""" old_dir = os.getcwd() @@ -51,7 +55,8 @@ def run_setup(setup_script, args): save_modules = sys.modules.copy() pr_state = pkg_resources.__getstate__() try: - tempfile.tempdir = temp_dir; os.chdir(setup_dir) + tempfile.tempdir = temp_dir + os.chdir(setup_dir) try: sys.argv[:] = [setup_script]+list(args) sys.path.insert(0, setup_dir) @@ -71,8 +76,14 @@ def run_setup(setup_script, args): finally: pkg_resources.__setstate__(pr_state) sys.modules.update(save_modules) - for key in list(sys.modules): - if key not in save_modules: del sys.modules[key] + # remove any modules imported within the sandbox + del_modules = [ + mod_name for mod_name in sys.modules + if mod_name not in save_modules + # exclude any encodings modules. See #285 + and not mod_name.startswith('encodings.') + ] + map(sys.modules.__delitem__, del_modules) os.chdir(old_dir) sys.path[:] = save_path sys.argv[:] = save_argv @@ -99,14 +110,16 @@ class AbstractSandbox: """Run 'func' under os sandboxing""" try: self._copy(self) - __builtin__.file = self._file + if _file: + __builtin__.file = self._file __builtin__.open = self._open self._active = True return func() finally: self._active = False + if _file: + __builtin__.file = _file __builtin__.open = _open - __builtin__.file = _file self._copy(_os) def _mk_dual_path_wrapper(name): @@ -129,8 +142,9 @@ class AbstractSandbox: return original(path,*args,**kw) return wrap + if _file: + _file = _mk_single_path_wrapper('file', _file) _open = _mk_single_path_wrapper('open', _open) - _file = _mk_single_path_wrapper('file', _file) for name in [ "stat", "listdir", "chdir", "open", "chmod", "chown", "mkdir", "remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat", @@ -182,6 +196,19 @@ class AbstractSandbox: ) +if hasattr(os, 'devnull'): + _EXCEPTIONS = [os.devnull,] +else: + _EXCEPTIONS = [] + +try: + from win32com.client.gencache import GetGeneratePath + _EXCEPTIONS.append(GetGeneratePath()) + del GetGeneratePath +except ImportError: + # it appears pywin32 is not installed, so no need to exclude. + pass + class DirectorySandbox(AbstractSandbox): """Restrict operations to a single subdirectory - pseudo-chroot""" @@ -190,20 +217,28 @@ class DirectorySandbox(AbstractSandbox): "utime", "lchown", "chroot", "mkfifo", "mknod", "tempnam", ]) - def __init__(self,sandbox): + def __init__(self, sandbox, exceptions=_EXCEPTIONS): self._sandbox = os.path.normcase(os.path.realpath(sandbox)) self._prefix = os.path.join(self._sandbox,'') + self._exceptions = [os.path.normcase(os.path.realpath(path)) for path in exceptions] AbstractSandbox.__init__(self) def _violation(self, operation, *args, **kw): raise SandboxViolation(operation, args, kw) + if _file: + def _file(self, path, mode='r', *args, **kw): + if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): + self._violation("file", path, mode, *args, **kw) + return _file(path,mode,*args,**kw) + def _open(self, path, mode='r', *args, **kw): if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): self._violation("open", path, mode, *args, **kw) return _open(path,mode,*args,**kw) - def tmpnam(self): self._violation("tmpnam") + def tmpnam(self): + self._violation("tmpnam") def _ok(self,path): if hasattr(_os,'devnull') and path==_os.devnull: return True @@ -211,11 +246,16 @@ class DirectorySandbox(AbstractSandbox): try: self._active = False realpath = os.path.normcase(os.path.realpath(path)) - if realpath==self._sandbox or realpath.startswith(self._prefix): + if (self._exempted(realpath) or realpath == self._sandbox + or realpath.startswith(self._prefix)): return True finally: self._active = active + def _exempted(self, filepath): + exception_matches = map(filepath.startswith, self._exceptions) + return True in exception_matches + def _remap_input(self,operation,path,*args,**kw): """Called for path inputs""" if operation in self.write_ops and not self._ok(path): @@ -228,11 +268,6 @@ class DirectorySandbox(AbstractSandbox): self._violation(operation, src, dst, *args, **kw) return (src,dst) - def _file(self, path, mode='r', *args, **kw): - if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): - self._violation("file", path, mode, *args, **kw) - return _file(path,mode,*args,**kw) - def open(self, file, flags, mode=0777): """Called for low-level os.open()""" if flags & WRITE_FLAGS and not self._ok(file): |