mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	Issue #23152: Implement _Py_fstat() to support files larger than 2 GB on Windows.
fstat() may fail with EOVERFLOW on files larger than 2 GB because the file size type is an signed 32-bit integer.
This commit is contained in:
		
							parent
							
								
									18d1924987
								
							
						
					
					
						commit
						f2f373f593
					
				
					 12 changed files with 242 additions and 180 deletions
				
			
		|  | @ -21,11 +21,40 @@ PyAPI_FUNC(int) _Py_wstat( | ||||||
|     struct stat *buf); |     struct stat *buf); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #if defined(HAVE_FSTAT) || defined(MS_WINDOWS) | ||||||
|  | 
 | ||||||
|  | #ifdef MS_WINDOWS | ||||||
|  | struct _Py_stat_struct { | ||||||
|  |     unsigned long st_dev; | ||||||
|  |     __int64 st_ino; | ||||||
|  |     unsigned short st_mode; | ||||||
|  |     int st_nlink; | ||||||
|  |     int st_uid; | ||||||
|  |     int st_gid; | ||||||
|  |     unsigned long st_rdev; | ||||||
|  |     __int64 st_size; | ||||||
|  |     time_t st_atime; | ||||||
|  |     int st_atime_nsec; | ||||||
|  |     time_t st_mtime; | ||||||
|  |     int st_mtime_nsec; | ||||||
|  |     time_t st_ctime; | ||||||
|  |     int st_ctime_nsec; | ||||||
|  |     unsigned long st_file_attributes; | ||||||
|  | }; | ||||||
|  | #else | ||||||
|  | #  define _Py_stat_struct stat | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | PyAPI_FUNC(int) _Py_fstat( | ||||||
|  |     int fd, | ||||||
|  |     struct _Py_stat_struct *stat); | ||||||
|  | #endif   /* HAVE_FSTAT || MS_WINDOWS */ | ||||||
|  | 
 | ||||||
| #ifdef HAVE_STAT | #ifdef HAVE_STAT | ||||||
| PyAPI_FUNC(int) _Py_stat( | PyAPI_FUNC(int) _Py_stat( | ||||||
|     PyObject *path, |     PyObject *path, | ||||||
|     struct stat *statbuf); |     struct stat *statbuf); | ||||||
| #endif | #endif   /* HAVE_STAT */ | ||||||
| 
 | 
 | ||||||
| #ifndef Py_LIMITED_API | #ifndef Py_LIMITED_API | ||||||
| PyAPI_FUNC(int) _Py_open( | PyAPI_FUNC(int) _Py_open( | ||||||
|  |  | ||||||
|  | @ -180,9 +180,9 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | ||||||
| static int | static int | ||||||
| check_fd(int fd) | check_fd(int fd) | ||||||
| { | { | ||||||
| #if defined(HAVE_FSTAT) | #if defined(HAVE_FSTAT) || defined(MS_WINDOWS) | ||||||
|     struct stat buf; |     struct _Py_stat_struct buf; | ||||||
|     if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) { |     if (!_PyVerify_fd(fd) || (_Py_fstat(fd, &buf) < 0 && errno == EBADF)) { | ||||||
|         PyObject *exc; |         PyObject *exc; | ||||||
|         char *msg = strerror(EBADF); |         char *msg = strerror(EBADF); | ||||||
|         exc = PyObject_CallFunction(PyExc_OSError, "(is)", |         exc = PyObject_CallFunction(PyExc_OSError, "(is)", | ||||||
|  | @ -222,8 +222,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) | ||||||
| #elif !defined(MS_WINDOWS) | #elif !defined(MS_WINDOWS) | ||||||
|     int *atomic_flag_works = NULL; |     int *atomic_flag_works = NULL; | ||||||
| #endif | #endif | ||||||
| #ifdef HAVE_FSTAT | #if defined(HAVE_FSTAT) || defined(MS_WINDOWS) | ||||||
|     struct stat fdfstat; |     struct _Py_stat_struct fdfstat; | ||||||
| #endif | #endif | ||||||
|     int async_err = 0; |     int async_err = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -420,9 +420,11 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     self->blksize = DEFAULT_BUFFER_SIZE; |     self->blksize = DEFAULT_BUFFER_SIZE; | ||||||
| #ifdef HAVE_FSTAT | #if defined(HAVE_FSTAT) || defined(MS_WINDOWS) | ||||||
|     if (fstat(self->fd, &fdfstat) < 0) |     if (_Py_fstat(self->fd, &fdfstat) < 0) { | ||||||
|  |         PyErr_SetFromErrno(PyExc_OSError); | ||||||
|         goto error; |         goto error; | ||||||
|  |     } | ||||||
| #if defined(S_ISDIR) && defined(EISDIR) | #if defined(S_ISDIR) && defined(EISDIR) | ||||||
|     /* On Unix, open will succeed for directories.
 |     /* On Unix, open will succeed for directories.
 | ||||||
|        In Python, there should be no file objects referring to |        In Python, there should be no file objects referring to | ||||||
|  | @ -437,7 +439,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) | ||||||
|     if (fdfstat.st_blksize > 1) |     if (fdfstat.st_blksize > 1) | ||||||
|         self->blksize = fdfstat.st_blksize; |         self->blksize = fdfstat.st_blksize; | ||||||
| #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ | #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ | ||||||
| #endif /* HAVE_FSTAT */ | #endif /* HAVE_FSTAT || MS_WINDOWS */ | ||||||
| 
 | 
 | ||||||
| #if defined(MS_WINDOWS) || defined(__CYGWIN__) | #if defined(MS_WINDOWS) || defined(__CYGWIN__) | ||||||
|     /* don't translate newlines (\r\n <=> \n) */ |     /* don't translate newlines (\r\n <=> \n) */ | ||||||
|  | @ -603,17 +605,7 @@ fileio_readinto(fileio *self, PyObject *args) | ||||||
|     return PyLong_FromSsize_t(n); |     return PyLong_FromSsize_t(n); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifndef HAVE_FSTAT | #if defined(HAVE_FSTAT) || defined(MS_WINDOWS) | ||||||
| 
 |  | ||||||
| static PyObject * |  | ||||||
| fileio_readall(fileio *self) |  | ||||||
| { |  | ||||||
|     _Py_IDENTIFIER(readall); |  | ||||||
|     return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, |  | ||||||
|                                   &PyId_readall, "O", self); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #else |  | ||||||
| 
 | 
 | ||||||
| static size_t | static size_t | ||||||
| new_buffersize(fileio *self, size_t currentsize) | new_buffersize(fileio *self, size_t currentsize) | ||||||
|  | @ -637,7 +629,7 @@ new_buffersize(fileio *self, size_t currentsize) | ||||||
| static PyObject * | static PyObject * | ||||||
| fileio_readall(fileio *self) | fileio_readall(fileio *self) | ||||||
| { | { | ||||||
|     struct stat st; |     struct _Py_stat_struct st; | ||||||
|     Py_off_t pos, end; |     Py_off_t pos, end; | ||||||
|     PyObject *result; |     PyObject *result; | ||||||
|     Py_ssize_t bytes_read = 0; |     Py_ssize_t bytes_read = 0; | ||||||
|  | @ -655,7 +647,7 @@ fileio_readall(fileio *self) | ||||||
| #else | #else | ||||||
|     pos = lseek(self->fd, 0L, SEEK_CUR); |     pos = lseek(self->fd, 0L, SEEK_CUR); | ||||||
| #endif | #endif | ||||||
|     if (fstat(self->fd, &st) == 0) |     if (_Py_fstat(self->fd, &st) == 0) | ||||||
|         end = st.st_size; |         end = st.st_size; | ||||||
|     else |     else | ||||||
|         end = (Py_off_t)-1; |         end = (Py_off_t)-1; | ||||||
|  | @ -729,7 +721,17 @@ fileio_readall(fileio *self) | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #endif /* HAVE_FSTAT */ | #else | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | fileio_readall(fileio *self) | ||||||
|  | { | ||||||
|  |     _Py_IDENTIFIER(readall); | ||||||
|  |     return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, | ||||||
|  |                                   &PyId_readall, "O", self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif /* HAVE_FSTAT || MS_WINDOWS */ | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| fileio_read(fileio *self, PyObject *args) | fileio_read(fileio *self, PyObject *args) | ||||||
|  |  | ||||||
|  | @ -752,9 +752,8 @@ Py_Main(int argc, wchar_t **argv) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             { |             { | ||||||
|                 /* XXX: does this work on Win/Win64? (see posix_fstat) */ |                 struct _Py_stat_struct sb; | ||||||
|                 struct stat sb; |                 if (_Py_fstat(fileno(fp), &sb) == 0 && | ||||||
|                 if (fstat(fileno(fp), &sb) == 0 && |  | ||||||
|                     S_ISDIR(sb.st_mode)) { |                     S_ISDIR(sb.st_mode)) { | ||||||
|                     fprintf(stderr, "%ls: '%ls' is a directory, cannot continue\n", argv[0], filename); |                     fprintf(stderr, "%ls: '%ls' is a directory, cannot continue\n", argv[0], filename); | ||||||
|                     fclose(fp); |                     fclose(fp); | ||||||
|  |  | ||||||
|  | @ -459,8 +459,8 @@ mmap_size_method(mmap_object *self, | ||||||
| 
 | 
 | ||||||
| #ifdef UNIX | #ifdef UNIX | ||||||
|     { |     { | ||||||
|         struct stat buf; |         struct _Py_stat_struct buf; | ||||||
|         if (-1 == fstat(self->fd, &buf)) { |         if (-1 == _Py_fstat(self->fd, &buf)) { | ||||||
|             PyErr_SetFromErrno(PyExc_OSError); |             PyErr_SetFromErrno(PyExc_OSError); | ||||||
|             return NULL; |             return NULL; | ||||||
|         } |         } | ||||||
|  | @ -1107,7 +1107,7 @@ static PyObject * | ||||||
| new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) | new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) | ||||||
| { | { | ||||||
| #ifdef HAVE_FSTAT | #ifdef HAVE_FSTAT | ||||||
|     struct stat st; |     struct _Py_stat_struct st; | ||||||
| #endif | #endif | ||||||
|     mmap_object *m_obj; |     mmap_object *m_obj; | ||||||
|     PyObject *map_size_obj = NULL; |     PyObject *map_size_obj = NULL; | ||||||
|  | @ -1174,7 +1174,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) | ||||||
|         (void)fcntl(fd, F_FULLFSYNC); |         (void)fcntl(fd, F_FULLFSYNC); | ||||||
| #endif | #endif | ||||||
| #ifdef HAVE_FSTAT | #ifdef HAVE_FSTAT | ||||||
|     if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { |     if (fd != -1 && _Py_fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { | ||||||
|         if (map_size == 0) { |         if (map_size == 0) { | ||||||
|             if (st.st_size == 0) { |             if (st.st_size == 0) { | ||||||
|                 PyErr_SetString(PyExc_ValueError, |                 PyErr_SetString(PyExc_ValueError, | ||||||
|  |  | ||||||
|  | @ -350,8 +350,8 @@ static int win32_can_symlink = 0; | ||||||
| #ifdef MS_WINDOWS | #ifdef MS_WINDOWS | ||||||
| #       define STAT win32_stat | #       define STAT win32_stat | ||||||
| #       define LSTAT win32_lstat | #       define LSTAT win32_lstat | ||||||
| #       define FSTAT win32_fstat | #       define FSTAT _Py_fstat | ||||||
| #       define STRUCT_STAT struct win32_stat | #       define STRUCT_STAT struct _Py_stat_struct | ||||||
| #else | #else | ||||||
| #       define STAT stat | #       define STAT stat | ||||||
| #       define LSTAT lstat | #       define LSTAT lstat | ||||||
|  | @ -1469,73 +1469,6 @@ struct win32_stat{ | ||||||
|     unsigned long st_file_attributes; |     unsigned long st_file_attributes; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */ |  | ||||||
| 
 |  | ||||||
| static void |  | ||||||
| FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) |  | ||||||
| { |  | ||||||
|     /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */ |  | ||||||
|     /* Cannot simply cast and dereference in_ptr,
 |  | ||||||
|        since it might not be aligned properly */ |  | ||||||
|     __int64 in; |  | ||||||
|     memcpy(&in, in_ptr, sizeof(in)); |  | ||||||
|     *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ |  | ||||||
|     *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void |  | ||||||
| time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) |  | ||||||
| { |  | ||||||
|     /* XXX endianness */ |  | ||||||
|     __int64 out; |  | ||||||
|     out = time_in + secs_between_epochs; |  | ||||||
|     out = out * 10000000 + nsec_in / 100; |  | ||||||
|     memcpy(out_ptr, &out, sizeof(out)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* Below, we *know* that ugo+r is 0444 */ |  | ||||||
| #if _S_IREAD != 0400 |  | ||||||
| #error Unsupported C library |  | ||||||
| #endif |  | ||||||
| static int |  | ||||||
| attributes_to_mode(DWORD attr) |  | ||||||
| { |  | ||||||
|     int m = 0; |  | ||||||
|     if (attr & FILE_ATTRIBUTE_DIRECTORY) |  | ||||||
|         m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */ |  | ||||||
|     else |  | ||||||
|         m |= _S_IFREG; |  | ||||||
|     if (attr & FILE_ATTRIBUTE_READONLY) |  | ||||||
|         m |= 0444; |  | ||||||
|     else |  | ||||||
|         m |= 0666; |  | ||||||
|     return m; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int |  | ||||||
| attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct win32_stat *result) |  | ||||||
| { |  | ||||||
|     memset(result, 0, sizeof(*result)); |  | ||||||
|     result->st_mode = attributes_to_mode(info->dwFileAttributes); |  | ||||||
|     result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow; |  | ||||||
|     result->st_dev = info->dwVolumeSerialNumber; |  | ||||||
|     result->st_rdev = result->st_dev; |  | ||||||
|     FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec); |  | ||||||
|     FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); |  | ||||||
|     FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); |  | ||||||
|     result->st_nlink = info->nNumberOfLinks; |  | ||||||
|     result->st_ino = (((__int64)info->nFileIndexHigh)<<32) + info->nFileIndexLow; |  | ||||||
|     if (reparse_tag == IO_REPARSE_TAG_SYMLINK) { |  | ||||||
|         /* first clear the S_IFMT bits */ |  | ||||||
|         result->st_mode ^= (result->st_mode & S_IFMT); |  | ||||||
|         /* now set the bits that make this a symlink */ |  | ||||||
|         result->st_mode |= S_IFLNK; |  | ||||||
|     } |  | ||||||
|     result->st_file_attributes = info->dwFileAttributes; |  | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static BOOL | static BOOL | ||||||
| attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag) | attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag) | ||||||
| { | { | ||||||
|  | @ -1645,11 +1578,15 @@ get_target_path(HANDLE hdl, wchar_t **target_path) | ||||||
|     return TRUE; |     return TRUE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* defined in fileutils.c */ | ||||||
|  | int | ||||||
|  | attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct _Py_stat_struct *result); | ||||||
|  | 
 | ||||||
| static int | static int | ||||||
| win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, | win32_xstat_impl_w(const wchar_t *path, struct _Py_stat_struct *result, | ||||||
|                    BOOL traverse); |                    BOOL traverse); | ||||||
| static int | static int | ||||||
| win32_xstat_impl(const char *path, struct win32_stat *result, | win32_xstat_impl(const char *path, struct _Py_stat_struct *result, | ||||||
|                  BOOL traverse) |                  BOOL traverse) | ||||||
| { | { | ||||||
|     int code; |     int code; | ||||||
|  | @ -1745,7 +1682,7 @@ win32_xstat_impl(const char *path, struct win32_stat *result, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, | win32_xstat_impl_w(const wchar_t *path, struct _Py_stat_struct *result, | ||||||
|                    BOOL traverse) |                    BOOL traverse) | ||||||
| { | { | ||||||
|     int code; |     int code; | ||||||
|  | @ -1841,7 +1778,7 @@ win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| win32_xstat(const char *path, struct win32_stat *result, BOOL traverse) | win32_xstat(const char *path, struct _Py_stat_struct *result, BOOL traverse) | ||||||
| { | { | ||||||
|     /* Protocol violation: we explicitly clear errno, instead of
 |     /* Protocol violation: we explicitly clear errno, instead of
 | ||||||
|        setting it to a POSIX error. Callers should use GetLastError. */ |        setting it to a POSIX error. Callers should use GetLastError. */ | ||||||
|  | @ -1851,7 +1788,7 @@ win32_xstat(const char *path, struct win32_stat *result, BOOL traverse) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse) | win32_xstat_w(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse) | ||||||
| { | { | ||||||
|     /* Protocol violation: we explicitly clear errno, instead of
 |     /* Protocol violation: we explicitly clear errno, instead of
 | ||||||
|        setting it to a POSIX error. Callers should use GetLastError. */ |        setting it to a POSIX error. Callers should use GetLastError. */ | ||||||
|  | @ -1873,80 +1810,29 @@ win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse) | ||||||
|    The _w represent Unicode equivalents of the aforementioned ANSI functions. */ |    The _w represent Unicode equivalents of the aforementioned ANSI functions. */ | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| win32_lstat(const char* path, struct win32_stat *result) | win32_lstat(const char* path, struct _Py_stat_struct *result) | ||||||
| { | { | ||||||
|     return win32_xstat(path, result, FALSE); |     return win32_xstat(path, result, FALSE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| win32_lstat_w(const wchar_t* path, struct win32_stat *result) | win32_lstat_w(const wchar_t* path, struct _Py_stat_struct *result) | ||||||
| { | { | ||||||
|     return win32_xstat_w(path, result, FALSE); |     return win32_xstat_w(path, result, FALSE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| win32_stat(const char* path, struct win32_stat *result) | win32_stat(const char* path, struct _Py_stat_struct *result) | ||||||
| { | { | ||||||
|     return win32_xstat(path, result, TRUE); |     return win32_xstat(path, result, TRUE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| win32_stat_w(const wchar_t* path, struct win32_stat *result) | win32_stat_w(const wchar_t* path, struct _Py_stat_struct *result) | ||||||
| { | { | ||||||
|     return win32_xstat_w(path, result, TRUE); |     return win32_xstat_w(path, result, TRUE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int |  | ||||||
| win32_fstat(int file_number, struct win32_stat *result) |  | ||||||
| { |  | ||||||
|     BY_HANDLE_FILE_INFORMATION info; |  | ||||||
|     HANDLE h; |  | ||||||
|     int type; |  | ||||||
| 
 |  | ||||||
|     if (!_PyVerify_fd(file_number)) |  | ||||||
|         h = INVALID_HANDLE_VALUE; |  | ||||||
|     else |  | ||||||
|         h = (HANDLE)_get_osfhandle(file_number); |  | ||||||
| 
 |  | ||||||
|     /* Protocol violation: we explicitly clear errno, instead of
 |  | ||||||
|        setting it to a POSIX error. Callers should use GetLastError. */ |  | ||||||
|     errno = 0; |  | ||||||
| 
 |  | ||||||
|     if (h == INVALID_HANDLE_VALUE) { |  | ||||||
|         /* This is really a C library error (invalid file handle).
 |  | ||||||
|            We set the Win32 error to the closes one matching. */ |  | ||||||
|         SetLastError(ERROR_INVALID_HANDLE); |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
|     memset(result, 0, sizeof(*result)); |  | ||||||
| 
 |  | ||||||
|     type = GetFileType(h); |  | ||||||
|     if (type == FILE_TYPE_UNKNOWN) { |  | ||||||
|         DWORD error = GetLastError(); |  | ||||||
|         if (error != 0) { |  | ||||||
|             return -1; |  | ||||||
|         } |  | ||||||
|         /* else: valid but unknown file */ |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (type != FILE_TYPE_DISK) { |  | ||||||
|         if (type == FILE_TYPE_CHAR) |  | ||||||
|             result->st_mode = _S_IFCHR; |  | ||||||
|         else if (type == FILE_TYPE_PIPE) |  | ||||||
|             result->st_mode = _S_IFIFO; |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (!GetFileInformationByHandle(h, &info)) { |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     attribute_data_to_stat(&info, 0, result); |  | ||||||
|     /* specific to fstat() */ |  | ||||||
|     result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow; |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #endif /* MS_WINDOWS */ | #endif /* MS_WINDOWS */ | ||||||
| 
 | 
 | ||||||
| PyDoc_STRVAR(stat_result__doc__, | PyDoc_STRVAR(stat_result__doc__, | ||||||
|  | @ -6333,6 +6219,11 @@ os_utime(PyModuleDef *module, PyObject *args, PyObject *kwargs) | ||||||
|     return return_value; |     return return_value; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef MS_WINDOWS | ||||||
|  | void | ||||||
|  | time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| os_utime_impl(PyModuleDef *module, path_t *path, PyObject *times, PyObject *ns, int dir_fd, int follow_symlinks) | os_utime_impl(PyModuleDef *module, path_t *path, PyObject *times, PyObject *ns, int dir_fd, int follow_symlinks) | ||||||
| /*[clinic end generated code: output=891489c35cc68c5d input=1f18c17d5941aa82]*/ | /*[clinic end generated code: output=891489c35cc68c5d input=1f18c17d5941aa82]*/ | ||||||
|  |  | ||||||
|  | @ -503,13 +503,13 @@ signal_siginterrupt(PyObject *self, PyObject *args) | ||||||
| static PyObject * | static PyObject * | ||||||
| signal_set_wakeup_fd(PyObject *self, PyObject *args) | signal_set_wakeup_fd(PyObject *self, PyObject *args) | ||||||
| { | { | ||||||
|  |     struct _Py_stat_struct st; | ||||||
| #ifdef MS_WINDOWS | #ifdef MS_WINDOWS | ||||||
|     PyObject *fdobj; |     PyObject *fdobj; | ||||||
|     SOCKET_T sockfd, old_sockfd; |     SOCKET_T sockfd, old_sockfd; | ||||||
|     int res; |     int res; | ||||||
|     int res_size = sizeof res; |     int res_size = sizeof res; | ||||||
|     PyObject *mod; |     PyObject *mod; | ||||||
|     struct stat st; |  | ||||||
|     int is_socket; |     int is_socket; | ||||||
| 
 | 
 | ||||||
|     if (!PyArg_ParseTuple(args, "O:set_wakeup_fd", &fdobj)) |     if (!PyArg_ParseTuple(args, "O:set_wakeup_fd", &fdobj)) | ||||||
|  | @ -520,7 +520,6 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args) | ||||||
|         return NULL; |         return NULL; | ||||||
| #else | #else | ||||||
|     int fd, old_fd; |     int fd, old_fd; | ||||||
|     struct stat st; |  | ||||||
| 
 | 
 | ||||||
|     if (!PyArg_ParseTuple(args, "i:set_wakeup_fd", &fd)) |     if (!PyArg_ParseTuple(args, "i:set_wakeup_fd", &fd)) | ||||||
|         return NULL; |         return NULL; | ||||||
|  | @ -560,7 +559,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args) | ||||||
|                 return NULL; |                 return NULL; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (fstat(fd, &st) != 0) { |             if (_Py_fstat(fd, &st) != 0) { | ||||||
|                 PyErr_SetFromErrno(PyExc_OSError); |                 PyErr_SetFromErrno(PyExc_OSError); | ||||||
|                 return NULL; |                 return NULL; | ||||||
|             } |             } | ||||||
|  | @ -592,7 +591,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args) | ||||||
|             return NULL; |             return NULL; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (fstat(fd, &st) != 0) { |         if (_Py_fstat(fd, &st) != 0) { | ||||||
|             PyErr_SetFromErrno(PyExc_OSError); |             PyErr_SetFromErrno(PyExc_OSError); | ||||||
|             return NULL; |             return NULL; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -35,7 +35,7 @@ main(int argc, char *argv[]) | ||||||
| { | { | ||||||
|     char *inpath, *outpath; |     char *inpath, *outpath; | ||||||
|     FILE *infile = NULL, *outfile = NULL; |     FILE *infile = NULL, *outfile = NULL; | ||||||
|     struct stat st; |     struct _Py_stat_struct st; | ||||||
|     size_t text_size, data_size, n; |     size_t text_size, data_size, n; | ||||||
|     char *text = NULL; |     char *text = NULL; | ||||||
|     unsigned char *data; |     unsigned char *data; | ||||||
|  | @ -54,7 +54,7 @@ main(int argc, char *argv[]) | ||||||
|         fprintf(stderr, "cannot open '%s' for reading\n", inpath); |         fprintf(stderr, "cannot open '%s' for reading\n", inpath); | ||||||
|         goto error; |         goto error; | ||||||
|     } |     } | ||||||
|     if (fstat(fileno(infile), &st)) { |     if (_Py_fstat(fileno(infile), &st)) { | ||||||
|         fprintf(stderr, "cannot fstat '%s'\n", inpath); |         fprintf(stderr, "cannot fstat '%s'\n", inpath); | ||||||
|         goto error; |         goto error; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -71,8 +71,8 @@ dl_funcptr _PyImport_GetDynLoadFunc(const char *shortname, | ||||||
| 
 | 
 | ||||||
|     if (fp != NULL) { |     if (fp != NULL) { | ||||||
|         int i; |         int i; | ||||||
|         struct stat statb; |         struct _Py_stat_struct statb; | ||||||
|         if (fstat(fileno(fp), &statb) == -1) { |         if (_Py_fstat(fileno(fp), &statb) == -1) { | ||||||
|             PyErr_SetFromErrno(PyExc_IOError); |             PyErr_SetFromErrno(PyExc_IOError); | ||||||
|             return NULL; |             return NULL; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -544,8 +544,145 @@ _Py_wstat(const wchar_t* path, struct stat *buf) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef HAVE_STAT |  | ||||||
| 
 | 
 | ||||||
|  | #if defined(HAVE_FSTAT) || defined(MS_WINDOWS) | ||||||
|  | 
 | ||||||
|  | #ifdef MS_WINDOWS | ||||||
|  | static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */ | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) | ||||||
|  | { | ||||||
|  |     /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */ | ||||||
|  |     /* Cannot simply cast and dereference in_ptr,
 | ||||||
|  |        since it might not be aligned properly */ | ||||||
|  |     __int64 in; | ||||||
|  |     memcpy(&in, in_ptr, sizeof(in)); | ||||||
|  |     *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ | ||||||
|  |     *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) | ||||||
|  | { | ||||||
|  |     /* XXX endianness */ | ||||||
|  |     __int64 out; | ||||||
|  |     out = time_in + secs_between_epochs; | ||||||
|  |     out = out * 10000000 + nsec_in / 100; | ||||||
|  |     memcpy(out_ptr, &out, sizeof(out)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Below, we *know* that ugo+r is 0444 */ | ||||||
|  | #if _S_IREAD != 0400 | ||||||
|  | #error Unsupported C library | ||||||
|  | #endif | ||||||
|  | static int | ||||||
|  | attributes_to_mode(DWORD attr) | ||||||
|  | { | ||||||
|  |     int m = 0; | ||||||
|  |     if (attr & FILE_ATTRIBUTE_DIRECTORY) | ||||||
|  |         m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */ | ||||||
|  |     else | ||||||
|  |         m |= _S_IFREG; | ||||||
|  |     if (attr & FILE_ATTRIBUTE_READONLY) | ||||||
|  |         m |= 0444; | ||||||
|  |     else | ||||||
|  |         m |= 0666; | ||||||
|  |     return m; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct _Py_stat_struct *result) | ||||||
|  | { | ||||||
|  |     memset(result, 0, sizeof(*result)); | ||||||
|  |     result->st_mode = attributes_to_mode(info->dwFileAttributes); | ||||||
|  |     result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow; | ||||||
|  |     result->st_dev = info->dwVolumeSerialNumber; | ||||||
|  |     result->st_rdev = result->st_dev; | ||||||
|  |     FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec); | ||||||
|  |     FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); | ||||||
|  |     FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); | ||||||
|  |     result->st_nlink = info->nNumberOfLinks; | ||||||
|  |     result->st_ino = (((__int64)info->nFileIndexHigh)<<32) + info->nFileIndexLow; | ||||||
|  |     if (reparse_tag == IO_REPARSE_TAG_SYMLINK) { | ||||||
|  |         /* first clear the S_IFMT bits */ | ||||||
|  |         result->st_mode ^= (result->st_mode & S_IFMT); | ||||||
|  |         /* now set the bits that make this a symlink */ | ||||||
|  |         result->st_mode |= S_IFLNK; | ||||||
|  |     } | ||||||
|  |     result->st_file_attributes = info->dwFileAttributes; | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* Return information about a file.
 | ||||||
|  | 
 | ||||||
|  |    On POSIX, use fstat(). | ||||||
|  | 
 | ||||||
|  |    On Windows, use GetFileType() and GetFileInformationByHandle() which support | ||||||
|  |    files larger than 2 GB.  fstat() may fail with EOVERFLOW on files larger | ||||||
|  |    than 2 GB because the file size type is an signed 32-bit integer: see issue | ||||||
|  |    #23152. | ||||||
|  |    */ | ||||||
|  | int | ||||||
|  | _Py_fstat(int fd, struct _Py_stat_struct *result) | ||||||
|  | { | ||||||
|  | #ifdef MS_WINDOWS | ||||||
|  |     BY_HANDLE_FILE_INFORMATION info; | ||||||
|  |     HANDLE h; | ||||||
|  |     int type; | ||||||
|  | 
 | ||||||
|  |     if (!_PyVerify_fd(fd)) | ||||||
|  |         h = INVALID_HANDLE_VALUE; | ||||||
|  |     else | ||||||
|  |         h = (HANDLE)_get_osfhandle(fd); | ||||||
|  | 
 | ||||||
|  |     /* Protocol violation: we explicitly clear errno, instead of
 | ||||||
|  |        setting it to a POSIX error. Callers should use GetLastError. */ | ||||||
|  |     errno = 0; | ||||||
|  | 
 | ||||||
|  |     if (h == INVALID_HANDLE_VALUE) { | ||||||
|  |         /* This is really a C library error (invalid file handle).
 | ||||||
|  |            We set the Win32 error to the closes one matching. */ | ||||||
|  |         SetLastError(ERROR_INVALID_HANDLE); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     memset(result, 0, sizeof(*result)); | ||||||
|  | 
 | ||||||
|  |     type = GetFileType(h); | ||||||
|  |     if (type == FILE_TYPE_UNKNOWN) { | ||||||
|  |         DWORD error = GetLastError(); | ||||||
|  |         if (error != 0) { | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |         /* else: valid but unknown file */ | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (type != FILE_TYPE_DISK) { | ||||||
|  |         if (type == FILE_TYPE_CHAR) | ||||||
|  |             result->st_mode = _S_IFCHR; | ||||||
|  |         else if (type == FILE_TYPE_PIPE) | ||||||
|  |             result->st_mode = _S_IFIFO; | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!GetFileInformationByHandle(h, &info)) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     attribute_data_to_stat(&info, 0, result); | ||||||
|  |     /* specific to fstat() */ | ||||||
|  |     result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow; | ||||||
|  |     return 0; | ||||||
|  | #else | ||||||
|  |     return fstat(fd, result); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | #endif   /* HAVE_FSTAT || MS_WINDOWS */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #ifdef HAVE_STAT | ||||||
| /* Call _wstat() on Windows, or encode the path to the filesystem encoding and
 | /* Call _wstat() on Windows, or encode the path to the filesystem encoding and
 | ||||||
|    call stat() otherwise. Only fill st_mode attribute on Windows. |    call stat() otherwise. Only fill st_mode attribute on Windows. | ||||||
| 
 | 
 | ||||||
|  | @ -578,7 +715,8 @@ _Py_stat(PyObject *path, struct stat *statbuf) | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #endif | #endif   /* HAVE_STAT */ | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| get_inheritable(int fd, int raise) | get_inheritable(int fd, int raise) | ||||||
|  |  | ||||||
|  | @ -1481,16 +1481,20 @@ PyMarshal_ReadLongFromFile(FILE *fp) | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef HAVE_FSTAT | #if defined(HAVE_FSTAT) || defined(MS_WINDOWS) | ||||||
| /* Return size of file in bytes; < 0 if unknown. */ | /* Return size of file in bytes; < 0 if unknown or INT_MAX if too big */ | ||||||
| static off_t | static off_t | ||||||
| getfilesize(FILE *fp) | getfilesize(FILE *fp) | ||||||
| { | { | ||||||
|     struct stat st; |     struct _Py_stat_struct st; | ||||||
|     if (fstat(fileno(fp), &st) != 0) |     if (_Py_fstat(fileno(fp), &st) != 0) | ||||||
|         return -1; |         return -1; | ||||||
|  | #if SIZEOF_OFF_T == 4 | ||||||
|  |     else if (st.st_size >= INT_MAX) | ||||||
|  |         return (off_t)INT_MAX; | ||||||
|  | #endif | ||||||
|     else |     else | ||||||
|         return st.st_size; |         return (off_t)st.st_size; | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | @ -1505,7 +1509,7 @@ PyMarshal_ReadLastObjectFromFile(FILE *fp) | ||||||
| { | { | ||||||
| /* REASONABLE_FILE_LIMIT is by defn something big enough for Tkinter.pyc. */ | /* REASONABLE_FILE_LIMIT is by defn something big enough for Tkinter.pyc. */ | ||||||
| #define REASONABLE_FILE_LIMIT (1L << 18) | #define REASONABLE_FILE_LIMIT (1L << 18) | ||||||
| #ifdef HAVE_FSTAT | #if defined(HAVE_FSTAT) || defined(MS_WINDOWS) | ||||||
|     off_t filesize; |     off_t filesize; | ||||||
|     filesize = getfilesize(fp); |     filesize = getfilesize(fp); | ||||||
|     if (filesize > 0 && filesize <= REASONABLE_FILE_LIMIT) { |     if (filesize > 0 && filesize <= REASONABLE_FILE_LIMIT) { | ||||||
|  |  | ||||||
|  | @ -139,14 +139,14 @@ dev_urandom_python(char *buffer, Py_ssize_t size) | ||||||
| { | { | ||||||
|     int fd; |     int fd; | ||||||
|     Py_ssize_t n; |     Py_ssize_t n; | ||||||
|     struct stat st; |     struct _Py_stat_struct st; | ||||||
| 
 | 
 | ||||||
|     if (size <= 0) |     if (size <= 0) | ||||||
|         return 0; |         return 0; | ||||||
| 
 | 
 | ||||||
|     if (urandom_cache.fd >= 0) { |     if (urandom_cache.fd >= 0) { | ||||||
|         /* Does the fd point to the same thing as before? (issue #21207) */ |         /* Does the fd point to the same thing as before? (issue #21207) */ | ||||||
|         if (fstat(urandom_cache.fd, &st) |         if (_Py_fstat(urandom_cache.fd, &st) | ||||||
|             || st.st_dev != urandom_cache.st_dev |             || st.st_dev != urandom_cache.st_dev | ||||||
|             || st.st_ino != urandom_cache.st_ino) { |             || st.st_ino != urandom_cache.st_ino) { | ||||||
|             /* Something changed: forget the cached fd (but don't close it,
 |             /* Something changed: forget the cached fd (but don't close it,
 | ||||||
|  | @ -178,7 +178,7 @@ dev_urandom_python(char *buffer, Py_ssize_t size) | ||||||
|             fd = urandom_cache.fd; |             fd = urandom_cache.fd; | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             if (fstat(fd, &st)) { |             if (_Py_fstat(fd, &st)) { | ||||||
|                 PyErr_SetFromErrno(PyExc_OSError); |                 PyErr_SetFromErrno(PyExc_OSError); | ||||||
|                 close(fd); |                 close(fd); | ||||||
|                 return -1; |                 return -1; | ||||||
|  |  | ||||||
|  | @ -1681,8 +1681,8 @@ _PySys_Init(void) | ||||||
|     the shell already prevents that. */ |     the shell already prevents that. */ | ||||||
| #if !defined(MS_WINDOWS) | #if !defined(MS_WINDOWS) | ||||||
|     { |     { | ||||||
|         struct stat sb; |         struct _Py_stat_struct sb; | ||||||
|         if (fstat(fileno(stdin), &sb) == 0 && |         if (_Py_fstat(fileno(stdin), &sb) == 0 && | ||||||
|             S_ISDIR(sb.st_mode)) { |             S_ISDIR(sb.st_mode)) { | ||||||
|             /* There's nothing more we can do. */ |             /* There's nothing more we can do. */ | ||||||
|             /* Py_FatalError() will core dump, so just exit. */ |             /* Py_FatalError() will core dump, so just exit. */ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Steve Dower
						Steve Dower