summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/os.path.rst4
-rw-r--r--Lib/ntpath.py7
-rw-r--r--Lib/test/test_ntpath.py13
-rw-r--r--Misc/NEWS2
-rw-r--r--Modules/posixmodule.c28
5 files changed, 52 insertions, 2 deletions
diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst
index 317f55a..7aac5c4 100644
--- a/Doc/library/os.path.rst
+++ b/Doc/library/os.path.rst
@@ -251,7 +251,9 @@ applications should use string objects to access all files.
Return ``True`` if the file descriptors *fp1* and *fp2* refer to the same file.
- Availability: Unix.
+ Availability: Unix, Windows.
+
+ .. versionchanged:: 3.2 Added Windows support.
.. function:: samestat(stat1, stat2)
diff --git a/Lib/ntpath.py b/Lib/ntpath.py
index ee7ac67..eae3cf3 100644
--- a/Lib/ntpath.py
+++ b/Lib/ntpath.py
@@ -10,6 +10,7 @@ import sys
import stat
import genericpath
from genericpath import *
+from nt import _getfileinformation
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
"basename","dirname","commonprefix","getsize","getmtime",
@@ -17,7 +18,7 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
"ismount", "expanduser","expandvars","normpath","abspath",
"splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
"extsep","devnull","realpath","supports_unicode_filenames","relpath",
- "samefile",]
+ "samefile", "sameopenfile",]
# strings representing various path-related bits and pieces
# These are primarily for export; internally, they are hardcoded.
@@ -652,3 +653,7 @@ def samefile(f1, f2):
# Also, on other operating systems, fake this method with a
# Windows-XP approximation.
return abspath(f1) == abspath(f2)
+
+def sameopenfile(f1, f2):
+ """Test whether two file objects reference the same file"""
+ return _getfileinformation(f1) == _getfileinformation(f2)
diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py
index 86e3eda..9f39aba 100644
--- a/Lib/test/test_ntpath.py
+++ b/Lib/test/test_ntpath.py
@@ -2,6 +2,7 @@ import ntpath
import os
from test.support import TestFailed
from test import support, test_genericpath
+from tempfile import TemporaryFile
import unittest
@@ -237,6 +238,18 @@ class TestNtpath(unittest.TestCase):
tester('ntpath.relpath("/a", "/a")', '.')
tester('ntpath.relpath("/a/b", "/a/b")', '.')
+ def test_sameopenfile(self):
+ with TemporaryFile() as tf1, TemporaryFile() as tf2:
+ # Make sure the same file is really the same
+ self.assertTrue(ntpath.sameopenfile(tf1.fileno(), tf1.fileno()))
+ # Make sure different files are really different
+ self.assertFalse(ntpath.sameopenfile(tf1.fileno(), tf2.fileno()))
+ # Make sure invalid values don't cause issues
+ with self.assertRaises(ValueError):
+ # Invalid file descriptors shouldn't display assert
+ # dialogs (#4804)
+ ntpath.sameopenfile(-1, -1)
+
class NtCommonTest(test_genericpath.CommonTest):
pathmodule = ntpath
diff --git a/Misc/NEWS b/Misc/NEWS
index 732c145..1ac1dec 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,8 @@ Core and Builtins
Library
-------
+- Issue #7566: Implement os.path.sameopenfile for Windows.
+
- Issue #9293: I/O streams now raise ``io.UnsupportedOperation`` when an
unsupported operation is attempted (for example, writing to a file open
only for reading).
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index dda758f..a83a06b 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -2758,6 +2758,33 @@ posix__getfinalpathname(PyObject *self, PyObject *args)
return result;
} /* end of posix__getfinalpathname */
+
+static PyObject *
+posix__getfileinformation(PyObject *self, PyObject *args)
+{
+ HANDLE hFile;
+ BY_HANDLE_FILE_INFORMATION info;
+ int fd;
+
+ if (!PyArg_ParseTuple(args, "i:_getfileinformation", &fd))
+ return NULL;
+
+ if (!_PyVerify_fd(fd)) {
+ PyErr_SetString(PyExc_ValueError, "received invalid file descriptor");
+ return NULL;
+ }
+
+ hFile = (HANDLE)_get_osfhandle(fd);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return win32_error("_getfileinformation", NULL);
+
+ if (!GetFileInformationByHandle(hFile, &info))
+ return win32_error("_getfileinformation", NULL);
+
+ return Py_BuildValue("iii", info.dwVolumeSerialNumber,
+ info.nFileIndexHigh,
+ info.nFileIndexLow);
+}
#endif /* MS_WINDOWS */
PyDoc_STRVAR(posix_mkdir__doc__,
@@ -7908,6 +7935,7 @@ static PyMethodDef posix_methods[] = {
#ifdef MS_WINDOWS
{"_getfullpathname", posix__getfullpathname, METH_VARARGS, NULL},
{"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL},
+ {"_getfileinformation", posix__getfileinformation, METH_VARARGS, NULL},
#endif
#ifdef HAVE_GETLOADAVG
{"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__},