Implement #7566 - os.path.sameopenfile for Windows.
This uses the GetFileInformationByHandle function to return a tuple of values to identify a file, then ntpath.sameopenfile compares file tuples, which is exposed as os.path.sameopenfile.
This commit is contained in:
parent
5c997b8d90
commit
6285774f06
|
@ -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.
|
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)
|
.. function:: samestat(stat1, stat2)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import sys
|
||||||
import stat
|
import stat
|
||||||
import genericpath
|
import genericpath
|
||||||
from genericpath import *
|
from genericpath import *
|
||||||
|
from nt import _getfileinformation
|
||||||
|
|
||||||
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
|
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
|
||||||
"basename","dirname","commonprefix","getsize","getmtime",
|
"basename","dirname","commonprefix","getsize","getmtime",
|
||||||
|
@ -17,7 +18,7 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
|
||||||
"ismount", "expanduser","expandvars","normpath","abspath",
|
"ismount", "expanduser","expandvars","normpath","abspath",
|
||||||
"splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
|
"splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
|
||||||
"extsep","devnull","realpath","supports_unicode_filenames","relpath",
|
"extsep","devnull","realpath","supports_unicode_filenames","relpath",
|
||||||
"samefile",]
|
"samefile", "sameopenfile",]
|
||||||
|
|
||||||
# strings representing various path-related bits and pieces
|
# strings representing various path-related bits and pieces
|
||||||
# These are primarily for export; internally, they are hardcoded.
|
# 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
|
# Also, on other operating systems, fake this method with a
|
||||||
# Windows-XP approximation.
|
# Windows-XP approximation.
|
||||||
return abspath(f1) == abspath(f2)
|
return abspath(f1) == abspath(f2)
|
||||||
|
|
||||||
|
def sameopenfile(f1, f2):
|
||||||
|
"""Test whether two file objects reference the same file"""
|
||||||
|
return _getfileinformation(f1) == _getfileinformation(f2)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import ntpath
|
||||||
import os
|
import os
|
||||||
from test.support import TestFailed
|
from test.support import TestFailed
|
||||||
from test import support, test_genericpath
|
from test import support, test_genericpath
|
||||||
|
from tempfile import TemporaryFile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
@ -237,6 +238,18 @@ class TestNtpath(unittest.TestCase):
|
||||||
tester('ntpath.relpath("/a", "/a")', '.')
|
tester('ntpath.relpath("/a", "/a")', '.')
|
||||||
tester('ntpath.relpath("/a/b", "/a/b")', '.')
|
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):
|
class NtCommonTest(test_genericpath.CommonTest):
|
||||||
pathmodule = ntpath
|
pathmodule = ntpath
|
||||||
|
|
|
@ -13,6 +13,8 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #7566: Implement os.path.sameopenfile for Windows.
|
||||||
|
|
||||||
- Issue #9293: I/O streams now raise ``io.UnsupportedOperation`` when an
|
- Issue #9293: I/O streams now raise ``io.UnsupportedOperation`` when an
|
||||||
unsupported operation is attempted (for example, writing to a file open
|
unsupported operation is attempted (for example, writing to a file open
|
||||||
only for reading).
|
only for reading).
|
||||||
|
|
|
@ -2758,6 +2758,33 @@ posix__getfinalpathname(PyObject *self, PyObject *args)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
} /* end of posix__getfinalpathname */
|
} /* 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 */
|
#endif /* MS_WINDOWS */
|
||||||
|
|
||||||
PyDoc_STRVAR(posix_mkdir__doc__,
|
PyDoc_STRVAR(posix_mkdir__doc__,
|
||||||
|
@ -7908,6 +7935,7 @@ static PyMethodDef posix_methods[] = {
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
{"_getfullpathname", posix__getfullpathname, METH_VARARGS, NULL},
|
{"_getfullpathname", posix__getfullpathname, METH_VARARGS, NULL},
|
||||||
{"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL},
|
{"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL},
|
||||||
|
{"_getfileinformation", posix__getfileinformation, METH_VARARGS, NULL},
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_GETLOADAVG
|
#ifdef HAVE_GETLOADAVG
|
||||||
{"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__},
|
{"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__},
|
||||||
|
|
Loading…
Reference in New Issue