summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/repository.c66
-rw-r--r--src/win32/posix_w32.c54
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)