2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
11 #include "../fileops.h"
15 #include "repository.h"
24 #ifndef FILE_NAME_NORMALIZED
25 # define FILE_NAME_NORMALIZED 0
28 #ifndef IO_REPARSE_TAG_SYMLINK
29 #define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
32 /* Allowable mode bits on Win32. Using mode bits that are not supported on
33 * Win32 (eg S_IRWXU) is generally ignored, but Wine warns loudly about it
34 * so we simply remove them.
36 #define WIN32_MODE_MASK (_S_IREAD | _S_IWRITE)
38 /* GetFinalPathNameByHandleW signature */
39 typedef DWORD(WINAPI
*PFGetFinalPathNameByHandleW
)(HANDLE
, LPWSTR
, DWORD
, DWORD
);
41 unsigned long git_win32__createfile_sharemode
=
42 FILE_SHARE_READ
| FILE_SHARE_WRITE
;
43 int git_win32__retries
= 10;
45 GIT_INLINE(void) set_errno(void)
47 switch (GetLastError()) {
48 case ERROR_FILE_NOT_FOUND
:
49 case ERROR_PATH_NOT_FOUND
:
50 case ERROR_INVALID_DRIVE
:
51 case ERROR_NO_MORE_FILES
:
52 case ERROR_BAD_NETPATH
:
53 case ERROR_BAD_NET_NAME
:
54 case ERROR_BAD_PATHNAME
:
55 case ERROR_FILENAME_EXCED_RANGE
:
58 case ERROR_BAD_ENVIRONMENT
:
61 case ERROR_BAD_FORMAT
:
62 case ERROR_INVALID_STARTING_CODESEG
:
63 case ERROR_INVALID_STACKSEG
:
64 case ERROR_INVALID_MODULETYPE
:
65 case ERROR_INVALID_EXE_SIGNATURE
:
66 case ERROR_EXE_MARKED_INVALID
:
67 case ERROR_BAD_EXE_FORMAT
:
68 case ERROR_ITERATED_DATA_EXCEEDS_64k
:
69 case ERROR_INVALID_MINALLOCSIZE
:
70 case ERROR_DYNLINK_FROM_INVALID_RING
:
71 case ERROR_IOPL_NOT_ENABLED
:
72 case ERROR_INVALID_SEGDPL
:
73 case ERROR_AUTODATASEG_EXCEEDS_64k
:
74 case ERROR_RING2SEG_MUST_BE_MOVABLE
:
75 case ERROR_RELOC_CHAIN_XEEDS_SEGLIM
:
76 case ERROR_INFLOOP_IN_RELOC_CHAIN
:
79 case ERROR_INVALID_HANDLE
:
80 case ERROR_INVALID_TARGET_HANDLE
:
81 case ERROR_DIRECT_ACCESS_HANDLE
:
84 case ERROR_WAIT_NO_CHILDREN
:
85 case ERROR_CHILD_NOT_COMPLETE
:
88 case ERROR_NO_PROC_SLOTS
:
89 case ERROR_MAX_THRDS_REACHED
:
90 case ERROR_NESTING_NOT_ALLOWED
:
93 case ERROR_ARENA_TRASHED
:
94 case ERROR_NOT_ENOUGH_MEMORY
:
95 case ERROR_INVALID_BLOCK
:
96 case ERROR_NOT_ENOUGH_QUOTA
:
99 case ERROR_ACCESS_DENIED
:
100 case ERROR_CURRENT_DIRECTORY
:
101 case ERROR_WRITE_PROTECT
:
103 case ERROR_NOT_READY
:
104 case ERROR_BAD_COMMAND
:
106 case ERROR_BAD_LENGTH
:
108 case ERROR_NOT_DOS_DISK
:
109 case ERROR_SECTOR_NOT_FOUND
:
110 case ERROR_OUT_OF_PAPER
:
111 case ERROR_WRITE_FAULT
:
112 case ERROR_READ_FAULT
:
113 case ERROR_GEN_FAILURE
:
114 case ERROR_SHARING_VIOLATION
:
115 case ERROR_LOCK_VIOLATION
:
116 case ERROR_WRONG_DISK
:
117 case ERROR_SHARING_BUFFER_EXCEEDED
:
118 case ERROR_NETWORK_ACCESS_DENIED
:
119 case ERROR_CANNOT_MAKE
:
121 case ERROR_DRIVE_LOCKED
:
122 case ERROR_SEEK_ON_DEVICE
:
123 case ERROR_NOT_LOCKED
:
124 case ERROR_LOCK_FAILED
:
127 case ERROR_FILE_EXISTS
:
128 case ERROR_ALREADY_EXISTS
:
131 case ERROR_NOT_SAME_DEVICE
:
134 case ERROR_INVALID_FUNCTION
:
135 case ERROR_INVALID_ACCESS
:
136 case ERROR_INVALID_DATA
:
137 case ERROR_INVALID_PARAMETER
:
138 case ERROR_NEGATIVE_SEEK
:
141 case ERROR_TOO_MANY_OPEN_FILES
:
144 case ERROR_DISK_FULL
:
147 case ERROR_BROKEN_PIPE
:
150 case ERROR_DIR_NOT_EMPTY
:
158 GIT_INLINE(bool) last_error_retryable(void)
160 int os_error
= GetLastError();
162 return (os_error
== ERROR_SHARING_VIOLATION
||
163 os_error
== ERROR_ACCESS_DENIED
);
166 #define do_with_retries(fn, remediation) \
168 int __retry, __ret; \
169 for (__retry = git_win32__retries; __retry; __retry--) { \
170 if ((__ret = (fn)) != GIT_RETRY) \
172 if (__retry > 1 && (__ret = (remediation)) != 0) { \
173 if (__ret == GIT_RETRY) \
182 static int ensure_writable(wchar_t *path)
186 if ((attrs
= GetFileAttributesW(path
)) == INVALID_FILE_ATTRIBUTES
)
189 if ((attrs
& FILE_ATTRIBUTE_READONLY
) == 0)
192 if (!SetFileAttributesW(path
, (attrs
& ~FILE_ATTRIBUTE_READONLY
)))
203 * Truncate or extend file.
205 * We now take a "git_off_t" rather than "long" because
206 * files may be longer than 2Gb.
208 int p_ftruncate(int fd
, git_off_t size
)
215 #if !defined(__MINGW32__) || defined(MINGW_HAS_SECURE_API)
216 return ((_chsize_s(fd
, size
) == 0) ? 0 : -1);
218 /* TODO MINGW32 Find a replacement for _chsize() that handles big files. */
219 if (size
> INT32_MAX
) {
223 return _chsize(fd
, (long)size
);
227 int p_mkdir(const char *path
, mode_t mode
)
233 if (git_win32_path_from_utf8(buf
, path
) < 0)
239 int p_link(const char *old
, const char *new)
247 GIT_INLINE(int) unlink_once(const wchar_t *path
)
249 if (DeleteFileW(path
))
252 if (last_error_retryable())
259 int p_unlink(const char *path
)
261 git_win32_path wpath
;
263 if (git_win32_path_from_utf8(wpath
, path
) < 0)
266 do_with_retries(unlink_once(wpath
), ensure_writable(wpath
));
271 HANDLE fh
= (HANDLE
)_get_osfhandle(fd
);
275 if (fh
== INVALID_HANDLE_VALUE
) {
280 if (!FlushFileBuffers(fh
)) {
281 DWORD code
= GetLastError();
283 if (code
== ERROR_INVALID_HANDLE
)
294 #define WIN32_IS_WSEP(CH) ((CH) == L'/' || (CH) == L'\\')
301 WIN32_FILE_ATTRIBUTE_DATA fdata
;
303 if (GetFileAttributesExW(path
, GetFileExInfoStandard
, &fdata
)) {
307 return git_win32__file_attribute_to_stat(buf
, &fdata
, path
);
310 switch (GetLastError()) {
311 case ERROR_ACCESS_DENIED
:
319 /* To match POSIX behavior, set ENOTDIR when any of the folders in the
320 * file path is a regular file, otherwise set ENOENT.
322 if (errno
== ENOENT
&& posix_enotdir
) {
323 size_t path_len
= wcslen(path
);
325 /* scan up path until we find an existing item */
329 /* remove last directory component */
330 for (path_len
--; path_len
> 0 && !WIN32_IS_WSEP(path
[path_len
]); path_len
--);
335 path
[path_len
] = L
'\0';
336 attrs
= GetFileAttributesW(path
);
338 if (attrs
!= INVALID_FILE_ATTRIBUTES
) {
339 if (!(attrs
& FILE_ATTRIBUTE_DIRECTORY
))
349 static int do_lstat(const char *path
, struct stat
*buf
, bool posixly_correct
)
351 git_win32_path path_w
;
354 if ((len
= git_win32_path_from_utf8(path_w
, path
)) < 0)
357 git_win32__path_trim_end(path_w
, len
);
359 return lstat_w(path_w
, buf
, posixly_correct
);
362 int p_lstat(const char *filename
, struct stat
*buf
)
364 return do_lstat(filename
, buf
, false);
367 int p_lstat_posixly(const char *filename
, struct stat
*buf
)
369 return do_lstat(filename
, buf
, true);
372 int p_readlink(const char *path
, char *buf
, size_t bufsiz
)
374 git_win32_path path_w
, target_w
;
375 git_win32_utf8_path target
;
378 /* readlink(2) does not NULL-terminate the string written
379 * to the target buffer. Furthermore, the target buffer need
380 * not be large enough to hold the entire result. A truncated
381 * result should be written in this case. Since this truncation
382 * could occur in the middle of the encoding of a code point,
383 * we need to buffer the result on the stack. */
385 if (git_win32_path_from_utf8(path_w
, path
) < 0 ||
386 git_win32_path_readlink_w(target_w
, path_w
) < 0 ||
387 (len
= git_win32_path_to_utf8(target
, target_w
)) < 0)
390 bufsiz
= min((size_t)len
, bufsiz
);
391 memcpy(buf
, target
, bufsiz
);
396 int p_symlink(const char *old
, const char *new)
398 /* Real symlinks on NTFS require admin privileges. Until this changes,
399 * libgit2 just creates a text file with the link target in the contents.
401 return git_futils_fake_symlink(old
, new);
407 SECURITY_ATTRIBUTES security
;
408 DWORD creation_disposition
;
413 GIT_INLINE(void) open_opts_from_posix(struct open_opts
*opts
, int flags
, mode_t mode
)
415 memset(opts
, 0, sizeof(struct open_opts
));
417 switch (flags
& (O_WRONLY
| O_RDWR
)) {
419 opts
->access
= GENERIC_WRITE
;
422 opts
->access
= GENERIC_READ
| GENERIC_WRITE
;
425 opts
->access
= GENERIC_READ
;
429 opts
->sharing
= (DWORD
)git_win32__createfile_sharemode
;
431 switch (flags
& (O_CREAT
| O_TRUNC
| O_EXCL
)) {
432 case O_CREAT
| O_EXCL
:
433 case O_CREAT
| O_TRUNC
| O_EXCL
:
434 opts
->creation_disposition
= CREATE_NEW
;
436 case O_CREAT
| O_TRUNC
:
437 opts
->creation_disposition
= CREATE_ALWAYS
;
440 opts
->creation_disposition
= TRUNCATE_EXISTING
;
443 opts
->creation_disposition
= OPEN_ALWAYS
;
446 opts
->creation_disposition
= OPEN_EXISTING
;
450 opts
->attributes
= ((flags
& O_CREAT
) && !(mode
& S_IWRITE
)) ?
451 FILE_ATTRIBUTE_READONLY
: FILE_ATTRIBUTE_NORMAL
;
452 opts
->osf_flags
= flags
& (O_RDONLY
| O_APPEND
);
454 opts
->security
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
455 opts
->security
.lpSecurityDescriptor
= NULL
;
456 opts
->security
.bInheritHandle
= 0;
459 GIT_INLINE(int) open_once(
461 struct open_opts
*opts
)
465 HANDLE handle
= CreateFileW(path
, opts
->access
, opts
->sharing
,
466 &opts
->security
, opts
->creation_disposition
, opts
->attributes
, 0);
468 if (handle
== INVALID_HANDLE_VALUE
) {
469 if (last_error_retryable())
476 if ((fd
= _open_osfhandle((intptr_t)handle
, opts
->osf_flags
)) < 0)
482 int p_open(const char *path
, int flags
, ...)
484 git_win32_path wpath
;
486 struct open_opts opts
= {0};
488 if (git_win32_path_from_utf8(wpath
, path
) < 0)
491 if (flags
& O_CREAT
) {
494 va_start(arg_list
, flags
);
495 mode
= (mode_t
)va_arg(arg_list
, int);
499 open_opts_from_posix(&opts
, flags
, mode
);
502 open_once(wpath
, &opts
),
506 int p_creat(const char *path
, mode_t mode
)
508 return p_open(path
, O_WRONLY
| O_CREAT
| O_TRUNC
, mode
);
511 int p_utimes(const char *path
, const struct p_timeval times
[2])
513 git_win32_path wpath
;
515 DWORD attrs_orig
, attrs_new
= 0;
516 struct open_opts opts
= { 0 };
518 if (git_win32_path_from_utf8(wpath
, path
) < 0)
521 attrs_orig
= GetFileAttributesW(wpath
);
523 if (attrs_orig
& FILE_ATTRIBUTE_READONLY
) {
524 attrs_new
= attrs_orig
& ~FILE_ATTRIBUTE_READONLY
;
526 if (!SetFileAttributesW(wpath
, attrs_new
)) {
527 giterr_set(GITERR_OS
, "failed to set attributes");
532 open_opts_from_posix(&opts
, O_RDWR
, 0);
534 if ((fd
= open_once(wpath
, &opts
)) < 0) {
539 error
= p_futimes(fd
, times
);
543 if (attrs_orig
!= attrs_new
) {
544 DWORD os_error
= GetLastError();
545 SetFileAttributesW(wpath
, attrs_orig
);
546 SetLastError(os_error
);
552 int p_futimes(int fd
, const struct p_timeval times
[2])
555 FILETIME atime
= { 0 }, mtime
= { 0 };
561 SystemTimeToFileTime(&st
, &atime
);
562 SystemTimeToFileTime(&st
, &mtime
);
565 git_win32__timeval_to_filetime(&atime
, times
[0]);
566 git_win32__timeval_to_filetime(&mtime
, times
[1]);
569 if ((handle
= (HANDLE
)_get_osfhandle(fd
)) == INVALID_HANDLE_VALUE
)
572 if (SetFileTime(handle
, NULL
, &atime
, &mtime
) == 0)
578 int p_getcwd(char *buffer_out
, size_t size
)
581 wchar_t *cwd
= _wgetcwd(buf
, GIT_WIN_PATH_UTF16
);
586 /* Convert the working directory back to UTF-8 */
587 if (git__utf16_to_8(buffer_out
, size
, cwd
) < 0) {
588 DWORD code
= GetLastError();
590 if (code
== ERROR_INSUFFICIENT_BUFFER
)
602 * Returns the address of the GetFinalPathNameByHandleW function.
603 * This function is available on Windows Vista and higher.
605 static PFGetFinalPathNameByHandleW
get_fpnbyhandle(void)
607 static PFGetFinalPathNameByHandleW pFunc
= NULL
;
608 PFGetFinalPathNameByHandleW toReturn
= pFunc
;
611 HMODULE hModule
= GetModuleHandleW(L
"kernel32");
614 toReturn
= (PFGetFinalPathNameByHandleW
)GetProcAddress(hModule
, "GetFinalPathNameByHandleW");
624 static int getfinalpath_w(
628 PFGetFinalPathNameByHandleW pgfp
= get_fpnbyhandle();
635 /* Use FILE_FLAG_BACKUP_SEMANTICS so we can open a directory. Do not
636 * specify FILE_FLAG_OPEN_REPARSE_POINT; we want to open a handle to the
637 * target of the link. */
638 hFile
= CreateFileW(path
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_DELETE
,
639 NULL
, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
641 if (INVALID_HANDLE_VALUE
== hFile
)
644 /* Call GetFinalPathNameByHandle */
645 dwChars
= pgfp(hFile
, dest
, GIT_WIN_PATH_UTF16
, FILE_NAME_NORMALIZED
);
648 if (!dwChars
|| dwChars
>= GIT_WIN_PATH_UTF16
)
651 /* The path may be delivered to us with a prefix; canonicalize */
652 return (int)git_win32__canonicalize_path(dest
, dwChars
);
655 static int follow_and_lstat_link(git_win32_path path
, struct stat
* buf
)
657 git_win32_path target_w
;
659 if (getfinalpath_w(target_w
, path
) < 0)
662 return lstat_w(target_w
, buf
, false);
665 int p_fstat(int fd
, struct stat
*buf
)
667 BY_HANDLE_FILE_INFORMATION fhInfo
;
669 HANDLE fh
= (HANDLE
)_get_osfhandle(fd
);
671 if (fh
== INVALID_HANDLE_VALUE
||
672 !GetFileInformationByHandle(fh
, &fhInfo
)) {
677 git_win32__file_information_to_stat(buf
, &fhInfo
);
681 int p_stat(const char* path
, struct stat
* buf
)
683 git_win32_path path_w
;
686 if ((len
= git_win32_path_from_utf8(path_w
, path
)) < 0 ||
687 lstat_w(path_w
, buf
, false) < 0)
690 /* The item is a symbolic link or mount point. No need to iterate
691 * to follow multiple links; use GetFinalPathNameFromHandle. */
692 if (S_ISLNK(buf
->st_mode
))
693 return follow_and_lstat_link(path_w
, buf
);
698 int p_chdir(const char* path
)
702 if (git_win32_path_from_utf8(buf
, path
) < 0)
708 int p_chmod(const char* path
, mode_t mode
)
712 if (git_win32_path_from_utf8(buf
, path
) < 0)
715 return _wchmod(buf
, mode
);
718 int p_rmdir(const char* path
)
723 if (git_win32_path_from_utf8(buf
, path
) < 0)
726 error
= _wrmdir(buf
);
729 switch (GetLastError()) {
730 /* _wrmdir() is documented to return EACCES if "A program has an open
731 * handle to the directory." This sounds like what everybody else calls
732 * EBUSY. Let's convert appropriate error codes.
734 case ERROR_SHARING_VIOLATION
:
738 /* This error can be returned when trying to rmdir an extant file. */
739 case ERROR_DIRECTORY
:
748 char *p_realpath(const char *orig_path
, char *buffer
)
750 git_win32_path orig_path_w
, buffer_w
;
752 if (git_win32_path_from_utf8(orig_path_w
, orig_path
) < 0)
755 /* Note that if the path provided is a relative path, then the current directory
756 * is used to resolve the path -- which is a concurrency issue because the current
757 * directory is a process-wide variable. */
758 if (!GetFullPathNameW(orig_path_w
, GIT_WIN_PATH_UTF16
, buffer_w
, NULL
)) {
759 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
760 errno
= ENAMETOOLONG
;
767 /* The path must exist. */
768 if (GetFileAttributesW(buffer_w
) == INVALID_FILE_ATTRIBUTES
) {
773 if (!buffer
&& !(buffer
= git__malloc(GIT_WIN_PATH_UTF8
))) {
778 /* Convert the path to UTF-8. If the caller provided a buffer, then it
779 * is assumed to be GIT_WIN_PATH_UTF8 characters in size. If it isn't,
780 * then we may overflow. */
781 if (git_win32_path_to_utf8(buffer
, buffer_w
) < 0)
784 git_path_mkposix(buffer
);
789 int p_vsnprintf(char *buffer
, size_t count
, const char *format
, va_list argptr
)
791 #if defined(_MSC_VER)
795 return _vscprintf(format
, argptr
);
798 len
= _vsnprintf_s(buffer
, count
, _TRUNCATE
, format
, argptr
);
800 len
= _vsnprintf(buffer
, count
, format
, argptr
);
804 return _vscprintf(format
, argptr
);
808 return vsnprintf(buffer
, count
, format
, argptr
);
812 int p_snprintf(char *buffer
, size_t count
, const char *format
, ...)
817 va_start(va
, format
);
818 r
= p_vsnprintf(buffer
, count
, format
, va
);
825 int p_mkstemp(char *tmp_path
)
827 #if defined(_MSC_VER) && _MSC_VER >= 1500
828 if (_mktemp_s(tmp_path
, strlen(tmp_path
) + 1) != 0)
831 if (_mktemp(tmp_path
) == NULL
)
835 return p_open(tmp_path
, O_RDWR
| O_CREAT
| O_EXCL
, 0744); //-V536
838 int p_access(const char* path
, mode_t mode
)
842 if (git_win32_path_from_utf8(buf
, path
) < 0)
845 return _waccess(buf
, mode
& WIN32_MODE_MASK
);
848 GIT_INLINE(int) rename_once(const wchar_t *from
, const wchar_t *to
)
850 if (MoveFileExW(from
, to
, MOVEFILE_REPLACE_EXISTING
| MOVEFILE_COPY_ALLOWED
))
853 if (last_error_retryable())
860 int p_rename(const char *from
, const char *to
)
862 git_win32_path wfrom
, wto
;
864 if (git_win32_path_from_utf8(wfrom
, from
) < 0 ||
865 git_win32_path_from_utf8(wto
, to
) < 0)
868 do_with_retries(rename_once(wfrom
, wto
), ensure_writable(wto
));
871 int p_recv(GIT_SOCKET socket
, void *buffer
, size_t length
, int flags
)
873 if ((size_t)((int)length
) != length
)
874 return -1; /* giterr_set will be done by caller */
876 return recv(socket
, buffer
, (int)length
, flags
);
879 int p_send(GIT_SOCKET socket
, const void *buffer
, size_t length
, int flags
)
881 if ((size_t)((int)length
) != length
)
882 return -1; /* giterr_set will be done by caller */
884 return send(socket
, buffer
, (int)length
, flags
);
888 * Borrowed from http://old.nabble.com/Porting-localtime_r-and-gmtime_r-td15282276.html
889 * On Win32, `gmtime_r` doesn't exist but `gmtime` is threadsafe, so we can use that
892 p_localtime_r (const time_t *timer
, struct tm
*result
)
894 struct tm
*local_result
;
895 local_result
= localtime (timer
);
897 if (local_result
== NULL
|| result
== NULL
)
900 memcpy (result
, local_result
, sizeof (struct tm
));
904 p_gmtime_r (const time_t *timer
, struct tm
*result
)
906 struct tm
*local_result
;
907 local_result
= gmtime (timer
);
909 if (local_result
== NULL
|| result
== NULL
)
912 memcpy (result
, local_result
, sizeof (struct tm
));
916 int p_inet_pton(int af
, const char *src
, void *dst
)
918 struct sockaddr_storage sin
;
920 int sin_len
= sizeof(struct sockaddr_storage
), addr_len
;
924 addr
= &((struct sockaddr_in
*)&sin
)->sin_addr
;
925 addr_len
= sizeof(struct in_addr
);
926 } else if (af
== AF_INET6
) {
927 addr
= &((struct sockaddr_in6
*)&sin
)->sin6_addr
;
928 addr_len
= sizeof(struct in6_addr
);
930 errno
= EAFNOSUPPORT
;
934 if ((error
= WSAStringToAddressA((LPSTR
)src
, af
, NULL
, (LPSOCKADDR
)&sin
, &sin_len
)) == 0) {
935 memcpy(dst
, addr
, addr_len
);
939 switch(WSAGetLastError()) {
945 case WSA_NOT_ENOUGH_MEMORY
: