mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-28 17:17:08 +00:00
Merge pull request #4192 from libgit2/ethomson/win32_posix
Refactor some of the win32 POSIX emulation
This commit is contained in:
commit
8d89e40961
@ -9,6 +9,10 @@ v0.25 + 1
|
||||
|
||||
### API additions
|
||||
|
||||
* You can now set the default share mode on Windows for opening files using
|
||||
`GIT_OPT_SET_WINDOWS_SHAREMODE` option with `git_libgit2_opts()`.
|
||||
You can query the current share mode with `GIT_OPT_GET_WINDOWS_SHAREMODE`.
|
||||
|
||||
### API removals
|
||||
|
||||
### Breaking API changes
|
||||
|
@ -180,6 +180,8 @@ typedef enum {
|
||||
GIT_OPT_GET_USER_AGENT,
|
||||
GIT_OPT_ENABLE_OFS_DELTA,
|
||||
GIT_OPT_ENABLE_SYNCHRONOUS_OBJECT_CREATION,
|
||||
GIT_OPT_GET_WINDOWS_SHAREMODE,
|
||||
GIT_OPT_SET_WINDOWS_SHAREMODE,
|
||||
} git_libgit2_opt_t;
|
||||
|
||||
/**
|
||||
@ -284,6 +286,17 @@ typedef enum {
|
||||
* > - `user_agent` is the value that will be delivered as the
|
||||
* > User-Agent header on HTTP requests.
|
||||
*
|
||||
* * opts(GIT_OPT_SET_WINDOWS_SHAREMODE, unsigned long value)
|
||||
*
|
||||
* > Set the share mode used when opening files on Windows.
|
||||
* > For more information, see the documentation for CreateFile.
|
||||
* > The default is: FILE_SHARE_READ | FILE_SHARE_WRITE. This is
|
||||
* > ignored and unused on non-Windows platforms.
|
||||
*
|
||||
* * opts(GIT_OPT_GET_WINDOWS_SHAREMODE, unsigned long *value)
|
||||
*
|
||||
* > Get the share mode used when opening files on Windows.
|
||||
*
|
||||
* * opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, int enabled)
|
||||
*
|
||||
* > Enable strict input validation when creating new objects
|
||||
|
@ -53,6 +53,7 @@ typedef enum {
|
||||
|
||||
GIT_PASSTHROUGH = -30, /**< Internal only */
|
||||
GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */
|
||||
GIT_RETRY = -32, /**< Internal only */
|
||||
} git_error_code;
|
||||
|
||||
/**
|
||||
|
@ -24,6 +24,10 @@
|
||||
#define _S_IFLNK S_IFLNK
|
||||
#endif
|
||||
|
||||
#ifndef S_IWUSR
|
||||
#define S_IWUSR 00200
|
||||
#endif
|
||||
|
||||
#ifndef S_IXUSR
|
||||
#define S_IXUSR 00100
|
||||
#endif
|
||||
|
@ -231,6 +231,18 @@ int git_libgit2_opts(int key, ...)
|
||||
git_object__synchronous_writing = (va_arg(ap, int) != 0);
|
||||
break;
|
||||
|
||||
case GIT_OPT_GET_WINDOWS_SHAREMODE:
|
||||
#ifdef GIT_WIN32
|
||||
*(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case GIT_OPT_SET_WINDOWS_SHAREMODE:
|
||||
#ifdef GIT_WIN32
|
||||
git_win32__createfile_sharemode = va_arg(ap, unsigned long);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
giterr_set(GITERR_INVALID, "invalid option key");
|
||||
error = -1;
|
||||
|
@ -14,6 +14,9 @@
|
||||
#include "utf-conv.h"
|
||||
#include "dir.h"
|
||||
|
||||
extern unsigned long git_win32__createfile_sharemode;
|
||||
extern int git_win32__retries;
|
||||
|
||||
typedef SOCKET GIT_SOCKET;
|
||||
|
||||
#define p_lseek(f,n,w) _lseeki64(f, n, w)
|
||||
|
@ -26,15 +26,6 @@
|
||||
#define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
|
||||
#endif
|
||||
|
||||
/* Options which we always provide to _wopen.
|
||||
*
|
||||
* _O_BINARY - Raw access; no translation of CR or LF characters
|
||||
* _O_NOINHERIT - Do not mark the created handle as inheritable by child processes.
|
||||
* The Windows default is 'not inheritable', but the CRT's default (following
|
||||
* POSIX convention) is 'inheritable'. We have no desire for our handles to be
|
||||
* inheritable on Windows, so specify the flag to get default behavior back. */
|
||||
#define STANDARD_OPEN_FLAGS (_O_BINARY | _O_NOINHERIT)
|
||||
|
||||
/* Allowable mode bits on Win32. Using mode bits that are not supported on
|
||||
* Win32 (eg S_IRWXU) is generally ignored, but Wine warns loudly about it
|
||||
* so we simply remove them.
|
||||
@ -44,6 +35,164 @@
|
||||
/* GetFinalPathNameByHandleW signature */
|
||||
typedef DWORD(WINAPI *PFGetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD, DWORD);
|
||||
|
||||
unsigned long git_win32__createfile_sharemode =
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
int git_win32__retries = 10;
|
||||
|
||||
GIT_INLINE(void) set_errno(void)
|
||||
{
|
||||
switch (GetLastError()) {
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
case ERROR_INVALID_DRIVE:
|
||||
case ERROR_NO_MORE_FILES:
|
||||
case ERROR_BAD_NETPATH:
|
||||
case ERROR_BAD_NET_NAME:
|
||||
case ERROR_BAD_PATHNAME:
|
||||
case ERROR_FILENAME_EXCED_RANGE:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case ERROR_BAD_ENVIRONMENT:
|
||||
errno = E2BIG;
|
||||
break;
|
||||
case ERROR_BAD_FORMAT:
|
||||
case ERROR_INVALID_STARTING_CODESEG:
|
||||
case ERROR_INVALID_STACKSEG:
|
||||
case ERROR_INVALID_MODULETYPE:
|
||||
case ERROR_INVALID_EXE_SIGNATURE:
|
||||
case ERROR_EXE_MARKED_INVALID:
|
||||
case ERROR_BAD_EXE_FORMAT:
|
||||
case ERROR_ITERATED_DATA_EXCEEDS_64k:
|
||||
case ERROR_INVALID_MINALLOCSIZE:
|
||||
case ERROR_DYNLINK_FROM_INVALID_RING:
|
||||
case ERROR_IOPL_NOT_ENABLED:
|
||||
case ERROR_INVALID_SEGDPL:
|
||||
case ERROR_AUTODATASEG_EXCEEDS_64k:
|
||||
case ERROR_RING2SEG_MUST_BE_MOVABLE:
|
||||
case ERROR_RELOC_CHAIN_XEEDS_SEGLIM:
|
||||
case ERROR_INFLOOP_IN_RELOC_CHAIN:
|
||||
errno = ENOEXEC;
|
||||
break;
|
||||
case ERROR_INVALID_HANDLE:
|
||||
case ERROR_INVALID_TARGET_HANDLE:
|
||||
case ERROR_DIRECT_ACCESS_HANDLE:
|
||||
errno = EBADF;
|
||||
break;
|
||||
case ERROR_WAIT_NO_CHILDREN:
|
||||
case ERROR_CHILD_NOT_COMPLETE:
|
||||
errno = ECHILD;
|
||||
break;
|
||||
case ERROR_NO_PROC_SLOTS:
|
||||
case ERROR_MAX_THRDS_REACHED:
|
||||
case ERROR_NESTING_NOT_ALLOWED:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
case ERROR_ARENA_TRASHED:
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
case ERROR_INVALID_BLOCK:
|
||||
case ERROR_NOT_ENOUGH_QUOTA:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_CURRENT_DIRECTORY:
|
||||
case ERROR_WRITE_PROTECT:
|
||||
case ERROR_BAD_UNIT:
|
||||
case ERROR_NOT_READY:
|
||||
case ERROR_BAD_COMMAND:
|
||||
case ERROR_CRC:
|
||||
case ERROR_BAD_LENGTH:
|
||||
case ERROR_SEEK:
|
||||
case ERROR_NOT_DOS_DISK:
|
||||
case ERROR_SECTOR_NOT_FOUND:
|
||||
case ERROR_OUT_OF_PAPER:
|
||||
case ERROR_WRITE_FAULT:
|
||||
case ERROR_READ_FAULT:
|
||||
case ERROR_GEN_FAILURE:
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
case ERROR_LOCK_VIOLATION:
|
||||
case ERROR_WRONG_DISK:
|
||||
case ERROR_SHARING_BUFFER_EXCEEDED:
|
||||
case ERROR_NETWORK_ACCESS_DENIED:
|
||||
case ERROR_CANNOT_MAKE:
|
||||
case ERROR_FAIL_I24:
|
||||
case ERROR_DRIVE_LOCKED:
|
||||
case ERROR_SEEK_ON_DEVICE:
|
||||
case ERROR_NOT_LOCKED:
|
||||
case ERROR_LOCK_FAILED:
|
||||
errno = EACCES;
|
||||
break;
|
||||
case ERROR_FILE_EXISTS:
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
errno = EEXIST;
|
||||
break;
|
||||
case ERROR_NOT_SAME_DEVICE:
|
||||
errno = EXDEV;
|
||||
break;
|
||||
case ERROR_INVALID_FUNCTION:
|
||||
case ERROR_INVALID_ACCESS:
|
||||
case ERROR_INVALID_DATA:
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
case ERROR_NEGATIVE_SEEK:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case ERROR_TOO_MANY_OPEN_FILES:
|
||||
errno = EMFILE;
|
||||
break;
|
||||
case ERROR_DISK_FULL:
|
||||
errno = ENOSPC;
|
||||
break;
|
||||
case ERROR_BROKEN_PIPE:
|
||||
errno = EPIPE;
|
||||
break;
|
||||
case ERROR_DIR_NOT_EMPTY:
|
||||
errno = ENOTEMPTY;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
GIT_INLINE(bool) last_error_retryable(void)
|
||||
{
|
||||
int os_error = GetLastError();
|
||||
|
||||
return (os_error == ERROR_SHARING_VIOLATION ||
|
||||
os_error == ERROR_ACCESS_DENIED);
|
||||
}
|
||||
|
||||
#define do_with_retries(fn, remediation) \
|
||||
do { \
|
||||
int __tries, __ret; \
|
||||
for (__tries = 0; __tries < git_win32__retries; __tries++) { \
|
||||
if (__tries && (__ret = (remediation)) != 0) \
|
||||
return __ret; \
|
||||
if ((__ret = (fn)) != GIT_RETRY) \
|
||||
return __ret; \
|
||||
Sleep(5); \
|
||||
} \
|
||||
return -1; \
|
||||
} while (0) \
|
||||
|
||||
static int ensure_writable(wchar_t *path)
|
||||
{
|
||||
DWORD attrs;
|
||||
|
||||
if ((attrs = GetFileAttributesW(path)) == INVALID_FILE_ATTRIBUTES)
|
||||
goto on_error;
|
||||
|
||||
if ((attrs & FILE_ATTRIBUTE_READONLY) == 0)
|
||||
return 0;
|
||||
|
||||
if (!SetFileAttributesW(path, (attrs & ~FILE_ATTRIBUTE_READONLY)))
|
||||
goto on_error;
|
||||
|
||||
return 0;
|
||||
|
||||
on_error:
|
||||
set_errno();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate or extend file.
|
||||
*
|
||||
@ -89,24 +238,26 @@ int p_link(const char *old, const char *new)
|
||||
return -1;
|
||||
}
|
||||
|
||||
GIT_INLINE(int) unlink_once(const wchar_t *path)
|
||||
{
|
||||
if (DeleteFileW(path))
|
||||
return 0;
|
||||
|
||||
if (last_error_retryable())
|
||||
return GIT_RETRY;
|
||||
|
||||
set_errno();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int p_unlink(const char *path)
|
||||
{
|
||||
git_win32_path buf;
|
||||
int error;
|
||||
git_win32_path wpath;
|
||||
|
||||
if (git_win32_path_from_utf8(buf, path) < 0)
|
||||
if (git_win32_path_from_utf8(wpath, path) < 0)
|
||||
return -1;
|
||||
|
||||
error = _wunlink(buf);
|
||||
|
||||
/* If the file could not be deleted because it was
|
||||
* read-only, clear the bit and try again */
|
||||
if (error == -1 && errno == EACCES) {
|
||||
_wchmod(buf, 0666);
|
||||
error = _wunlink(buf);
|
||||
}
|
||||
|
||||
return error;
|
||||
do_with_retries(unlink_once(wpath), ensure_writable(wpath));
|
||||
}
|
||||
|
||||
int p_fsync(int fd)
|
||||
@ -212,44 +363,6 @@ int p_lstat_posixly(const char *filename, struct stat *buf)
|
||||
return do_lstat(filename, buf, true);
|
||||
}
|
||||
|
||||
int p_utimes(const char *filename, const struct p_timeval times[2])
|
||||
{
|
||||
int fd, error;
|
||||
|
||||
if ((fd = p_open(filename, O_RDWR)) < 0)
|
||||
return fd;
|
||||
|
||||
error = p_futimes(fd, times);
|
||||
|
||||
close(fd);
|
||||
return error;
|
||||
}
|
||||
|
||||
int p_futimes(int fd, const struct p_timeval times[2])
|
||||
{
|
||||
HANDLE handle;
|
||||
FILETIME atime = {0}, mtime = {0};
|
||||
|
||||
if (times == NULL) {
|
||||
SYSTEMTIME st;
|
||||
|
||||
GetSystemTime(&st);
|
||||
SystemTimeToFileTime(&st, &atime);
|
||||
SystemTimeToFileTime(&st, &mtime);
|
||||
} else {
|
||||
git_win32__timeval_to_filetime(&atime, times[0]);
|
||||
git_win32__timeval_to_filetime(&mtime, times[1]);
|
||||
}
|
||||
|
||||
if ((handle = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
|
||||
if (SetFileTime(handle, NULL, &atime, &mtime) == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int p_readlink(const char *path, char *buf, size_t bufsiz)
|
||||
{
|
||||
git_win32_path path_w, target_w;
|
||||
@ -282,12 +395,91 @@ int p_symlink(const char *old, const char *new)
|
||||
return git_futils_fake_symlink(old, new);
|
||||
}
|
||||
|
||||
struct open_opts {
|
||||
DWORD access;
|
||||
DWORD sharing;
|
||||
SECURITY_ATTRIBUTES security;
|
||||
DWORD creation_disposition;
|
||||
DWORD attributes;
|
||||
int osf_flags;
|
||||
};
|
||||
|
||||
GIT_INLINE(void) open_opts_from_posix(struct open_opts *opts, int flags, mode_t mode)
|
||||
{
|
||||
memset(opts, 0, sizeof(struct open_opts));
|
||||
|
||||
switch (flags & (O_WRONLY | O_RDWR)) {
|
||||
case O_WRONLY:
|
||||
opts->access = GENERIC_WRITE;
|
||||
break;
|
||||
case O_RDWR:
|
||||
opts->access = GENERIC_READ | GENERIC_WRITE;
|
||||
break;
|
||||
default:
|
||||
opts->access = GENERIC_READ;
|
||||
break;
|
||||
}
|
||||
|
||||
opts->sharing = (DWORD)git_win32__createfile_sharemode;
|
||||
|
||||
switch (flags & (O_CREAT | O_TRUNC | O_EXCL)) {
|
||||
case O_CREAT | O_EXCL:
|
||||
case O_CREAT | O_TRUNC | O_EXCL:
|
||||
opts->creation_disposition = CREATE_NEW;
|
||||
break;
|
||||
case O_CREAT | O_TRUNC:
|
||||
opts->creation_disposition = CREATE_ALWAYS;
|
||||
break;
|
||||
case O_TRUNC:
|
||||
opts->creation_disposition = TRUNCATE_EXISTING;
|
||||
break;
|
||||
case O_CREAT:
|
||||
opts->creation_disposition = OPEN_ALWAYS;
|
||||
break;
|
||||
default:
|
||||
opts->creation_disposition = OPEN_EXISTING;
|
||||
break;
|
||||
}
|
||||
|
||||
opts->attributes = ((flags & O_CREAT) && !(mode & S_IWRITE)) ?
|
||||
FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL;
|
||||
opts->osf_flags = flags & (O_RDONLY | O_APPEND);
|
||||
|
||||
opts->security.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
opts->security.lpSecurityDescriptor = NULL;
|
||||
opts->security.bInheritHandle = 0;
|
||||
}
|
||||
|
||||
GIT_INLINE(int) open_once(
|
||||
const wchar_t *path,
|
||||
struct open_opts *opts)
|
||||
{
|
||||
int fd;
|
||||
|
||||
HANDLE handle = CreateFileW(path, opts->access, opts->sharing,
|
||||
&opts->security, opts->creation_disposition, opts->attributes, 0);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
if (last_error_retryable())
|
||||
return GIT_RETRY;
|
||||
|
||||
set_errno();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fd = _open_osfhandle((intptr_t)handle, opts->osf_flags)) < 0)
|
||||
CloseHandle(handle);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int p_open(const char *path, int flags, ...)
|
||||
{
|
||||
git_win32_path buf;
|
||||
git_win32_path wpath;
|
||||
mode_t mode = 0;
|
||||
struct open_opts opts = {0};
|
||||
|
||||
if (git_win32_path_from_utf8(buf, path) < 0)
|
||||
if (git_win32_path_from_utf8(wpath, path) < 0)
|
||||
return -1;
|
||||
|
||||
if (flags & O_CREAT) {
|
||||
@ -298,19 +490,83 @@ int p_open(const char *path, int flags, ...)
|
||||
va_end(arg_list);
|
||||
}
|
||||
|
||||
return _wopen(buf, flags | STANDARD_OPEN_FLAGS, mode & WIN32_MODE_MASK);
|
||||
open_opts_from_posix(&opts, flags, mode);
|
||||
|
||||
do_with_retries(
|
||||
open_once(wpath, &opts),
|
||||
0);
|
||||
}
|
||||
|
||||
int p_creat(const char *path, mode_t mode)
|
||||
{
|
||||
git_win32_path buf;
|
||||
return p_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
|
||||
}
|
||||
|
||||
if (git_win32_path_from_utf8(buf, path) < 0)
|
||||
int p_utimes(const char *path, const struct p_timeval times[2])
|
||||
{
|
||||
git_win32_path wpath;
|
||||
int fd, error;
|
||||
DWORD attrs_orig, attrs_new = 0;
|
||||
struct open_opts opts = { 0 };
|
||||
|
||||
if (git_win32_path_from_utf8(wpath, path) < 0)
|
||||
return -1;
|
||||
|
||||
return _wopen(buf,
|
||||
_O_WRONLY | _O_CREAT | _O_TRUNC | STANDARD_OPEN_FLAGS,
|
||||
mode & WIN32_MODE_MASK);
|
||||
attrs_orig = GetFileAttributesW(wpath);
|
||||
|
||||
if (attrs_orig & FILE_ATTRIBUTE_READONLY) {
|
||||
attrs_new = attrs_orig & ~FILE_ATTRIBUTE_READONLY;
|
||||
|
||||
if (!SetFileAttributesW(wpath, attrs_new)) {
|
||||
giterr_set(GITERR_OS, "failed to set attributes");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
open_opts_from_posix(&opts, O_RDWR, 0);
|
||||
|
||||
if ((fd = open_once(wpath, &opts)) < 0) {
|
||||
error = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
error = p_futimes(fd, times);
|
||||
close(fd);
|
||||
|
||||
done:
|
||||
if (attrs_orig != attrs_new) {
|
||||
DWORD os_error = GetLastError();
|
||||
SetFileAttributesW(wpath, attrs_orig);
|
||||
SetLastError(os_error);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int p_futimes(int fd, const struct p_timeval times[2])
|
||||
{
|
||||
HANDLE handle;
|
||||
FILETIME atime = { 0 }, mtime = { 0 };
|
||||
|
||||
if (times == NULL) {
|
||||
SYSTEMTIME st;
|
||||
|
||||
GetSystemTime(&st);
|
||||
SystemTimeToFileTime(&st, &atime);
|
||||
SystemTimeToFileTime(&st, &mtime);
|
||||
}
|
||||
else {
|
||||
git_win32__timeval_to_filetime(&atime, times[0]);
|
||||
git_win32__timeval_to_filetime(&mtime, times[1]);
|
||||
}
|
||||
|
||||
if ((handle = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
|
||||
if (SetFileTime(handle, NULL, &atime, &mtime) == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int p_getcwd(char *buffer_out, size_t size)
|
||||
@ -583,62 +839,27 @@ int p_access(const char* path, mode_t mode)
|
||||
return _waccess(buf, mode & WIN32_MODE_MASK);
|
||||
}
|
||||
|
||||
static int ensure_writable(wchar_t *fpath)
|
||||
GIT_INLINE(int) rename_once(const wchar_t *from, const wchar_t *to)
|
||||
{
|
||||
DWORD attrs;
|
||||
|
||||
attrs = GetFileAttributesW(fpath);
|
||||
if (attrs == INVALID_FILE_ATTRIBUTES) {
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND)
|
||||
return 0;
|
||||
|
||||
giterr_set(GITERR_OS, "failed to get attributes");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(attrs & FILE_ATTRIBUTE_READONLY))
|
||||
if (MoveFileExW(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
|
||||
return 0;
|
||||
|
||||
attrs &= ~FILE_ATTRIBUTE_READONLY;
|
||||
if (!SetFileAttributesW(fpath, attrs)) {
|
||||
giterr_set(GITERR_OS, "failed to set attributes");
|
||||
return -1;
|
||||
}
|
||||
if (last_error_retryable())
|
||||
return GIT_RETRY;
|
||||
|
||||
return 0;
|
||||
set_errno();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int p_rename(const char *from, const char *to)
|
||||
{
|
||||
git_win32_path wfrom;
|
||||
git_win32_path wto;
|
||||
int rename_tries;
|
||||
int rename_succeeded;
|
||||
int error;
|
||||
git_win32_path wfrom, wto;
|
||||
|
||||
if (git_win32_path_from_utf8(wfrom, from) < 0 ||
|
||||
git_win32_path_from_utf8(wto, to) < 0)
|
||||
return -1;
|
||||
|
||||
/* wait up to 50ms if file is locked by another thread or process */
|
||||
rename_tries = 0;
|
||||
rename_succeeded = 0;
|
||||
while (rename_tries < 10) {
|
||||
if (ensure_writable(wto) == 0 &&
|
||||
MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0) {
|
||||
rename_succeeded = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
error = GetLastError();
|
||||
if (error == ERROR_SHARING_VIOLATION || error == ERROR_ACCESS_DENIED) {
|
||||
Sleep(5);
|
||||
rename_tries++;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
return rename_succeeded ? 0 : -1;
|
||||
do_with_retries(rename_once(wfrom, wto), ensure_writable(wto));
|
||||
}
|
||||
|
||||
int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags)
|
||||
|
@ -55,6 +55,31 @@ void test_odb_freshen__loose_blob(void)
|
||||
cl_assert(before.st_mtime < after.st_mtime);
|
||||
}
|
||||
|
||||
#define UNIQUE_STR "doesnt exist in the odb yet\n"
|
||||
#define UNIQUE_BLOB_ID "78a87d0b8878c5953b9a63015ff4e22a3d898826"
|
||||
#define UNIQUE_BLOB_FN "78/a87d0b8878c5953b9a63015ff4e22a3d898826"
|
||||
|
||||
void test_odb_freshen__readonly_object(void)
|
||||
{
|
||||
git_oid expected_id, id;
|
||||
struct stat before, after;
|
||||
|
||||
cl_git_pass(git_oid_fromstr(&expected_id, UNIQUE_BLOB_ID));
|
||||
|
||||
cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR)));
|
||||
cl_assert_equal_oid(&expected_id, &id);
|
||||
|
||||
set_time_wayback(&before, UNIQUE_BLOB_FN);
|
||||
cl_assert((before.st_mode & S_IWUSR) == 0);
|
||||
|
||||
cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR)));
|
||||
cl_assert_equal_oid(&expected_id, &id);
|
||||
cl_must_pass(p_lstat("testrepo.git/objects/" UNIQUE_BLOB_FN, &after));
|
||||
|
||||
cl_assert(before.st_atime < after.st_atime);
|
||||
cl_assert(before.st_mtime < after.st_mtime);
|
||||
}
|
||||
|
||||
#define LOOSE_TREE_ID "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"
|
||||
#define LOOSE_TREE_FN "94/4c0f6e4dfa41595e6eb3ceecdb14f50fe18162"
|
||||
|
||||
|
@ -19,12 +19,25 @@ static git_repository *_repo;
|
||||
static git_tree *_a, *_b;
|
||||
static git_atomic _counts[4];
|
||||
static int _check_counts;
|
||||
static int _retries;
|
||||
|
||||
#define THREADS 20
|
||||
|
||||
void test_threads_diff__initialize(void)
|
||||
{
|
||||
#ifdef GIT_WIN32
|
||||
_retries = git_win32__retries;
|
||||
git_win32__retries = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_threads_diff__cleanup(void)
|
||||
{
|
||||
cl_git_sandbox_cleanup();
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
git_win32__retries = _retries;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void setup_trees(void)
|
||||
|
Loading…
Reference in New Issue
Block a user