Visitar URL original
gh-99726: Improves correctness of stat results for Windows, and uses faster API when available by zooba · Pull Request #102149 · python/cpython · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
gh-99726: Improves correctness of stat results for Windows, and uses …
…faster API when available
  • Loading branch information
zooba committed Feb 22, 2023
commit 5187810c2a24e6b12c612e5cd8bdd2018fab7d0a
39 changes: 28 additions & 11 deletions Doc/library/os.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2790,6 +2790,10 @@ features:
Added support for the :class:`~os.PathLike` interface. Added support
for :class:`bytes` paths on Windows.

.. versionchanged:: 3.12
The ``st_ctime`` attributes of a stat result are now set to zero, rather
than being incorrectly set to the creation time of the file.


.. function:: stat(path, *, dir_fd=None, follow_symlinks=True)

Expand Down Expand Up @@ -2905,10 +2909,7 @@ features:

.. attribute:: st_ctime

Platform dependent:

* the time of most recent metadata change on Unix,
* the time of creation on Windows, expressed in seconds.
Time of most recent metadata change expressed in seconds.

.. attribute:: st_atime_ns

Expand All @@ -2921,11 +2922,8 @@ features:

.. attribute:: st_ctime_ns

Platform dependent:

* the time of most recent metadata change on Unix,
* the time of creation on Windows, expressed in nanoseconds as an
integer.
Time of most recent metadata change expressed in nanoseconds as an
integer.

.. note::

Expand Down Expand Up @@ -2975,7 +2973,7 @@ features:

.. attribute:: st_birthtime

Time of file creation.
Time of file creation. This is also available on Windows.

On Solaris and derivatives, the following attributes may also be
available:
Expand All @@ -2999,7 +2997,8 @@ features:

File type.

On Windows systems, the following attributes are also available:
On Windows systems, as well as ``st_birthtime`` above, the following
attributes are also available:

.. attribute:: st_file_attributes

Expand Down Expand Up @@ -3049,6 +3048,24 @@ features:
files as :const:`S_IFCHR`, :const:`S_IFIFO` or :const:`S_IFBLK`
as appropriate.

.. versionchanged:: 3.12
On Windows, :attr:`st_ctime` now also contains the last metadata
change time, for consistency with other platforms.
Use :attr:`st_birthtime` for the creation time when available.

.. versionchanged:: 3.12
On Windows, :attr:`st_ino` may now be up to 128 bits, depending
on the file system. Previously it would not be above 64 bits, and
larger file identifiers would be arbitrarily packed.

.. versionchanged:: 3.12
On Windows, :attr:`st_rdev` no longer returns a value. Previously
it would contain the same as :attr:`st_dev`, which was incorrect.

.. versionadded:: 3.12
Added the :attr:`st_birthtime` on Windows


.. function:: statvfs(path)

Perform a :c:func:`statvfs` system call on the given path. The return value is
Expand Down
9 changes: 9 additions & 0 deletions Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,15 @@ os
method to check if the entry is a junction.
(Contributed by Charles Machalow in :gh:`99547`.)

* :func:`os.stat` and :func:`os.lstat` are now more accurate on Windows.
The ``st_birthtime`` field will now be filled with the creation time
of the file, and ``st_ctime`` now returns the last metadata change,
for consistency with other platforms. ``st_ino`` may now be up to 128
bits, depending on your file system, and ``st_rdev`` is always set to
zero rather than to incorrect values.
Both functions may be significantly faster on newer releases of
Windows. (Contributed by Steve Dower in :gh:`99726`.)

os.path
-------

Expand Down
5 changes: 4 additions & 1 deletion Include/internal/pycore_fileutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ PyAPI_FUNC(PyObject *) _Py_device_encoding(int);

#ifdef MS_WINDOWS
struct _Py_stat_struct {
unsigned long st_dev;
uint64_t st_dev;
uint64_t st_ino;
unsigned short st_mode;
int st_nlink;
Expand All @@ -80,8 +80,11 @@ struct _Py_stat_struct {
int st_mtime_nsec;
time_t st_ctime;
int st_ctime_nsec;
time_t st_birthtime;
int st_birthtime_nsec;
unsigned long st_file_attributes;
unsigned long st_reparse_tag;
uint64_t st_ino_high;
};
#else
# define _Py_stat_struct stat
Expand Down
80 changes: 80 additions & 0 deletions Include/internal/pycore_fileutils_windows.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#ifndef Py_INTERNAL_FILEUTILS_WINDOWS_H
#define Py_INTERNAL_FILEUTILS_WINDOWS_H
#ifdef __cplusplus
extern "C" {
#endif

#ifndef Py_BUILD_CORE
# error "Py_BUILD_CORE must be defined to include this header"
#endif

#ifdef MS_WINDOWS

#if !defined(NTDDI_WIN10_NI) || !(NTDDI_VERSION >= NTDDI_WIN10_NI)
typedef struct _FILE_STAT_BASIC_INFORMATION {
LARGE_INTEGER FileId;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER AllocationSize;
LARGE_INTEGER EndOfFile;
ULONG FileAttributes;
ULONG ReparseTag;
ULONG NumberOfLinks;
ULONG DeviceType;
ULONG DeviceCharacteristics;
ULONG Reserved;
ULONGLONG FileIdHigh;
ULONGLONG VolumeSerialNumber;
} FILE_STAT_BASIC_INFORMATION;

typedef enum _FILE_INFO_BY_NAME_CLASS {
FileStatByNameInfo,
FileStatLxByNameInfo,
FileCaseSensitiveByNameInfo,
FileStatBasicByNameInfo,
MaximumFileInfoByNameClass
} FILE_INFO_BY_NAME_CLASS;
#endif

typedef BOOL (WINAPI *PGetFileInformationByName)(
PCWSTR FileName,
FILE_INFO_BY_NAME_CLASS FileInformationClass,
PVOID FileInfoBuffer,
ULONG FileInfoBufferSize
);

static inline BOOL _Py_GetFileInformationByName(
PCWSTR FileName,
FILE_INFO_BY_NAME_CLASS FileInformationClass,
PVOID FileInfoBuffer,
ULONG FileInfoBufferSize
) {
static PGetFileInformationByName GetFileInformationByName = NULL;
static int GetFileInformationByName_init = -1;

if (GetFileInformationByName_init < 0) {
HMODULE hMod = LoadLibraryW(L"api-ms-win-core-file-l2-1-4");
GetFileInformationByName_init = 0;
if (hMod) {
GetFileInformationByName = (PGetFileInformationByName)GetProcAddress(
hMod, "GetFileInformationByName");
if (GetFileInformationByName) {
GetFileInformationByName_init = 1;
} else {
FreeLibrary(hMod);
}
}
}

if (GetFileInformationByName_init <= 0) {
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
return GetFileInformationByName(FileName, FileInformationClass, FileInfoBuffer, FileInfoBufferSize);
}

#endif

#endif
3 changes: 2 additions & 1 deletion Lib/test/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -4164,7 +4164,8 @@ def assert_stat_equal(self, stat1, stat2, skip_fields):
for attr in dir(stat1):
if not attr.startswith("st_"):
continue
if attr in ("st_dev", "st_ino", "st_nlink"):
if attr in ("st_dev", "st_ino", "st_nlink", "st_ctime",
"st_ctime_ns"):
continue
self.assertEqual(getattr(stat1, attr),
getattr(stat2, attr),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improves correctness of stat results for Windows, and uses faster API when
available
Loading