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.
|
||||
|
||||
Availability: Unix.
|
||||
Availability: Unix, Windows.
|
||||
|
||||
.. versionchanged:: 3.2 Added Windows support.
|
||||
|
||||
|
||||
.. function:: samestat(stat1, stat2)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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__},
|
||||
|
|
Loading…
Reference in New Issue