@@ -2855,6 +2855,8 @@ FTRUNCATE
28552855#ifdef MS_WINDOWS
28562856 #undef PATH_HAVE_FTRUNCATE
28572857 #define PATH_HAVE_FTRUNCATE 1
2858+ #undef PATH_HAVE_FCHMOD
2859+ #define PATH_HAVE_FCHMOD 1
28582860#endif
28592861
28602862/*[python input]
@@ -3332,7 +3334,38 @@ win32_lchmod(LPCWSTR path, int mode)
33323334 }
33333335 return SetFileAttributesW (path , attr );
33343336}
3335- #endif
3337+
3338+ static int
3339+ win32_hchmod (HANDLE hfile , int mode )
3340+ {
3341+ FILE_BASIC_INFO info ;
3342+ if (!GetFileInformationByHandleEx (hfile , FileBasicInfo ,
3343+ & info , sizeof (info )))
3344+ {
3345+ return 0 ;
3346+ }
3347+ if (mode & _S_IWRITE ) {
3348+ info .FileAttributes &= ~FILE_ATTRIBUTE_READONLY ;
3349+ }
3350+ else {
3351+ info .FileAttributes |= FILE_ATTRIBUTE_READONLY ;
3352+ }
3353+ return SetFileInformationByHandle (hfile , FileBasicInfo ,
3354+ & info , sizeof (info ));
3355+ }
3356+
3357+ static int
3358+ win32_fchmod (int fd , int mode )
3359+ {
3360+ HANDLE hfile = _Py_get_osfhandle_noraise (fd );
3361+ if (hfile == INVALID_HANDLE_VALUE ) {
3362+ SetLastError (ERROR_INVALID_HANDLE );
3363+ return 0 ;
3364+ }
3365+ return win32_hchmod (hfile , mode );
3366+ }
3367+
3368+ #endif /* MS_WINDOWS */
33363369
33373370/*[clinic input]
33383371os.chmod
@@ -3395,27 +3428,16 @@ os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd,
33953428#ifdef MS_WINDOWS
33963429 result = 0 ;
33973430 Py_BEGIN_ALLOW_THREADS
3398- if (follow_symlinks ) {
3399- HANDLE hfile ;
3400- FILE_BASIC_INFO info ;
3401-
3402- hfile = CreateFileW (path -> wide ,
3403- FILE_READ_ATTRIBUTES |FILE_WRITE_ATTRIBUTES ,
3404- 0 , NULL ,
3405- OPEN_EXISTING , FILE_FLAG_BACKUP_SEMANTICS , NULL );
3431+ if (path -> fd != -1 ) {
3432+ result = win32_fchmod ( path -> fd , mode ) ;
3433+ }
3434+ else if ( follow_symlinks ) {
3435+ HANDLE hfile = CreateFileW (path -> wide ,
3436+ FILE_READ_ATTRIBUTES |FILE_WRITE_ATTRIBUTES ,
3437+ 0 , NULL ,
3438+ OPEN_EXISTING , FILE_FLAG_BACKUP_SEMANTICS , NULL );
34063439 if (hfile != INVALID_HANDLE_VALUE ) {
3407- if (GetFileInformationByHandleEx (hfile , FileBasicInfo ,
3408- & info , sizeof (info )))
3409- {
3410- if (mode & _S_IWRITE ) {
3411- info .FileAttributes &= ~FILE_ATTRIBUTE_READONLY ;
3412- }
3413- else {
3414- info .FileAttributes |= FILE_ATTRIBUTE_READONLY ;
3415- }
3416- result = SetFileInformationByHandle (hfile , FileBasicInfo ,
3417- & info , sizeof (info ));
3418- }
3440+ result = win32_hchmod (hfile , mode );
34193441 (void )CloseHandle (hfile );
34203442 }
34213443 }
@@ -3511,7 +3533,7 @@ os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd,
35113533}
35123534
35133535
3514- #ifdef HAVE_FCHMOD
3536+ #if defined( HAVE_FCHMOD ) || defined( MS_WINDOWS )
35153537/*[clinic input]
35163538os.fchmod
35173539
@@ -3533,23 +3555,33 @@ os_fchmod_impl(PyObject *module, int fd, int mode)
35333555/*[clinic end generated code: output=afd9bc05b4e426b3 input=b5594618bbbc22df]*/
35343556{
35353557 int res ;
3536- int async_err = 0 ;
35373558
35383559 if (PySys_Audit ("os.chmod" , "iii" , fd , mode , -1 ) < 0 ) {
35393560 return NULL ;
35403561 }
35413562
3563+ #ifdef MS_WINDOWS
3564+ res = 0 ;
3565+ Py_BEGIN_ALLOW_THREADS
3566+ res = win32_fchmod (fd , mode );
3567+ Py_END_ALLOW_THREADS
3568+ if (!res ) {
3569+ return PyErr_SetFromWindowsErr (0 );
3570+ }
3571+ #else /* MS_WINDOWS */
3572+ int async_err = 0 ;
35423573 do {
35433574 Py_BEGIN_ALLOW_THREADS
35443575 res = fchmod (fd , mode );
35453576 Py_END_ALLOW_THREADS
35463577 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
35473578 if (res != 0 )
35483579 return (!async_err ) ? posix_error () : NULL ;
3580+ #endif /* MS_WINDOWS */
35493581
35503582 Py_RETURN_NONE ;
35513583}
3552- #endif /* HAVE_FCHMOD */
3584+ #endif /* HAVE_FCHMOD || MS_WINDOWS */
35533585
35543586
35553587#if defined(HAVE_LCHMOD ) || defined(MS_WINDOWS )
0 commit comments