[Jython-checkins] jython: Ensure os.fstat() returns a valid st_mode on Windows. Addresses #2320.

jeff.allen jython-checkins at python.org
Tue Nov 10 14:07:25 EST 2015


https://hg.python.org/jython/rev/0381d60ca611
changeset:   7798:0381d60ca611
user:        Jeff Allen <ja.py at farowl.co.uk>
date:        Tue Nov 10 07:27:49 2015 +0000
summary:
  Ensure os.fstat() returns a valid st_mode on Windows. Addresses #2320.

Compensate for (probable) bug in jnr-posix whereby fstat st_mode is
always zero. We provide a custom stat-object able to synthesize a mode
from DOS-ish file attributes. Also we suppress os.closerange on Windows
until real integer file descriptors are available.

files:
  Lib/test/regrtest.py                          |   1 -
  src/org/python/modules/posix/PosixModule.java |  66 ++++++++-
  2 files changed, 59 insertions(+), 8 deletions(-)


diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -1358,7 +1358,6 @@
 
     'java.nt':     # Expected to fail on Windows
         """
-        test_fileinput         # issue 2320 (because fstat().st_mode is zero)
         test_mailbox           # fails miserably and ruins other tests
         test_os_jy             # Locale tests run and fail on Cygwin
         test_popen             # http://bugs.python.org/issue1559298
diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java
--- a/src/org/python/modules/posix/PosixModule.java
+++ b/src/org/python/modules/posix/PosixModule.java
@@ -15,8 +15,8 @@
 import java.nio.file.FileAlreadyExistsException;
 import java.nio.file.Files;
 import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.NotLinkException;
-import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.attribute.BasicFileAttributeView;
@@ -34,9 +34,11 @@
 import jnr.posix.FileStat;
 import jnr.posix.POSIX;
 import jnr.posix.POSIXFactory;
+import jnr.posix.POSIXHandler;
 import jnr.posix.Times;
+import jnr.posix.WindowsRawFileStat;
 import jnr.posix.util.FieldAccess;
-import jnr.posix.util.Platform;
+import jnr.posix.windows.CommonFileInformation;
 
 import org.python.core.BufferProtocol;
 import org.python.core.ClassDictInit;
@@ -53,8 +55,8 @@
 import org.python.core.PyString;
 import org.python.core.PySystemState;
 import org.python.core.PyTuple;
+import org.python.core.Untraversable;
 import org.python.core.imp;
-import org.python.core.Untraversable;
 import org.python.core.io.FileIO;
 import org.python.core.io.IOBase;
 import org.python.core.io.RawIOBase;
@@ -75,7 +77,8 @@
     private static final OS os = OS.getOS();
 
     /** Platform specific POSIX services. */
-    private static final POSIX posix = POSIXFactory.getPOSIX(new PythonPOSIXHandler(), true);
+    private static final POSIXHandler posixHandler = new PythonPOSIXHandler();
+    private static final POSIX posix = POSIXFactory.getPOSIX(posixHandler, true);
 
     /** os.open flags. */
     private static final int O_RDONLY = 0x0;
@@ -354,6 +357,7 @@
         }
     }
 
+    @Hide(OS.NT)
     public static void closerange(PyObject fd_lowObj, PyObject fd_highObj) {
         int fd_low = getFD(fd_lowObj).getIntFD(false);
         int fd_high = getFD(fd_highObj).getIntFD(false);
@@ -1365,10 +1369,18 @@
             try {
                 FDUnion fd = getFD(fdObj);
                 FileStat stat;
-                if (fd.isIntFD()) {
-                    stat = posix.fstat(fd.intFD);
+                if (os != OS.NT) {
+                    if (fd.isIntFD()) {
+                        stat = posix.fstat(fd.intFD);
+                    } else {
+                        stat = posix.fstat(fd.javaFD);
+                    }
                 } else {
-                    stat = posix.fstat(fd.javaFD);
+                    // FIXME: jnr-posix fstat work-around. See issue #2320.
+                    stat = new WindowsRawFileStat2(posix, posixHandler);
+                    if (posix.fstat(fd.javaFD, stat) < 0) {
+                        throw Py.OSError(Errno.EBADF);
+                    }
                 }
                 return PyStatResult.fromFileStat(stat);
             } catch (PyException ex) {
@@ -1376,4 +1388,44 @@
             }
         }
     }
+
+    /*
+     * Extend the Windows stat object defined by jnr.posix, which in jnr-posix 2.0.4 is buggy to the
+     * extent that st_mode is always zero. Remarkably, it is possible to fix this by defining a
+     * cunning replacement.
+     */
+    private static class WindowsRawFileStat2 extends WindowsRawFileStat {
+
+        public WindowsRawFileStat2(POSIX posix, POSIXHandler handler) {
+            super(posix, handler);
+        }
+
+        private int mode; // Replaces st_mode
+
+        @Override
+        public void setup(CommonFileInformation fileInfo) {
+            super.setup(fileInfo);
+            // CommonFileInformation gives us (DOS-style) file attributes, not access rights.
+            int attr = fileInfo.getFileAttributes();
+            int mode = ALL_READ;
+            if ((attr & CommonFileInformation.FILE_ATTRIBUTE_READONLY) == 0) {
+                // Writable: assume by all
+                mode |= ALL_WRITE;
+            }
+            if ((attr & CommonFileInformation.FILE_ATTRIBUTE_DIRECTORY) != 0) {
+                // Directory: assume by all can look things up in it.
+                mode |= S_IFDIR | S_IXUGO;
+            } else {
+                // Regular file
+                mode |= S_IFREG;
+            }
+            this.mode = mode;
+        }
+
+        @Override
+        public int mode() {
+            return mode;
+        }
+    }
+
 }

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list