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 "../futils.h"
15 #include "repository.h"
23 #ifndef FILE_NAME_NORMALIZED
24 # define FILE_NAME_NORMALIZED 0
27 #ifndef IO_REPARSE_TAG_SYMLINK
28 #define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
31 #ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
32 # define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x02
35 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
36 # define SYMBOLIC_LINK_FLAG_DIRECTORY 0x01
39 /* Allowable mode bits on Win32. Using mode bits that are not supported on
40 * Win32 (eg S_IRWXU) is generally ignored, but Wine warns loudly about it
41 * so we simply remove them.
43 #define WIN32_MODE_MASK (_S_IREAD | _S_IWRITE)
45 unsigned long git_win32__createfile_sharemode
=
46 FILE_SHARE_READ
| FILE_SHARE_WRITE
;
47 int git_win32__retries
= 10;
49 GIT_INLINE(void) set_errno(void)
51 switch (GetLastError()) {
52 case ERROR_FILE_NOT_FOUND
:
53 case ERROR_PATH_NOT_FOUND
:
54 case ERROR_INVALID_DRIVE
:
55 case ERROR_NO_MORE_FILES
:
56 case ERROR_BAD_NETPATH
:
57 case ERROR_BAD_NET_NAME
:
58 case ERROR_BAD_PATHNAME
:
59 case ERROR_FILENAME_EXCED_RANGE
:
62 case ERROR_BAD_ENVIRONMENT
:
65 case ERROR_BAD_FORMAT
:
66 case ERROR_INVALID_STARTING_CODESEG
:
67 case ERROR_INVALID_STACKSEG
:
68 case ERROR_INVALID_MODULETYPE
:
69 case ERROR_INVALID_EXE_SIGNATURE
:
70 case ERROR_EXE_MARKED_INVALID
:
71 case ERROR_BAD_EXE_FORMAT
:
72 case ERROR_ITERATED_DATA_EXCEEDS_64k
:
73 case ERROR_INVALID_MINALLOCSIZE
:
74 case ERROR_DYNLINK_FROM_INVALID_RING
:
75 case ERROR_IOPL_NOT_ENABLED
:
76 case ERROR_INVALID_SEGDPL
:
77 case ERROR_AUTODATASEG_EXCEEDS_64k
:
78 case ERROR_RING2SEG_MUST_BE_MOVABLE
:
79 case ERROR_RELOC_CHAIN_XEEDS_SEGLIM
:
80 case ERROR_INFLOOP_IN_RELOC_CHAIN
:
83 case ERROR_INVALID_HANDLE
:
84 case ERROR_INVALID_TARGET_HANDLE
:
85 case ERROR_DIRECT_ACCESS_HANDLE
:
88 case ERROR_WAIT_NO_CHILDREN
:
89 case ERROR_CHILD_NOT_COMPLETE
:
92 case ERROR_NO_PROC_SLOTS
:
93 case ERROR_MAX_THRDS_REACHED
:
94 case ERROR_NESTING_NOT_ALLOWED
:
97 case ERROR_ARENA_TRASHED
:
98 case ERROR_NOT_ENOUGH_MEMORY
:
99 case ERROR_INVALID_BLOCK
:
100 case ERROR_NOT_ENOUGH_QUOTA
:
103 case ERROR_ACCESS_DENIED
:
104 case ERROR_CURRENT_DIRECTORY
:
105 case ERROR_WRITE_PROTECT
:
107 case ERROR_NOT_READY
:
108 case ERROR_BAD_COMMAND
:
110 case ERROR_BAD_LENGTH
:
112 case ERROR_NOT_DOS_DISK
:
113 case ERROR_SECTOR_NOT_FOUND
:
114 case ERROR_OUT_OF_PAPER
:
115 case ERROR_WRITE_FAULT
:
116 case ERROR_READ_FAULT
:
117 case ERROR_GEN_FAILURE
:
118 case ERROR_SHARING_VIOLATION
:
119 case ERROR_LOCK_VIOLATION
:
120 case ERROR_WRONG_DISK
:
121 case ERROR_SHARING_BUFFER_EXCEEDED
:
122 case ERROR_NETWORK_ACCESS_DENIED
:
123 case ERROR_CANNOT_MAKE
:
125 case ERROR_DRIVE_LOCKED
:
126 case ERROR_SEEK_ON_DEVICE
:
127 case ERROR_NOT_LOCKED
:
128 case ERROR_LOCK_FAILED
:
131 case ERROR_FILE_EXISTS
:
132 case ERROR_ALREADY_EXISTS
:
135 case ERROR_NOT_SAME_DEVICE
:
138 case ERROR_INVALID_FUNCTION
:
139 case ERROR_INVALID_ACCESS
:
140 case ERROR_INVALID_DATA
:
141 case ERROR_INVALID_PARAMETER
:
142 case ERROR_NEGATIVE_SEEK
:
145 case ERROR_TOO_MANY_OPEN_FILES
:
148 case ERROR_DISK_FULL
:
151 case ERROR_BROKEN_PIPE
:
154 case ERROR_DIR_NOT_EMPTY
:
162 GIT_INLINE(bool) last_error_retryable(void)
164 int os_error
= GetLastError();
166 return (os_error
== ERROR_SHARING_VIOLATION
||
167 os_error
== ERROR_ACCESS_DENIED
);
170 #define do_with_retries(fn, remediation) \
172 int __retry, __ret; \
173 for (__retry = git_win32__retries; __retry; __retry--) { \
174 if ((__ret = (fn)) != GIT_RETRY) \
176 if (__retry > 1 && (__ret = (remediation)) != 0) { \
177 if (__ret == GIT_RETRY) \
186 static int ensure_writable(wchar_t *path)
190 if ((attrs
= GetFileAttributesW(path
)) == INVALID_FILE_ATTRIBUTES
)
193 if ((attrs
& FILE_ATTRIBUTE_READONLY
) == 0)
196 if (!SetFileAttributesW(path
, (attrs
& ~FILE_ATTRIBUTE_READONLY
)))
207 * Truncate or extend file.
209 * We now take a "git_off_t" rather than "long" because
210 * files may be longer than 2Gb.
212 int p_ftruncate(int fd
, off64_t size
)
219 #if !defined(__MINGW32__) || defined(MINGW_HAS_SECURE_API)
220 return ((_chsize_s(fd
, size
) == 0) ? 0 : -1);
222 /* TODO MINGW32 Find a replacement for _chsize() that handles big files. */
223 if (size
> INT32_MAX
) {
227 return _chsize(fd
, (long)size
);
231 int p_mkdir(const char *path
, mode_t mode
)
237 if (git_win32_path_from_utf8(buf
, path
) < 0)
243 int p_link(const char *old
, const char *new)
251 GIT_INLINE(int) unlink_once(const wchar_t *path
)
255 if (DeleteFileW(path
))
258 if ((error
= GetLastError()) == ERROR_ACCESS_DENIED
) {
259 WIN32_FILE_ATTRIBUTE_DATA fdata
;
260 if (!GetFileAttributesExW(path
, GetFileExInfoStandard
, &fdata
) ||
261 !(fdata
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) ||
262 !(fdata
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
265 if (RemoveDirectoryW(path
))
272 if (last_error_retryable())
279 int p_unlink(const char *path
)
281 git_win32_path wpath
;
283 if (git_win32_path_from_utf8(wpath
, path
) < 0)
286 do_with_retries(unlink_once(wpath
), ensure_writable(wpath
));
291 HANDLE fh
= (HANDLE
)_get_osfhandle(fd
);
295 if (fh
== INVALID_HANDLE_VALUE
) {
300 if (!FlushFileBuffers(fh
)) {
301 DWORD code
= GetLastError();
303 if (code
== ERROR_INVALID_HANDLE
)
314 #define WIN32_IS_WSEP(CH) ((CH) == L'/' || (CH) == L'\\')
321 WIN32_FILE_ATTRIBUTE_DATA fdata
;
323 if (GetFileAttributesExW(path
, GetFileExInfoStandard
, &fdata
)) {
327 return git_win32__file_attribute_to_stat(buf
, &fdata
, path
);
330 switch (GetLastError()) {
331 case ERROR_ACCESS_DENIED
:
339 /* To match POSIX behavior, set ENOTDIR when any of the folders in the
340 * file path is a regular file, otherwise set ENOENT.
342 if (errno
== ENOENT
&& posix_enotdir
) {
343 size_t path_len
= wcslen(path
);
345 /* scan up path until we find an existing item */
349 /* remove last directory component */
350 for (path_len
--; path_len
> 0 && !WIN32_IS_WSEP(path
[path_len
]); path_len
--);
355 path
[path_len
] = L
'\0';
356 attrs
= GetFileAttributesW(path
);
358 if (attrs
!= INVALID_FILE_ATTRIBUTES
) {
359 if (!(attrs
& FILE_ATTRIBUTE_DIRECTORY
))
369 static int do_lstat(const char *path
, struct stat
*buf
, bool posixly_correct
)
371 git_win32_path path_w
;
374 if ((len
= git_win32_path_from_utf8(path_w
, path
)) < 0)
377 git_win32_path_trim_end(path_w
, len
);
379 return lstat_w(path_w
, buf
, posixly_correct
);
382 int p_lstat(const char *filename
, struct stat
*buf
)
384 return do_lstat(filename
, buf
, false);
387 int p_lstat_posixly(const char *filename
, struct stat
*buf
)
389 return do_lstat(filename
, buf
, true);
392 int p_readlink(const char *path
, char *buf
, size_t bufsiz
)
394 git_win32_path path_w
, target_w
;
395 git_win32_utf8_path target
;
398 /* readlink(2) does not NULL-terminate the string written
399 * to the target buffer. Furthermore, the target buffer need
400 * not be large enough to hold the entire result. A truncated
401 * result should be written in this case. Since this truncation
402 * could occur in the middle of the encoding of a code point,
403 * we need to buffer the result on the stack. */
405 if (git_win32_path_from_utf8(path_w
, path
) < 0 ||
406 git_win32_path_readlink_w(target_w
, path_w
) < 0 ||
407 (len
= git_win32_path_to_utf8(target
, target_w
)) < 0)
410 bufsiz
= min((size_t)len
, bufsiz
);
411 memcpy(buf
, target
, bufsiz
);
416 static bool target_is_dir(const char *target
, const char *path
)
418 git_buf resolved
= GIT_BUF_INIT
;
419 git_win32_path resolved_w
;
422 if (git_path_is_absolute(target
))
423 git_win32_path_from_utf8(resolved_w
, target
);
424 else if (git_path_dirname_r(&resolved
, path
) < 0 ||
425 git_path_apply_relative(&resolved
, target
) < 0 ||
426 git_win32_path_from_utf8(resolved_w
, resolved
.ptr
) < 0)
429 isdir
= GetFileAttributesW(resolved_w
) & FILE_ATTRIBUTE_DIRECTORY
;
432 git_buf_dispose(&resolved
);
436 int p_symlink(const char *target
, const char *path
)
438 git_win32_path target_w
, path_w
;
442 * Convert both target and path to Windows-style paths. Note that we do
443 * not want to use `git_win32_path_from_utf8` for converting the target,
444 * as that function will automatically pre-pend the current working
445 * directory in case the path is not absolute. As Git will instead use
446 * relative symlinks, this is not someting we want.
448 if (git_win32_path_from_utf8(path_w
, path
) < 0 ||
449 git_win32_path_relative_from_utf8(target_w
, target
) < 0)
452 dwFlags
= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
;
453 if (target_is_dir(target
, path
))
454 dwFlags
|= SYMBOLIC_LINK_FLAG_DIRECTORY
;
456 if (!CreateSymbolicLinkW(path_w
, target_w
, dwFlags
))
465 SECURITY_ATTRIBUTES security
;
466 DWORD creation_disposition
;
471 GIT_INLINE(void) open_opts_from_posix(struct open_opts
*opts
, int flags
, mode_t mode
)
473 memset(opts
, 0, sizeof(struct open_opts
));
475 switch (flags
& (O_WRONLY
| O_RDWR
)) {
477 opts
->access
= GENERIC_WRITE
;
480 opts
->access
= GENERIC_READ
| GENERIC_WRITE
;
483 opts
->access
= GENERIC_READ
;
487 opts
->sharing
= (DWORD
)git_win32__createfile_sharemode
;
489 switch (flags
& (O_CREAT
| O_TRUNC
| O_EXCL
)) {
490 case O_CREAT
| O_EXCL
:
491 case O_CREAT
| O_TRUNC
| O_EXCL
:
492 opts
->creation_disposition
= CREATE_NEW
;
494 case O_CREAT
| O_TRUNC
:
495 opts
->creation_disposition
= CREATE_ALWAYS
;
498 opts
->creation_disposition
= TRUNCATE_EXISTING
;
501 opts
->creation_disposition
= OPEN_ALWAYS
;
504 opts
->creation_disposition
= OPEN_EXISTING
;
508 opts
->attributes
= ((flags
& O_CREAT
) && !(mode
& S_IWRITE
)) ?
509 FILE_ATTRIBUTE_READONLY
: FILE_ATTRIBUTE_NORMAL
;
510 opts
->osf_flags
= flags
& (O_RDONLY
| O_APPEND
);
512 opts
->security
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
513 opts
->security
.lpSecurityDescriptor
= NULL
;
514 opts
->security
.bInheritHandle
= 0;
517 GIT_INLINE(int) open_once(
519 struct open_opts
*opts
)
523 HANDLE handle
= CreateFileW(path
, opts
->access
, opts
->sharing
,
524 &opts
->security
, opts
->creation_disposition
, opts
->attributes
, 0);
526 if (handle
== INVALID_HANDLE_VALUE
) {
527 if (last_error_retryable())
534 if ((fd
= _open_osfhandle((intptr_t)handle
, opts
->osf_flags
)) < 0)
540 int p_open(const char *path
, int flags
, ...)
542 git_win32_path wpath
;
544 struct open_opts opts
= {0};
546 #ifdef GIT_DEBUG_STRICT_OPEN
547 if (strstr(path
, "//") != NULL
) {
553 if (git_win32_path_from_utf8(wpath
, path
) < 0)
556 if (flags
& O_CREAT
) {
559 va_start(arg_list
, flags
);
560 mode
= (mode_t
)va_arg(arg_list
, int);
564 open_opts_from_posix(&opts
, flags
, mode
);
567 open_once(wpath
, &opts
),
571 int p_creat(const char *path
, mode_t mode
)
573 return p_open(path
, O_WRONLY
| O_CREAT
| O_TRUNC
, mode
);
576 int p_utimes(const char *path
, const struct p_timeval times
[2])
578 git_win32_path wpath
;
580 DWORD attrs_orig
, attrs_new
= 0;
581 struct open_opts opts
= { 0 };
583 if (git_win32_path_from_utf8(wpath
, path
) < 0)
586 attrs_orig
= GetFileAttributesW(wpath
);
588 if (attrs_orig
& FILE_ATTRIBUTE_READONLY
) {
589 attrs_new
= attrs_orig
& ~FILE_ATTRIBUTE_READONLY
;
591 if (!SetFileAttributesW(wpath
, attrs_new
)) {
592 git_error_set(GIT_ERROR_OS
, "failed to set attributes");
597 open_opts_from_posix(&opts
, O_RDWR
, 0);
599 if ((fd
= open_once(wpath
, &opts
)) < 0) {
604 error
= p_futimes(fd
, times
);
608 if (attrs_orig
!= attrs_new
) {
609 DWORD os_error
= GetLastError();
610 SetFileAttributesW(wpath
, attrs_orig
);
611 SetLastError(os_error
);
617 int p_futimes(int fd
, const struct p_timeval times
[2])
620 FILETIME atime
= { 0 }, mtime
= { 0 };
626 SystemTimeToFileTime(&st
, &atime
);
627 SystemTimeToFileTime(&st
, &mtime
);
630 git_win32__timeval_to_filetime(&atime
, times
[0]);
631 git_win32__timeval_to_filetime(&mtime
, times
[1]);
634 if ((handle
= (HANDLE
)_get_osfhandle(fd
)) == INVALID_HANDLE_VALUE
)
637 if (SetFileTime(handle
, NULL
, &atime
, &mtime
) == 0)
643 int p_getcwd(char *buffer_out
, size_t size
)
646 wchar_t *cwd
= _wgetcwd(buf
, GIT_WIN_PATH_UTF16
);
651 git_win32_path_remove_namespace(cwd
, wcslen(cwd
));
653 /* Convert the working directory back to UTF-8 */
654 if (git__utf16_to_8(buffer_out
, size
, cwd
) < 0) {
655 DWORD code
= GetLastError();
657 if (code
== ERROR_INSUFFICIENT_BUFFER
)
665 git_path_mkposix(buffer_out
);
669 static int getfinalpath_w(
676 /* Use FILE_FLAG_BACKUP_SEMANTICS so we can open a directory. Do not
677 * specify FILE_FLAG_OPEN_REPARSE_POINT; we want to open a handle to the
678 * target of the link. */
679 hFile
= CreateFileW(path
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_DELETE
,
680 NULL
, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
682 if (INVALID_HANDLE_VALUE
== hFile
)
685 /* Call GetFinalPathNameByHandle */
686 dwChars
= GetFinalPathNameByHandleW(hFile
, dest
, GIT_WIN_PATH_UTF16
, FILE_NAME_NORMALIZED
);
689 if (!dwChars
|| dwChars
>= GIT_WIN_PATH_UTF16
)
692 /* The path may be delivered to us with a namespace prefix; remove */
693 return (int)git_win32_path_remove_namespace(dest
, dwChars
);
696 static int follow_and_lstat_link(git_win32_path path
, struct stat
*buf
)
698 git_win32_path target_w
;
700 if (getfinalpath_w(target_w
, path
) < 0)
703 return lstat_w(target_w
, buf
, false);
706 int p_fstat(int fd
, struct stat
*buf
)
708 BY_HANDLE_FILE_INFORMATION fhInfo
;
710 HANDLE fh
= (HANDLE
)_get_osfhandle(fd
);
712 if (fh
== INVALID_HANDLE_VALUE
||
713 !GetFileInformationByHandle(fh
, &fhInfo
)) {
718 git_win32__file_information_to_stat(buf
, &fhInfo
);
722 int p_stat(const char *path
, struct stat
*buf
)
724 git_win32_path path_w
;
727 if ((len
= git_win32_path_from_utf8(path_w
, path
)) < 0 ||
728 lstat_w(path_w
, buf
, false) < 0)
731 /* The item is a symbolic link or mount point. No need to iterate
732 * to follow multiple links; use GetFinalPathNameFromHandle. */
733 if (S_ISLNK(buf
->st_mode
))
734 return follow_and_lstat_link(path_w
, buf
);
739 int p_chdir(const char *path
)
743 if (git_win32_path_from_utf8(buf
, path
) < 0)
749 int p_chmod(const char *path
, mode_t mode
)
753 if (git_win32_path_from_utf8(buf
, path
) < 0)
756 return _wchmod(buf
, mode
);
759 int p_rmdir(const char *path
)
764 if (git_win32_path_from_utf8(buf
, path
) < 0)
767 error
= _wrmdir(buf
);
770 switch (GetLastError()) {
771 /* _wrmdir() is documented to return EACCES if "A program has an open
772 * handle to the directory." This sounds like what everybody else calls
773 * EBUSY. Let's convert appropriate error codes.
775 case ERROR_SHARING_VIOLATION
:
779 /* This error can be returned when trying to rmdir an extant file. */
780 case ERROR_DIRECTORY
:
789 char *p_realpath(const char *orig_path
, char *buffer
)
791 git_win32_path orig_path_w
, buffer_w
;
793 if (git_win32_path_from_utf8(orig_path_w
, orig_path
) < 0)
796 /* Note that if the path provided is a relative path, then the current directory
797 * is used to resolve the path -- which is a concurrency issue because the current
798 * directory is a process-wide variable. */
799 if (!GetFullPathNameW(orig_path_w
, GIT_WIN_PATH_UTF16
, buffer_w
, NULL
)) {
800 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
801 errno
= ENAMETOOLONG
;
808 /* The path must exist. */
809 if (GetFileAttributesW(buffer_w
) == INVALID_FILE_ATTRIBUTES
) {
814 if (!buffer
&& !(buffer
= git__malloc(GIT_WIN_PATH_UTF8
))) {
819 /* Convert the path to UTF-8. If the caller provided a buffer, then it
820 * is assumed to be GIT_WIN_PATH_UTF8 characters in size. If it isn't,
821 * then we may overflow. */
822 if (git_win32_path_to_utf8(buffer
, buffer_w
) < 0)
825 git_path_mkposix(buffer
);
830 int p_vsnprintf(char *buffer
, size_t count
, const char *format
, va_list argptr
)
832 #if defined(_MSC_VER)
836 return _vscprintf(format
, argptr
);
839 len
= _vsnprintf_s(buffer
, count
, _TRUNCATE
, format
, argptr
);
841 len
= _vsnprintf(buffer
, count
, format
, argptr
);
845 return _vscprintf(format
, argptr
);
849 return vsnprintf(buffer
, count
, format
, argptr
);
853 int p_snprintf(char *buffer
, size_t count
, const char *format
, ...)
858 va_start(va
, format
);
859 r
= p_vsnprintf(buffer
, count
, format
, va
);
866 int p_mkstemp(char *tmp_path
)
868 #if defined(_MSC_VER) && _MSC_VER >= 1500
869 if (_mktemp_s(tmp_path
, strlen(tmp_path
) + 1) != 0)
872 if (_mktemp(tmp_path
) == NULL
)
876 return p_open(tmp_path
, O_RDWR
| O_CREAT
| O_EXCL
, 0744); /* -V536 */
879 int p_access(const char *path
, mode_t mode
)
883 if (git_win32_path_from_utf8(buf
, path
) < 0)
886 return _waccess(buf
, mode
& WIN32_MODE_MASK
);
889 GIT_INLINE(int) rename_once(const wchar_t *from
, const wchar_t *to
)
891 if (MoveFileExW(from
, to
, MOVEFILE_REPLACE_EXISTING
| MOVEFILE_COPY_ALLOWED
))
894 if (last_error_retryable())
901 int p_rename(const char *from
, const char *to
)
903 git_win32_path wfrom
, wto
;
905 if (git_win32_path_from_utf8(wfrom
, from
) < 0 ||
906 git_win32_path_from_utf8(wto
, to
) < 0)
909 do_with_retries(rename_once(wfrom
, wto
), ensure_writable(wto
));
912 int p_recv(GIT_SOCKET socket
, void *buffer
, size_t length
, int flags
)
914 if ((size_t)((int)length
) != length
)
915 return -1; /* git_error_set will be done by caller */
917 return recv(socket
, buffer
, (int)length
, flags
);
920 int p_send(GIT_SOCKET socket
, const void *buffer
, size_t length
, int flags
)
922 if ((size_t)((int)length
) != length
)
923 return -1; /* git_error_set will be done by caller */
925 return send(socket
, buffer
, (int)length
, flags
);
929 * Borrowed from http://old.nabble.com/Porting-localtime_r-and-gmtime_r-td15282276.html
930 * On Win32, `gmtime_r` doesn't exist but `gmtime` is threadsafe, so we can use that
933 p_localtime_r (const time_t *timer
, struct tm
*result
)
935 struct tm
*local_result
;
936 local_result
= localtime (timer
);
938 if (local_result
== NULL
|| result
== NULL
)
941 memcpy (result
, local_result
, sizeof (struct tm
));
945 p_gmtime_r (const time_t *timer
, struct tm
*result
)
947 struct tm
*local_result
;
948 local_result
= gmtime (timer
);
950 if (local_result
== NULL
|| result
== NULL
)
953 memcpy (result
, local_result
, sizeof (struct tm
));
957 int p_inet_pton(int af
, const char *src
, void *dst
)
959 struct sockaddr_storage sin
;
961 int sin_len
= sizeof(struct sockaddr_storage
), addr_len
;
965 addr
= &((struct sockaddr_in
*)&sin
)->sin_addr
;
966 addr_len
= sizeof(struct in_addr
);
967 } else if (af
== AF_INET6
) {
968 addr
= &((struct sockaddr_in6
*)&sin
)->sin6_addr
;
969 addr_len
= sizeof(struct in6_addr
);
971 errno
= EAFNOSUPPORT
;
975 if ((error
= WSAStringToAddressA((LPSTR
)src
, af
, NULL
, (LPSOCKADDR
)&sin
, &sin_len
)) == 0) {
976 memcpy(dst
, addr
, addr_len
);
980 switch(WSAGetLastError()) {
986 case WSA_NOT_ENOUGH_MEMORY
:
995 ssize_t
p_pread(int fd
, void *data
, size_t size
, off64_t offset
)
1000 LARGE_INTEGER pos
= {0};
1001 off64_t final_offset
= 0;
1003 /* Fail if the final offset would have overflowed to match POSIX semantics. */
1004 if (!git__is_ssizet(size
) || git__add_int64_overflow(&final_offset
, offset
, (int64_t)size
)) {
1010 * Truncate large writes to the maximum allowable size: the caller
1011 * needs to always call this in a loop anyways.
1013 if (size
> INT32_MAX
) {
1017 pos
.QuadPart
= offset
;
1018 ov
.Offset
= pos
.LowPart
;
1019 ov
.OffsetHigh
= pos
.HighPart
;
1020 fh
= (HANDLE
)_get_osfhandle(fd
);
1022 if (ReadFile(fh
, data
, (DWORD
)size
, &rsize
, &ov
)) {
1023 return (ssize_t
)rsize
;
1030 ssize_t
p_pwrite(int fd
, const void *data
, size_t size
, off64_t offset
)
1034 OVERLAPPED ov
= {0};
1035 LARGE_INTEGER pos
= {0};
1036 off64_t final_offset
= 0;
1038 /* Fail if the final offset would have overflowed to match POSIX semantics. */
1039 if (!git__is_ssizet(size
) || git__add_int64_overflow(&final_offset
, offset
, (int64_t)size
)) {
1045 * Truncate large writes to the maximum allowable size: the caller
1046 * needs to always call this in a loop anyways.
1048 if (size
> INT32_MAX
) {
1052 pos
.QuadPart
= offset
;
1053 ov
.Offset
= pos
.LowPart
;
1054 ov
.OffsetHigh
= pos
.HighPart
;
1055 fh
= (HANDLE
)_get_osfhandle(fd
);
1057 if (WriteFile(fh
, data
, (DWORD
)size
, &wsize
, &ov
)) {
1058 return (ssize_t
)wsize
;