aboutsummaryrefslogtreecommitdiffstats
path: root/setuptools/sandbox.py
diff options
context:
space:
mode:
Diffstat (limited to 'setuptools/sandbox.py')
-rwxr-xr-xsetuptools/sandbox.py71
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):