diff options
Diffstat (limited to 'setuptools/sandbox.py')
| -rwxr-xr-x | setuptools/sandbox.py | 67 |
1 files changed, 57 insertions, 10 deletions
diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py index 4db0dbdb..1583b81f 100755 --- a/setuptools/sandbox.py +++ b/setuptools/sandbox.py @@ -1,14 +1,19 @@ -import os, sys, __builtin__, tempfile, operator -_os = sys.modules[os.name] +import os, sys, __builtin__, tempfile, operator, pkg_resources +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 from distutils.errors import DistutilsError __all__ = [ "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup", ] - def run_setup(setup_script, args): """Run a distutils setup script, sandboxed in its directory""" - old_dir = os.getcwd() save_argv = sys.argv[:] save_path = sys.path[:] @@ -16,7 +21,8 @@ def run_setup(setup_script, args): temp_dir = os.path.join(setup_dir,'temp') if not os.path.isdir(temp_dir): os.makedirs(temp_dir) save_tmp = tempfile.tempdir - + save_modules = sys.modules.copy() + pr_state = pkg_resources.__getstate__() try: tempfile.tempdir = temp_dir os.chdir(setup_dir) @@ -34,6 +40,16 @@ def run_setup(setup_script, args): raise # Normal exit, just return finally: + pkg_resources.__setstate__(pr_state) + sys.modules.update(save_modules) + # 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 @@ -58,12 +74,16 @@ class AbstractSandbox: """Run 'func' under os sandboxing""" try: self._copy(self) - __builtin__.open = __builtin__.file = self._open + if _file: + __builtin__.file = self._file + __builtin__.open = self._open self._active = True return func() finally: self._active = False - __builtin__.open = __builtin__.file = _open + if _file: + __builtin__.file = _file + __builtin__.open = _open self._copy(_os) @@ -88,7 +108,9 @@ class AbstractSandbox: return original(path,*args,**kw) return wrap - _open = _mk_single_path_wrapper('file', _open) + if _file: + _file = _mk_single_path_wrapper('file', _file) + _open = _mk_single_path_wrapper('open', _open) for name in [ "stat", "listdir", "chdir", "open", "chmod", "chown", "mkdir", "remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat", @@ -141,6 +163,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""" @@ -149,14 +184,21 @@ 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) @@ -170,11 +212,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): |
