[pypy-commit] pypy nedbat-sandbox: A correct implementation of os.fstat, with a test.

ned noreply at buildbot.pypy.org
Sun Dec 4 22:06:01 CET 2011


Author: Ned Batchelder <ned at nedbatchelder.com>
Branch: nedbat-sandbox
Changeset: r50156:e4704f598176
Date: 2011-12-04 16:05 -0500
http://bitbucket.org/pypy/pypy/changeset/e4704f598176/

Log:	A correct implementation of os.fstat, with a test.

diff --git a/pypy/translator/sandbox/sandlib.py b/pypy/translator/sandbox/sandlib.py
--- a/pypy/translator/sandbox/sandlib.py
+++ b/pypy/translator/sandbox/sandlib.py
@@ -409,7 +409,7 @@
     def __init__(self, *args, **kwds):
         super(VirtualizedSandboxedProc, self).__init__(*args, **kwds)
         self.virtual_root = self.build_virtual_root()
-        self.open_fds = {}   # {virtual_fd: real_file_object}
+        self.open_fds = {}   # {virtual_fd: (real_file_object, node)}
 
     def build_virtual_root(self):
         raise NotImplementedError("must be overridden")
@@ -451,19 +451,32 @@
     def do_ll_os__ll_os_isatty(self, fd):
         return self.virtual_console_isatty and fd in (0, 1, 2)
 
-    def allocate_fd(self, f):
+    def allocate_fd(self, f, node=None):
         for fd in self.virtual_fd_range:
             if fd not in self.open_fds:
-                self.open_fds[fd] = f
+                self.open_fds[fd] = (f, node)
                 return fd
         else:
             raise OSError(errno.EMFILE, "trying to open too many files")
 
-    def get_file(self, fd):
+    def get_fd(self, fd, throw=True):
+        """Get the objects implementing file descriptor `fd`.
+
+        Returns a pair, (open file, vfs node)
+
+        `throw`: if true, raise OSError for bad fd, else return (None, None).
+        """
         try:
-            return self.open_fds[fd]
+            f, node = self.open_fds[fd]
         except KeyError:
-            raise OSError(errno.EBADF, "bad file descriptor")
+            if throw:
+                raise OSError(errno.EBADF, "bad file descriptor")
+            return None, None
+        return f, node
+
+    def get_file(self, fd, throw=True):
+        """Return the open file for file descriptor `fd`."""
+        return self.get_fd(fd, throw)[0]
 
     def do_ll_os__ll_os_open(self, vpathname, flags, mode):
         node = self.get_node(vpathname)
@@ -471,7 +484,7 @@
             raise OSError(errno.EPERM, "write access denied")
         # all other flags are ignored
         f = node.open()
-        return self.allocate_fd(f)
+        return self.allocate_fd(f, node)
 
     def do_ll_os__ll_os_close(self, fd):
         f = self.get_file(fd)
@@ -479,9 +492,8 @@
         f.close()
 
     def do_ll_os__ll_os_read(self, fd, size):
-        try:
-            f = self.open_fds[fd]
-        except KeyError:
+        f = self.get_file(fd, throw=False)
+        if f is None:
             return super(VirtualizedSandboxedProc, self).do_ll_os__ll_os_read(
                 fd, size)
         else:
@@ -491,12 +503,8 @@
             return f.read(min(size, 256*1024))
 
     def do_ll_os__ll_os_fstat(self, fd):
-        try:
-            f = self.open_fds[fd]
-        except KeyError:
-            return super(VirtualizedSandboxedProc, self).do_ll_os__ll_os_fstat(fd)
-        else:
-            return os.stat(f.name)      # Isn't there a better way to do this?
+        f, node = self.get_fd(fd)
+        return node.stat()
     do_ll_os__ll_os_fstat.resulttype = s_StatResult
 
     def do_ll_os__ll_os_lseek(self, fd, pos, how):
@@ -539,13 +547,13 @@
 
     def do_ll_os__ll_os_read(self, fd, size):
         if fd in self.sockets:
-            return self.open_fds[fd].recv(size)
+            return self.get_file(fd).recv(size)
         return super(VirtualizedSocketProc, self).do_ll_os__ll_os_read(
             fd, size)
 
     def do_ll_os__ll_os_write(self, fd, data):
         if fd in self.sockets:
-            return self.open_fds[fd].send(data)
+            return self.get_file(fd).send(data)
         return super(VirtualizedSocketProc, self).do_ll_os__ll_os_write(
             fd, data)
 
diff --git a/pypy/translator/sandbox/test/test_sandlib.py b/pypy/translator/sandbox/test/test_sandlib.py
--- a/pypy/translator/sandbox/test/test_sandlib.py
+++ b/pypy/translator/sandbox/test/test_sandlib.py
@@ -167,3 +167,36 @@
     output, error = proc.communicate("")
     assert output == "All ok!\n"
     assert error == ""
+
+def test_fstat():
+    def compare(a, b, i):
+        if a != b:
+            print "stat and fstat differ @%d: %s != %s" % (i, a, b)
+
+    def entry_point(argv):
+        try:
+            # Open a file, and compare stat and fstat
+            fd = os.open('/hi.txt', os.O_RDONLY, 0777)
+            st = os.stat('/hi.txt')
+            fs = os.fstat(fd)
+            compare(st[0], fs[0], 0)
+            compare(st[1], fs[1], 1)
+            compare(st[2], fs[2], 2)
+            compare(st[3], fs[3], 3)
+            compare(st[4], fs[4], 4)
+            compare(st[5], fs[5], 5)
+            compare(st[6], fs[6], 6)
+            compare(st[7], fs[7], 7)
+            compare(st[8], fs[8], 8)
+            compare(st[9], fs[9], 9)
+        except OSError, e:
+            print "OSError: %s" % (e.errno,)
+        print "All ok!"
+        return 0
+    exe = compile(entry_point)
+
+    proc = SandboxedProcWithFiles([exe])
+    output, error = proc.communicate("")
+    assert output == "All ok!\n"
+    assert error == ""
+


More information about the pypy-commit mailing list