Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6285774

Browse files
committed
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.
1 parent 5c997b8 commit 6285774

5 files changed

Lines changed: 52 additions & 2 deletions

File tree

Doc/library/os.path.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,9 @@ applications should use string objects to access all files.
251251

252252
Return ``True`` if the file descriptors *fp1* and *fp2* refer to the same file.
253253

254-
Availability: Unix.
254+
Availability: Unix, Windows.
255+
256+
.. versionchanged:: 3.2 Added Windows support.
255257

256258

257259
.. function:: samestat(stat1, stat2)

Lib/ntpath.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
import stat
1111
import genericpath
1212
from genericpath import *
13+
from nt import _getfileinformation
1314

1415
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
1516
"basename","dirname","commonprefix","getsize","getmtime",
1617
"getatime","getctime", "islink","exists","lexists","isdir","isfile",
1718
"ismount", "expanduser","expandvars","normpath","abspath",
1819
"splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
1920
"extsep","devnull","realpath","supports_unicode_filenames","relpath",
20-
"samefile",]
21+
"samefile", "sameopenfile",]
2122

2223
# strings representing various path-related bits and pieces
2324
# These are primarily for export; internally, they are hardcoded.
@@ -652,3 +653,7 @@ def samefile(f1, f2):
652653
# Also, on other operating systems, fake this method with a
653654
# Windows-XP approximation.
654655
return abspath(f1) == abspath(f2)
656+
657+
def sameopenfile(f1, f2):
658+
"""Test whether two file objects reference the same file"""
659+
return _getfileinformation(f1) == _getfileinformation(f2)

Lib/test/test_ntpath.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
from test.support import TestFailed
44
from test import support, test_genericpath
5+
from tempfile import TemporaryFile
56
import unittest
67

78

@@ -237,6 +238,18 @@ def test_relpath(self):
237238
tester('ntpath.relpath("/a", "/a")', '.')
238239
tester('ntpath.relpath("/a/b", "/a/b")', '.')
239240

241+
def test_sameopenfile(self):
242+
with TemporaryFile() as tf1, TemporaryFile() as tf2:
243+
# Make sure the same file is really the same
244+
self.assertTrue(ntpath.sameopenfile(tf1.fileno(), tf1.fileno()))
245+
# Make sure different files are really different
246+
self.assertFalse(ntpath.sameopenfile(tf1.fileno(), tf2.fileno()))
247+
# Make sure invalid values don't cause issues
248+
with self.assertRaises(ValueError):
249+
# Invalid file descriptors shouldn't display assert
250+
# dialogs (#4804)
251+
ntpath.sameopenfile(-1, -1)
252+
240253

241254
class NtCommonTest(test_genericpath.CommonTest):
242255
pathmodule = ntpath

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Core and Builtins
1313
Library
1414
-------
1515

16+
- Issue #7566: Implement os.path.sameopenfile for Windows.
17+
1618
- Issue #9293: I/O streams now raise ``io.UnsupportedOperation`` when an
1719
unsupported operation is attempted (for example, writing to a file open
1820
only for reading).

Modules/posixmodule.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2758,6 +2758,33 @@ posix__getfinalpathname(PyObject *self, PyObject *args)
27582758
return result;
27592759

27602760
} /* end of posix__getfinalpathname */
2761+
2762+
static PyObject *
2763+
posix__getfileinformation(PyObject *self, PyObject *args)
2764+
{
2765+
HANDLE hFile;
2766+
BY_HANDLE_FILE_INFORMATION info;
2767+
int fd;
2768+
2769+
if (!PyArg_ParseTuple(args, "i:_getfileinformation", &fd))
2770+
return NULL;
2771+
2772+
if (!_PyVerify_fd(fd)) {
2773+
PyErr_SetString(PyExc_ValueError, "received invalid file descriptor");
2774+
return NULL;
2775+
}
2776+
2777+
hFile = (HANDLE)_get_osfhandle(fd);
2778+
if (hFile == INVALID_HANDLE_VALUE)
2779+
return win32_error("_getfileinformation", NULL);
2780+
2781+
if (!GetFileInformationByHandle(hFile, &info))
2782+
return win32_error("_getfileinformation", NULL);
2783+
2784+
return Py_BuildValue("iii", info.dwVolumeSerialNumber,
2785+
info.nFileIndexHigh,
2786+
info.nFileIndexLow);
2787+
}
27612788
#endif /* MS_WINDOWS */
27622789

27632790
PyDoc_STRVAR(posix_mkdir__doc__,
@@ -7908,6 +7935,7 @@ static PyMethodDef posix_methods[] = {
79087935
#ifdef MS_WINDOWS
79097936
{"_getfullpathname", posix__getfullpathname, METH_VARARGS, NULL},
79107937
{"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL},
7938+
{"_getfileinformation", posix__getfileinformation, METH_VARARGS, NULL},
79117939
#endif
79127940
#ifdef HAVE_GETLOADAVG
79137941
{"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__},

0 commit comments

Comments
 (0)