diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/repository.c | 66 | ||||
| -rw-r--r-- | src/win32/posix_w32.c | 54 |
3 files changed, 69 insertions, 53 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 157ce8000..8ba3aa590 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -423,7 +423,7 @@ FILE(GLOB SRC_H # On Windows use specific platform sources IF (WIN32 AND NOT CYGWIN) - ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0501) + ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0600) IF(MSVC) SET(WIN_RC "win32/git2.rc") diff --git a/src/repository.c b/src/repository.c index a2f88a283..490388051 100644 --- a/src/repository.c +++ b/src/repository.c @@ -944,18 +944,20 @@ static int load_config( git_buf config_path = GIT_BUF_INIT; git_config *cfg = NULL; - assert(repo && out); + assert(out); if ((error = git_config_new(&cfg)) < 0) return error; - if ((error = git_repository_item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0) - error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, repo, 0); + if (repo) { + if ((error = git_repository_item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0) + error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, repo, 0); - if (error && error != GIT_ENOTFOUND) - goto on_error; + if (error && error != GIT_ENOTFOUND) + goto on_error; - git_buf_dispose(&config_path); + git_buf_dispose(&config_path); + } if (global_config_path != NULL && (error = git_config_add_file_ondisk( @@ -1411,24 +1413,56 @@ static bool is_filesystem_case_insensitive(const char *gitdir_path) static bool are_symlinks_supported(const char *wd_path) { + git_config *config = NULL; git_buf path = GIT_BUF_INIT; int fd; struct stat st; - int symlinks_supported = -1; + bool symlinks = false; + + /* + * To emulate Git for Windows, symlinks on Windows must be explicitly + * opted-in. We examine the system configuration for a core.symlinks + * set to true. If found, we then examine the filesystem to see if + * symlinks are _actually_ supported by the current user. If that is + * _not_ set, then we do not test or enable symlink support. + */ +#ifdef GIT_WIN32 + git_buf global_buf = GIT_BUF_INIT; + git_buf xdg_buf = GIT_BUF_INIT; + git_buf system_buf = GIT_BUF_INIT; + git_buf programdata_buf = GIT_BUF_INIT; + + git_config_find_global(&global_buf); + git_config_find_xdg(&xdg_buf); + git_config_find_system(&system_buf); + git_config_find_programdata(&programdata_buf); + + if (load_config(&config, NULL, + path_unless_empty(&global_buf), + path_unless_empty(&xdg_buf), + path_unless_empty(&system_buf), + path_unless_empty(&programdata_buf)) < 0) + goto done; + + if (git_config_get_bool(&symlinks, config, "core.symlinks") < 0 || !symlinks) + goto done; +#endif if ((fd = git_futils_mktmp(&path, wd_path, 0666)) < 0 || - p_close(fd) < 0 || - p_unlink(path.ptr) < 0 || - p_symlink("testing", path.ptr) < 0 || - p_lstat(path.ptr, &st) < 0) - symlinks_supported = false; - else - symlinks_supported = (S_ISLNK(st.st_mode) != 0); + p_close(fd) < 0 || + p_unlink(path.ptr) < 0 || + p_symlink("testing", path.ptr) < 0 || + p_lstat(path.ptr, &st) < 0) + goto done; + + symlinks = (S_ISLNK(st.st_mode) != 0); (void)p_unlink(path.ptr); - git_buf_dispose(&path); - return symlinks_supported; +done: + git_buf_dispose(&path); + git_config_free(config); + return symlinks; } static int create_empty_file(const char *path, mode_t mode) diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 8c321ef3c..5d144936b 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -29,15 +29,16 @@ #define IO_REPARSE_TAG_SYMLINK (0xA000000CL) #endif +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x02 +#endif + /* 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. */ #define WIN32_MODE_MASK (_S_IREAD | _S_IWRITE) -/* 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; @@ -393,12 +394,20 @@ int p_readlink(const char *path, char *buf, size_t bufsiz) return (int)bufsiz; } -int p_symlink(const char *old, const char *new) +int p_symlink(const char *target, const char *path) { - /* Real symlinks on NTFS require admin privileges. Until this changes, - * libgit2 just creates a text file with the link target in the contents. - */ - return git_futils_fake_symlink(old, new); + git_win32_path target_w, path_w; + wchar_t *target_p; + + if (git_win32_path_from_utf8(path_w, path) < 0 || + git__utf8_to_16(target_w, MAX_PATH, target) < 0) + return -1; + + if (!CreateSymbolicLinkW(path_w, target_w, + SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) + return -1; + + return 0; } struct open_opts { @@ -598,40 +607,13 @@ int p_getcwd(char *buffer_out, size_t size) return 0; } -/* - * Returns the address of the GetFinalPathNameByHandleW function. - * This function is available on Windows Vista and higher. - */ -static PFGetFinalPathNameByHandleW get_fpnbyhandle(void) -{ - static PFGetFinalPathNameByHandleW pFunc = NULL; - PFGetFinalPathNameByHandleW toReturn = pFunc; - - if (!toReturn) { - HMODULE hModule = GetModuleHandleW(L"kernel32"); - - if (hModule) - toReturn = (PFGetFinalPathNameByHandleW)GetProcAddress(hModule, "GetFinalPathNameByHandleW"); - - pFunc = toReturn; - } - - assert(toReturn); - - return toReturn; -} - static int getfinalpath_w( git_win32_path dest, const wchar_t *path) { - PFGetFinalPathNameByHandleW pgfp = get_fpnbyhandle(); HANDLE hFile; DWORD dwChars; - if (!pgfp) - return -1; - /* Use FILE_FLAG_BACKUP_SEMANTICS so we can open a directory. Do not * specify FILE_FLAG_OPEN_REPARSE_POINT; we want to open a handle to the * target of the link. */ @@ -642,7 +624,7 @@ static int getfinalpath_w( return -1; /* Call GetFinalPathNameByHandle */ - dwChars = pgfp(hFile, dest, GIT_WIN_PATH_UTF16, FILE_NAME_NORMALIZED); + dwChars = GetFinalPathNameByHandleW(hFile, dest, GIT_WIN_PATH_UTF16, FILE_NAME_NORMALIZED); CloseHandle(hFile); if (!dwChars || dwChars >= GIT_WIN_PATH_UTF16) |
