@@ -363,44 +363,6 @@ int p_lstat_posixly(const char *filename, struct stat *buf)
363363 return do_lstat (filename , buf , true);
364364}
365365
366- int p_utimes (const char * filename , const struct p_timeval times [2 ])
367- {
368- int fd , error ;
369-
370- if ((fd = p_open (filename , O_RDWR )) < 0 )
371- return fd ;
372-
373- error = p_futimes (fd , times );
374-
375- close (fd );
376- return error ;
377- }
378-
379- int p_futimes (int fd , const struct p_timeval times [2 ])
380- {
381- HANDLE handle ;
382- FILETIME atime = {0 }, mtime = {0 };
383-
384- if (times == NULL ) {
385- SYSTEMTIME st ;
386-
387- GetSystemTime (& st );
388- SystemTimeToFileTime (& st , & atime );
389- SystemTimeToFileTime (& st , & mtime );
390- } else {
391- git_win32__timeval_to_filetime (& atime , times [0 ]);
392- git_win32__timeval_to_filetime (& mtime , times [1 ]);
393- }
394-
395- if ((handle = (HANDLE )_get_osfhandle (fd )) == INVALID_HANDLE_VALUE )
396- return -1 ;
397-
398- if (SetFileTime (handle , NULL , & atime , & mtime ) == 0 )
399- return -1 ;
400-
401- return 0 ;
402- }
403-
404366int p_readlink (const char * path , char * buf , size_t bufsiz )
405367{
406368 git_win32_path path_w , target_w ;
@@ -433,23 +395,69 @@ int p_symlink(const char *old, const char *new)
433395 return git_futils_fake_symlink (old , new );
434396}
435397
398+ struct open_opts {
399+ DWORD access ;
400+ DWORD sharing ;
401+ SECURITY_ATTRIBUTES security ;
402+ DWORD creation_disposition ;
403+ DWORD attributes ;
404+ int osf_flags ;
405+ };
406+
407+ GIT_INLINE (void ) open_opts_from_posix (struct open_opts * opts , int flags , mode_t mode )
408+ {
409+ memset (opts , 0 , sizeof (struct open_opts ));
410+
411+ switch (flags & (O_WRONLY | O_RDWR )) {
412+ case O_WRONLY :
413+ opts -> access = GENERIC_WRITE ;
414+ break ;
415+ case O_RDWR :
416+ opts -> access = GENERIC_READ | GENERIC_WRITE ;
417+ break ;
418+ default :
419+ opts -> access = GENERIC_READ ;
420+ break ;
421+ }
422+
423+ opts -> sharing = (DWORD )git_win32__createfile_sharemode ;
424+
425+ switch (flags & (O_CREAT | O_TRUNC | O_EXCL )) {
426+ case O_CREAT | O_EXCL :
427+ case O_CREAT | O_TRUNC | O_EXCL :
428+ opts -> creation_disposition = CREATE_NEW ;
429+ break ;
430+ case O_CREAT | O_TRUNC :
431+ opts -> creation_disposition = CREATE_ALWAYS ;
432+ break ;
433+ case O_TRUNC :
434+ opts -> creation_disposition = TRUNCATE_EXISTING ;
435+ break ;
436+ case O_CREAT :
437+ opts -> creation_disposition = OPEN_ALWAYS ;
438+ break ;
439+ default :
440+ opts -> creation_disposition = OPEN_EXISTING ;
441+ break ;
442+ }
443+
444+ opts -> attributes = ((flags & O_CREAT ) && !(mode & S_IWRITE )) ?
445+ FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL ;
446+ opts -> osf_flags = flags & (O_RDONLY | O_APPEND );
447+
448+ opts -> security .nLength = sizeof (SECURITY_ATTRIBUTES );
449+ opts -> security .lpSecurityDescriptor = NULL ;
450+ opts -> security .bInheritHandle = 0 ;
451+ }
452+
436453GIT_INLINE (int ) open_once (
437454 const wchar_t * path ,
438- DWORD access ,
439- DWORD sharing ,
440- DWORD creation_disposition ,
441- DWORD attributes ,
442- int osf_flags )
455+ struct open_opts * opts )
443456{
444- SECURITY_ATTRIBUTES security ;
445457 int fd ;
446458
447- security .nLength = sizeof (SECURITY_ATTRIBUTES );
448- security .lpSecurityDescriptor = NULL ;
449- security .bInheritHandle = 0 ;
450-
451- HANDLE handle = CreateFileW (path , access , sharing , & security ,
452- creation_disposition , attributes , 0 );
459+ HANDLE handle = CreateFileW (path , opts -> access , opts -> sharing ,
460+ & opts -> security , opts -> creation_disposition , opts -> attributes , 0 );
453461
454462 if (handle == INVALID_HANDLE_VALUE ) {
455463 if (last_error_retryable ())
@@ -459,14 +467,17 @@ GIT_INLINE(int) open_once(
459467 return -1 ;
460468 }
461469
462- return _open_osfhandle ((intptr_t )handle , osf_flags );
470+ if ((fd = _open_osfhandle ((intptr_t )handle , opts -> osf_flags )) < 0 )
471+ CloseHandle (handle );
472+
473+ return fd ;
463474}
464475
465476int p_open (const char * path , int flags , ...)
466477{
467478 git_win32_path wpath ;
468479 mode_t mode = 0 ;
469- DWORD access , sharing , creation , attributes , osf_flags ;
480+ struct open_opts opts = { 0 } ;
470481
471482 if (git_win32_path_from_utf8 (wpath , path ) < 0 )
472483 return -1 ;
@@ -479,51 +490,83 @@ int p_open(const char *path, int flags, ...)
479490 va_end (arg_list );
480491 }
481492
482- switch (flags & (O_WRONLY | O_RDWR )) {
483- case O_WRONLY :
484- access = GENERIC_WRITE ;
485- break ;
486- case O_RDWR :
487- access = GENERIC_READ | GENERIC_WRITE ;
488- break ;
489- default :
490- access = GENERIC_READ ;
491- break ;
493+ open_opts_from_posix (& opts , flags , mode );
494+
495+ do_with_retries (
496+ open_once (wpath , & opts ),
497+ 0 );
498+ }
499+
500+ int p_creat (const char * path , mode_t mode )
501+ {
502+ return p_open (path , O_WRONLY | O_CREAT | O_TRUNC , mode );
503+ }
504+
505+ int p_utimes (const char * path , const struct p_timeval times [2 ])
506+ {
507+ git_win32_path wpath ;
508+ int fd , error ;
509+ DWORD attrs_orig , attrs_new = 0 ;
510+ struct open_opts opts = { 0 };
511+
512+ if (git_win32_path_from_utf8 (wpath , path ) < 0 )
513+ return -1 ;
514+
515+ attrs_orig = GetFileAttributesW (wpath );
516+
517+ if (attrs_orig & FILE_ATTRIBUTE_READONLY ) {
518+ attrs_new = attrs_orig & ~FILE_ATTRIBUTE_READONLY ;
519+
520+ if (!SetFileAttributesW (wpath , attrs_new )) {
521+ giterr_set (GITERR_OS , "failed to set attributes" );
522+ return -1 ;
523+ }
492524 }
493525
494- sharing = ( DWORD ) git_win32__createfile_sharemode ;
526+ open_opts_from_posix ( & opts , O_RDWR , 0 ) ;
495527
496- switch (flags & (O_CREAT | O_TRUNC | O_EXCL )) {
497- case O_CREAT | O_EXCL :
498- case O_CREAT | O_TRUNC | O_EXCL :
499- creation = CREATE_NEW ;
500- break ;
501- case O_CREAT | O_TRUNC :
502- creation = CREATE_ALWAYS ;
503- break ;
504- case O_TRUNC :
505- creation = TRUNCATE_EXISTING ;
506- break ;
507- case O_CREAT :
508- creation = OPEN_ALWAYS ;
509- break ;
510- default :
511- creation = OPEN_EXISTING ;
512- break ;
528+ if ((fd = open_once (wpath , & opts )) < 0 ) {
529+ error = -1 ;
530+ goto done ;
513531 }
514532
515- attributes = ((flags & O_CREAT ) && !(mode & S_IWRITE )) ?
516- FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL ;
517- osf_flags = flags & (O_RDONLY | O_APPEND );
533+ error = p_futimes (fd , times );
534+ close (fd );
518535
519- do_with_retries (
520- open_once (wpath , access , sharing , creation , attributes , osf_flags ),
521- 0 );
536+ done :
537+ if (attrs_orig != attrs_new ) {
538+ DWORD os_error = GetLastError ();
539+ SetFileAttributesW (wpath , attrs_orig );
540+ SetLastError (os_error );
541+ }
542+
543+ return error ;
522544}
523545
524- int p_creat ( const char * path , mode_t mode )
546+ int p_futimes ( int fd , const struct p_timeval times [ 2 ] )
525547{
526- return p_open (path , O_WRONLY | O_CREAT | O_TRUNC , mode );
548+ HANDLE handle ;
549+ FILETIME atime = { 0 }, mtime = { 0 };
550+
551+ if (times == NULL ) {
552+ SYSTEMTIME st ;
553+
554+ GetSystemTime (& st );
555+ SystemTimeToFileTime (& st , & atime );
556+ SystemTimeToFileTime (& st , & mtime );
557+ }
558+ else {
559+ git_win32__timeval_to_filetime (& atime , times [0 ]);
560+ git_win32__timeval_to_filetime (& mtime , times [1 ]);
561+ }
562+
563+ if ((handle = (HANDLE )_get_osfhandle (fd )) == INVALID_HANDLE_VALUE )
564+ return -1 ;
565+
566+ if (SetFileTime (handle , NULL , & atime , & mtime ) == 0 )
567+ return -1 ;
568+
569+ return 0 ;
527570}
528571
529572int p_getcwd (char * buffer_out , size_t size )
0 commit comments