From aed8f8a101872e8b4c81de788a5e675c67b50d20 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Mon, 24 Sep 2012 18:02:47 +0200 Subject: [PATCH 01/16] Honor %HOME% on windows Use %HOME% before trying to figure out the windows user directory. Users might set this as they are used on *nix systems. Signed-off-by: Sven Strickroth --- src/fileops.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/fileops.c b/src/fileops.c index 8ccf063d5..d85ff7c72 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -455,9 +455,20 @@ int git_futils_find_system_file(git_buf *path, const char *filename) int git_futils_find_global_file(git_buf *path, const char *filename) { + const char *home = getenv("HOME"); + #ifdef GIT_WIN32 struct win32_path root; + if (home != NULL) { + if (git_buf_joinpath(path, home, filename) < 0) + return -1; + + if (git_path_exists(path->ptr)) { + return 0; + } + } + if (win32_expand_path(&root, L"%USERPROFILE%\\") < 0 || root.path[0] == L'%') /* i.e. no expansion happened */ { @@ -473,8 +484,6 @@ int git_futils_find_global_file(git_buf *path, const char *filename) return 0; #else - const char *home = getenv("HOME"); - if (home == NULL) { giterr_set(GITERR_OS, "Global file lookup failed. " "Cannot locate the user's home directory"); From 68e75c3a57874d3f1a6a7d36495e9303b69c6a78 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Mon, 24 Sep 2012 18:06:34 +0200 Subject: [PATCH 02/16] Calculate the Windows user profile directory the same way as msysgit On most systems %USERPROFILE% is the same as %HOMEDRIVE%\%HOMEPATH%, however, for windows machines in an AD or domain environment this might be different and %HOMEDRIVE%\%HOMEPATH% seems to be better. Signed-off-by: Sven Strickroth --- src/fileops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fileops.c b/src/fileops.c index d85ff7c72..cd0c055ae 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -469,7 +469,7 @@ int git_futils_find_global_file(git_buf *path, const char *filename) } } - if (win32_expand_path(&root, L"%USERPROFILE%\\") < 0 || + if (win32_expand_path(&root, L"%HOMEDRIVE%\\%HOMEPATH%\\") < 0 || root.path[0] == L'%') /* i.e. no expansion happened */ { giterr_set(GITERR_OS, "Cannot locate the user's profile directory"); From 6605f51d81a9ccfb1b5a1c1689a57cf3f5b2f5b3 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Mon, 24 Sep 2012 18:50:37 +0200 Subject: [PATCH 03/16] Automatically detect msysgit installation path Do not hardcode the installation path of msysgit, but read installation path from registry. Also "%PROGRAMFILES%\Git\etc" won't work on x64 systems with 64-bit libgit2, because msysgit is x86 only and located in "%ProgramFiles(x86)%\Git\etc". Signed-off-by: Sven Strickroth --- src/fileops.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/fileops.c b/src/fileops.c index cd0c055ae..b9044f0a3 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -423,12 +423,36 @@ static int win32_find_file(git_buf *path, const struct win32_path *root, const c int git_futils_find_system_file(git_buf *path, const char *filename) { #ifdef GIT_WIN32 +#ifndef _WIN64 +#define REG_MSYSGIT_INSTALL L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" +#else +#define REG_MSYSGIT_INSTALL L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" +#endif + struct win32_path root; - if (win32_expand_path(&root, L"%PROGRAMFILES%\\Git\\etc\\") < 0 || - root.path[0] == L'%') /* i.e. no expansion happened */ + HKEY hKey; + DWORD dwType = REG_SZ; + DWORD dwSize = MAX_PATH; + + root.len = 0; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, REG_MSYSGIT_INSTALL, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { - giterr_set(GITERR_OS, "Cannot locate the system's Program Files directory"); + if (RegQueryValueExW(hKey, L"InstallLocation", NULL, &dwType,(LPBYTE)&root.path, &dwSize) == ERROR_SUCCESS) + { + // InstallLocation points to the root of the msysgit directory + if (wcscat_s(root.path, MAX_PATH, L"etc\\")) + { + giterr_set(GITERR_OS, "Cannot locate the system's msysgit directory - path too long"); + return -1; + } + root.len = (DWORD)wcslen(root.path) + 1; + } + } + RegCloseKey(hKey); + + if (!root.len) { + giterr_set(GITERR_OS, "Cannot locate the system's msysgit directory"); return -1; } From 8b4f9b17580c52ac2b1f2f42f5c53116fb763436 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Mon, 24 Sep 2012 18:59:00 +0200 Subject: [PATCH 04/16] Correctly read xdr compatible %HOME%/.config/git/config config file This file is not just read if the global config file (%HOME%/.gitconfig) is not found, however, it is used everytime but with lower priority. Signed-off-by: Sven Strickroth --- include/git2/config.h | 20 ++++++++++++++++++++ src/config.c | 8 ++++++-- src/repository.c | 18 ++++++++++++++---- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/include/git2/config.h b/include/git2/config.h index 21d8a0b05..a3202c2b1 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -61,12 +61,32 @@ typedef struct { * may be used on any `git_config` call to load the * global configuration file. * + * This method will not guess the path to the xdr compatible + * config file (.config/git/config). + * * @param global_config_path Buffer of GIT_PATH_MAX length to store the path * @return 0 if a global configuration file has been * found. Its path will be stored in `buffer`. */ GIT_EXTERN(int) git_config_find_global(char *global_config_path, size_t length); +/** + * Locate the path to the global xdr compatible configuration file + * + * The xdr compatible configuration file is usually + * located in `$HOME/.config/git/config`. + * + * This method will try to guess the full path to that + * file, if the file exists. The returned path + * may be used on any `git_config` call to load the + * global configuration file. + * + * @param global_config_path Buffer of GIT_PATH_MAX length to store the path + * @return 0 if a global configuration file has been + * found. Its path will be stored in `buffer`. + */ +GIT_EXTERN(int) git_config_find_xdr(char *global_config_path, size_t length); + /** * Locate the path to the system configuration file * diff --git a/src/config.c b/src/config.c index e62dccf51..b3d6fc69a 100644 --- a/src/config.c +++ b/src/config.c @@ -451,8 +451,12 @@ int git_config_find_global_r(git_buf *path) { int error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME); - if (error == GIT_ENOTFOUND) - error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME_ALT); + return error; +} + +int git_config_find_xdr_r(git_buf *path) +{ + int error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME_ALT); return error; } diff --git a/src/repository.c b/src/repository.c index 1a46db0a5..3906cb388 100644 --- a/src/repository.c +++ b/src/repository.c @@ -445,6 +445,7 @@ static int load_config( git_config **out, git_repository *repo, const char *global_config_path, + const char *xdr_config_path, const char *system_config_path) { git_buf config_path = GIT_BUF_INIT; @@ -459,13 +460,18 @@ static int load_config( &config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO) < 0) goto on_error; - if (git_config_add_file_ondisk(cfg, config_path.ptr, 3) < 0) + if (git_config_add_file_ondisk(cfg, config_path.ptr, 4) < 0) goto on_error; git_buf_free(&config_path); if (global_config_path != NULL) { - if (git_config_add_file_ondisk(cfg, global_config_path, 2) < 0) + if (git_config_add_file_ondisk(cfg, global_config_path, 3) < 0) + goto on_error; + } + + if (xdr_config_path != NULL) { + if (git_config_add_file_ondisk(cfg, xdr_config_path, 3) < 0) goto on_error; } @@ -487,19 +493,23 @@ on_error: int git_repository_config__weakptr(git_config **out, git_repository *repo) { if (repo->_config == NULL) { - git_buf global_buf = GIT_BUF_INIT, system_buf = GIT_BUF_INIT; + git_buf global_buf = GIT_BUF_INIT, xdr_buf = GIT_BUF_INIT, system_buf = GIT_BUF_INIT; int res; const char *global_config_path = NULL; + const char *xdr_config_path = NULL; const char *system_config_path = NULL; if (git_config_find_global_r(&global_buf) == 0) global_config_path = global_buf.ptr; + if (git_config_find_xdr_r(&xdr_buf) == 0) + xdr_config_path = xdr_buf.ptr; + if (git_config_find_system_r(&system_buf) == 0) system_config_path = system_buf.ptr; - res = load_config(&repo->_config, repo, global_config_path, system_config_path); + res = load_config(&repo->_config, repo, global_config_path, xdr_config_path, system_config_path); git_buf_free(&global_buf); git_buf_free(&system_buf); From 407cf4e414ac2d67a27212e31d96582d4b83c8bc Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Mon, 24 Sep 2012 23:22:07 +0200 Subject: [PATCH 05/16] Fixed typo: xdr config needs to have a lower priority than the global one Signed-off-by: Sven Strickroth --- src/repository.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/repository.c b/src/repository.c index 3906cb388..d1cf47fe5 100644 --- a/src/repository.c +++ b/src/repository.c @@ -471,7 +471,7 @@ static int load_config( } if (xdr_config_path != NULL) { - if (git_config_add_file_ondisk(cfg, xdr_config_path, 3) < 0) + if (git_config_add_file_ondisk(cfg, xdr_config_path, 2) < 0) goto on_error; } From d7940ac3e4afd92fca527aafcc13a88817c5670f Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 25 Sep 2012 00:09:44 +0200 Subject: [PATCH 06/16] Fixed missing method Signed-off-by: Sven Strickroth --- src/config.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/config.c b/src/config.c index b3d6fc69a..e9854731b 100644 --- a/src/config.c +++ b/src/config.c @@ -483,6 +483,28 @@ int git_config_find_global(char *global_config_path, size_t length) return 0; } +int git_config_find_xdr(char *xdr_config_path, size_t length) +{ + git_buf path = GIT_BUF_INIT; + int ret = git_config_find_xdr_r(&path); + + if (ret < 0) { + git_buf_free(&path); + return ret; + } + + if (path.size >= length) { + git_buf_free(&path); + giterr_set(GITERR_NOMEMORY, + "Path is to long to fit on the given buffer"); + return -1; + } + + git_buf_copy_cstr(xdr_config_path, length, &path); + git_buf_free(&path); + return 0; +} + int git_config_find_system_r(git_buf *path) { return git_futils_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM); From c378a1184e8e4cdcffcad3271d650ab12792a6bc Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 25 Sep 2012 00:11:53 +0200 Subject: [PATCH 07/16] git_config_open_default: Honour xdr config Signed-off-by: Sven Strickroth --- src/config.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/config.c b/src/config.c index e9854731b..d8e54751a 100644 --- a/src/config.c +++ b/src/config.c @@ -541,6 +541,9 @@ int git_config_open_default(git_config **out) error = git_config_new(&cfg); if (!error && !git_config_find_global_r(&buf)) + error = git_config_add_file_ondisk(cfg, buf.ptr, 3); + + if (!error && !git_config_find_xdr_r(&buf)) error = git_config_add_file_ondisk(cfg, buf.ptr, 2); if (!error && !git_config_find_system_r(&buf)) From f2b126c76e858be1794c41f9e624ad0d3529432e Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 25 Sep 2012 00:33:53 +0200 Subject: [PATCH 08/16] Implemented the full msysgit fallback chain Signed-off-by: Sven Strickroth --- src/fileops.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/fileops.c b/src/fileops.c index b9044f0a3..a62967d93 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -493,11 +493,20 @@ int git_futils_find_global_file(git_buf *path, const char *filename) } } - if (win32_expand_path(&root, L"%HOMEDRIVE%\\%HOMEPATH%\\") < 0 || - root.path[0] == L'%') /* i.e. no expansion happened */ - { - giterr_set(GITERR_OS, "Cannot locate the user's profile directory"); - return -1; + if (getenv("HOMEPATH") != NULL) { + if (win32_expand_path(&root, L"%HOMEDRIVE%%HOMEPATH%\\") < 0 || + root.path[0] == L'%') /* i.e. no expansion happened */ + { + giterr_set(GITERR_OS, "Cannot locate the user's profile directory"); + return -1; + } + } else { + if (win32_expand_path(&root, L"%USERPROFILE%\\") < 0 || + root.path[0] == L'%') /* i.e. no expansion happened */ + { + giterr_set(GITERR_OS, "Cannot locate the user's profile directory"); + return -1; + } } if (win32_find_file(path, &root, filename) < 0) { From 549ee21a6f60baabf33b32b0d407957b4894d4aa Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sat, 29 Sep 2012 20:20:41 +0200 Subject: [PATCH 09/16] Find git installations based on %PATH% Signed-off-by: Sven Strickroth --- src/fileops.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/fileops.c b/src/fileops.c index a62967d93..846025182 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -418,6 +418,102 @@ static int win32_find_file(git_buf *path, const struct win32_path *root, const c git__free(file_utf16); return 0; } + +static wchar_t * nextpath(wchar_t * src, wchar_t * dst, size_t maxlen) +{ + wchar_t * orgsrc; + + while (*src == L';') + src++; + + orgsrc = src; + + if (!--maxlen) + goto nullterm; + + while (*src && *src != L';') + { + if (*src != L'"') + { + *dst++ = *src++; + if (!--maxlen) + { + orgsrc = src; + goto nullterm; + } + } + else + { + src++; + while (*src && *src != L'"') + { + *dst++ = *src++; + if (!--maxlen) + { + orgsrc = src; + goto nullterm; + } + } + + if (*src) + src++; + } + } + + while (*src == L';') + src++; + +nullterm: + *dst = 0; + + return (orgsrc != src) ? (wchar_t *)src : NULL; +} + +int find_system_file_using_path(git_buf *path, const char *filename) +{ + size_t size = 0; + wchar_t * env = NULL, * envOrig = NULL; + struct win32_path root; + + _wgetenv_s(&size, NULL, 0, L"PATH"); + + if (!size) + return -1; + + // make a copy of the content of the environment variable so that we can modify it + envOrig = git__calloc(size, sizeof(wchar_t)); + GITERR_CHECK_ALLOC(envOrig); + _wgetenv_s(&size, envOrig, size, L"PATH"); + env = envOrig; + + // search in all paths defined in PATH + while ((env = nextpath(env, root.path, MAX_PATH - 1)) != NULL && *root.path) + { + wchar_t * pfin = root.path + wcslen(root.path) - 1; // last char of the current path entry + + // ensure trailing slash + if (*pfin != L'/' && *pfin != L'\\') + wcscpy_s(++pfin, 2, L"\\"); // we have enough space left, MAX_PATH - 1 is used in nextpath above + + root.len = (DWORD)wcslen(root.path) + 1; + + if (win32_find_file(path, &root, "git.cmd") == 0 || win32_find_file(path, &root, "git.exe") == 0) { + // we found the cmd or bin directory of a git installaton + if (root.len > 5) { + wcscpy_s(root.path + wcslen(root.path) - 4, 5, L"etc\\"); + if (win32_find_file(path, &root, filename) == 0) + { + git__free(envOrig); + return 0; + } + } + } + } + + git__free(envOrig); + + return GIT_ENOTFOUND; +} #endif int git_futils_find_system_file(git_buf *path, const char *filename) @@ -435,6 +531,10 @@ int git_futils_find_system_file(git_buf *path, const char *filename) DWORD dwType = REG_SZ; DWORD dwSize = MAX_PATH; + // try to find git.exe/git.cmd on path + if (!find_system_file_using_path(path, filename)) + return 0; + root.len = 0; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, REG_MSYSGIT_INSTALL, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { From 32a4e3b712b2b63837afc28ebc9ba0169a0ac644 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sat, 29 Sep 2012 20:26:33 +0200 Subject: [PATCH 10/16] Move code to find msysgit path using registry to own method Signed-off-by: Sven Strickroth --- src/fileops.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/fileops.c b/src/fileops.c index 846025182..2a2324a7f 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -514,11 +514,9 @@ int find_system_file_using_path(git_buf *path, const char *filename) return GIT_ENOTFOUND; } -#endif -int git_futils_find_system_file(git_buf *path, const char *filename) +int find_system_file_using_registry(git_buf *path, const char *filename) { -#ifdef GIT_WIN32 #ifndef _WIN64 #define REG_MSYSGIT_INSTALL L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" #else @@ -531,10 +529,6 @@ int git_futils_find_system_file(git_buf *path, const char *filename) DWORD dwType = REG_SZ; DWORD dwSize = MAX_PATH; - // try to find git.exe/git.cmd on path - if (!find_system_file_using_path(path, filename)) - return 0; - root.len = 0; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, REG_MSYSGIT_INSTALL, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { @@ -563,18 +557,30 @@ int git_futils_find_system_file(git_buf *path, const char *filename) } return 0; +} +#endif +int git_futils_find_system_file(git_buf *path, const char *filename) +{ +#ifdef GIT_WIN32 + // try to find git.exe/git.cmd on path + if (!find_system_file_using_path(path, filename)) + return 0; + + // try to find msysgit installation path using registry + if (!find_system_file_using_registry(path, filename)) + return 0; #else if (git_buf_joinpath(path, "/etc", filename) < 0) return -1; if (git_path_exists(path->ptr) == true) return 0; +#endif git_buf_clear(path); giterr_set(GITERR_OS, "The system file '%s' doesn't exist", filename); return GIT_ENOTFOUND; -#endif } int git_futils_find_global_file(git_buf *path, const char *filename) From 77ddd4ccc37bf124525236e5d7f30af34b9d8075 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sat, 29 Sep 2012 21:24:07 +0200 Subject: [PATCH 11/16] Make it compile with MinGW on Windows Signed-off-by: Sven Strickroth --- src/fileops.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/fileops.c b/src/fileops.c index 2a2324a7f..a4b4dee83 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -471,21 +471,13 @@ nullterm: int find_system_file_using_path(git_buf *path, const char *filename) { - size_t size = 0; - wchar_t * env = NULL, * envOrig = NULL; + wchar_t * env = NULL; struct win32_path root; - _wgetenv_s(&size, NULL, 0, L"PATH"); - - if (!size) + env = _wgetenv(L"PATH"); + if (!env) return -1; - // make a copy of the content of the environment variable so that we can modify it - envOrig = git__calloc(size, sizeof(wchar_t)); - GITERR_CHECK_ALLOC(envOrig); - _wgetenv_s(&size, envOrig, size, L"PATH"); - env = envOrig; - // search in all paths defined in PATH while ((env = nextpath(env, root.path, MAX_PATH - 1)) != NULL && *root.path) { @@ -493,25 +485,20 @@ int find_system_file_using_path(git_buf *path, const char *filename) // ensure trailing slash if (*pfin != L'/' && *pfin != L'\\') - wcscpy_s(++pfin, 2, L"\\"); // we have enough space left, MAX_PATH - 1 is used in nextpath above + wcscpy(++pfin, L"\\"); // we have enough space left, MAX_PATH - 1 is used in nextpath above root.len = (DWORD)wcslen(root.path) + 1; if (win32_find_file(path, &root, "git.cmd") == 0 || win32_find_file(path, &root, "git.exe") == 0) { // we found the cmd or bin directory of a git installaton if (root.len > 5) { - wcscpy_s(root.path + wcslen(root.path) - 4, 5, L"etc\\"); + wcscpy(root.path + wcslen(root.path) - 4, L"etc\\"); if (win32_find_file(path, &root, filename) == 0) - { - git__free(envOrig); return 0; - } } } } - git__free(envOrig); - return GIT_ENOTFOUND; } @@ -535,11 +522,12 @@ int find_system_file_using_registry(git_buf *path, const char *filename) if (RegQueryValueExW(hKey, L"InstallLocation", NULL, &dwType,(LPBYTE)&root.path, &dwSize) == ERROR_SUCCESS) { // InstallLocation points to the root of the msysgit directory - if (wcscat_s(root.path, MAX_PATH, L"etc\\")) + if (dwSize + 4 > MAX_PATH) // 4 = wcslen(L"etc\\") { giterr_set(GITERR_OS, "Cannot locate the system's msysgit directory - path too long"); return -1; } + wcscat(root.path, L"etc\\"); root.len = (DWORD)wcslen(root.path) + 1; } } From dee18b825afd031e8f124a9b2d2a578a79988eda Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sat, 29 Sep 2012 21:26:04 +0200 Subject: [PATCH 12/16] Added win32_ prefix for Win32-only methods Signed-off-by: Sven Strickroth --- src/fileops.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fileops.c b/src/fileops.c index a4b4dee83..2bdea91c7 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -419,7 +419,7 @@ static int win32_find_file(git_buf *path, const struct win32_path *root, const c return 0; } -static wchar_t * nextpath(wchar_t * src, wchar_t * dst, size_t maxlen) +static wchar_t * win32_nextpath(wchar_t * src, wchar_t * dst, size_t maxlen) { wchar_t * orgsrc; @@ -469,7 +469,7 @@ nullterm: return (orgsrc != src) ? (wchar_t *)src : NULL; } -int find_system_file_using_path(git_buf *path, const char *filename) +int win32_find_system_file_using_path(git_buf *path, const char *filename) { wchar_t * env = NULL; struct win32_path root; @@ -479,7 +479,7 @@ int find_system_file_using_path(git_buf *path, const char *filename) return -1; // search in all paths defined in PATH - while ((env = nextpath(env, root.path, MAX_PATH - 1)) != NULL && *root.path) + while ((env = win32_nextpath(env, root.path, MAX_PATH - 1)) != NULL && *root.path) { wchar_t * pfin = root.path + wcslen(root.path) - 1; // last char of the current path entry @@ -502,7 +502,7 @@ int find_system_file_using_path(git_buf *path, const char *filename) return GIT_ENOTFOUND; } -int find_system_file_using_registry(git_buf *path, const char *filename) +int win32_find_system_file_using_registry(git_buf *path, const char *filename) { #ifndef _WIN64 #define REG_MSYSGIT_INSTALL L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" @@ -552,11 +552,11 @@ int git_futils_find_system_file(git_buf *path, const char *filename) { #ifdef GIT_WIN32 // try to find git.exe/git.cmd on path - if (!find_system_file_using_path(path, filename)) + if (!win32_find_system_file_using_path(path, filename)) return 0; // try to find msysgit installation path using registry - if (!find_system_file_using_registry(path, filename)) + if (!win32_find_system_file_using_registry(path, filename)) return 0; #else if (git_buf_joinpath(path, "/etc", filename) < 0) From 19aa8416e59e6c8f01c6b850ce6bb3e2f7457236 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sat, 29 Sep 2012 21:26:32 +0200 Subject: [PATCH 13/16] Silence MinGW warnings Signed-off-by: Sven Strickroth --- src/config.h | 1 + src/fileops.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/config.h b/src/config.h index 5475ef384..4e451a23f 100644 --- a/src/config.h +++ b/src/config.h @@ -24,6 +24,7 @@ struct git_config { }; extern int git_config_find_global_r(git_buf *global_config_path); +extern int git_config_find_xdr_r(git_buf *system_config_path); extern int git_config_find_system_r(git_buf *system_config_path); extern int git_config_parse_bool(int *out, const char *bool_string); diff --git a/src/fileops.c b/src/fileops.c index 2bdea91c7..cbc7419e0 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -469,7 +469,7 @@ nullterm: return (orgsrc != src) ? (wchar_t *)src : NULL; } -int win32_find_system_file_using_path(git_buf *path, const char *filename) +static int win32_find_system_file_using_path(git_buf *path, const char *filename) { wchar_t * env = NULL; struct win32_path root; @@ -502,7 +502,7 @@ int win32_find_system_file_using_path(git_buf *path, const char *filename) return GIT_ENOTFOUND; } -int win32_find_system_file_using_registry(git_buf *path, const char *filename) +static int win32_find_system_file_using_registry(git_buf *path, const char *filename) { #ifndef _WIN64 #define REG_MSYSGIT_INSTALL L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" From 8b3de0b6b8104019def3ddedcf2750539ea7409f Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 2 Oct 2012 17:16:22 +0200 Subject: [PATCH 14/16] Optimized win32_nextpath Based on a suggestion by Russell Belfer. Signed-off-by: Sven Strickroth Signed-off-by: Russell Belfer --- src/fileops.c | 52 ++++++++++----------------------------------------- 1 file changed, 10 insertions(+), 42 deletions(-) diff --git a/src/fileops.c b/src/fileops.c index cbc7419e0..d99e117bd 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -418,55 +418,23 @@ static int win32_find_file(git_buf *path, const struct win32_path *root, const c git__free(file_utf16); return 0; } - -static wchar_t * win32_nextpath(wchar_t * src, wchar_t * dst, size_t maxlen) +static wchar_t* win32_nextpath(wchar_t *path, wchar_t *buf, size_t buflen) { - wchar_t * orgsrc; + wchar_t term, *base = path; - while (*src == L';') - src++; + assert(path && buf && buflen); - orgsrc = src; + term = (*path == L'"') ? *path++ : L';'; - if (!--maxlen) - goto nullterm; + for (buflen--; *path && *path != term && buflen; buflen--) + *buf++ = *path++; - while (*src && *src != L';') - { - if (*src != L'"') - { - *dst++ = *src++; - if (!--maxlen) - { - orgsrc = src; - goto nullterm; - } - } - else - { - src++; - while (*src && *src != L'"') - { - *dst++ = *src++; - if (!--maxlen) - { - orgsrc = src; - goto nullterm; - } - } + *buf = L'\0'; /* reserved a byte via initial subtract */ - if (*src) - src++; - } - } + while (*path == term || *path == L';') + path++; - while (*src == L';') - src++; - -nullterm: - *dst = 0; - - return (orgsrc != src) ? (wchar_t *)src : NULL; + return (path != base) ? path : NULL; } static int win32_find_system_file_using_path(git_buf *path, const char *filename) From 4258d4832b9525ed4e21597a9e63a6dd5aa43507 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 2 Oct 2012 17:21:07 +0200 Subject: [PATCH 15/16] Rename xdr to xdg Signed-off-by: Sven Strickroth --- include/git2/config.h | 14 +++++++------- src/config.c | 10 +++++----- src/config.h | 2 +- src/repository.c | 16 ++++++++-------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/git2/config.h b/include/git2/config.h index a3202c2b1..a7d897443 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -61,7 +61,7 @@ typedef struct { * may be used on any `git_config` call to load the * global configuration file. * - * This method will not guess the path to the xdr compatible + * This method will not guess the path to the xdg compatible * config file (.config/git/config). * * @param global_config_path Buffer of GIT_PATH_MAX length to store the path @@ -71,21 +71,21 @@ typedef struct { GIT_EXTERN(int) git_config_find_global(char *global_config_path, size_t length); /** - * Locate the path to the global xdr compatible configuration file + * Locate the path to the global xdg compatible configuration file * - * The xdr compatible configuration file is usually + * The xdg compatible configuration file is usually * located in `$HOME/.config/git/config`. * * This method will try to guess the full path to that * file, if the file exists. The returned path * may be used on any `git_config` call to load the - * global configuration file. + * xdg compatible configuration file. * - * @param global_config_path Buffer of GIT_PATH_MAX length to store the path - * @return 0 if a global configuration file has been + * @param xdg_config_path Buffer of GIT_PATH_MAX length to store the path + * @return 0 if a xdg compatible configuration file has been * found. Its path will be stored in `buffer`. */ -GIT_EXTERN(int) git_config_find_xdr(char *global_config_path, size_t length); +GIT_EXTERN(int) git_config_find_xdg(char *xdg_config_path, size_t length); /** * Locate the path to the system configuration file diff --git a/src/config.c b/src/config.c index d8e54751a..b89c16b1c 100644 --- a/src/config.c +++ b/src/config.c @@ -454,7 +454,7 @@ int git_config_find_global_r(git_buf *path) return error; } -int git_config_find_xdr_r(git_buf *path) +int git_config_find_xdg_r(git_buf *path) { int error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME_ALT); @@ -483,10 +483,10 @@ int git_config_find_global(char *global_config_path, size_t length) return 0; } -int git_config_find_xdr(char *xdr_config_path, size_t length) +int git_config_find_xdg(char *xdg_config_path, size_t length) { git_buf path = GIT_BUF_INIT; - int ret = git_config_find_xdr_r(&path); + int ret = git_config_find_xdg_r(&path); if (ret < 0) { git_buf_free(&path); @@ -500,7 +500,7 @@ int git_config_find_xdr(char *xdr_config_path, size_t length) return -1; } - git_buf_copy_cstr(xdr_config_path, length, &path); + git_buf_copy_cstr(xdg_config_path, length, &path); git_buf_free(&path); return 0; } @@ -543,7 +543,7 @@ int git_config_open_default(git_config **out) if (!error && !git_config_find_global_r(&buf)) error = git_config_add_file_ondisk(cfg, buf.ptr, 3); - if (!error && !git_config_find_xdr_r(&buf)) + if (!error && !git_config_find_xdg_r(&buf)) error = git_config_add_file_ondisk(cfg, buf.ptr, 2); if (!error && !git_config_find_system_r(&buf)) diff --git a/src/config.h b/src/config.h index 4e451a23f..471b42dad 100644 --- a/src/config.h +++ b/src/config.h @@ -24,7 +24,7 @@ struct git_config { }; extern int git_config_find_global_r(git_buf *global_config_path); -extern int git_config_find_xdr_r(git_buf *system_config_path); +extern int git_config_find_xdg_r(git_buf *system_config_path); extern int git_config_find_system_r(git_buf *system_config_path); extern int git_config_parse_bool(int *out, const char *bool_string); diff --git a/src/repository.c b/src/repository.c index d1cf47fe5..e9c1bdf47 100644 --- a/src/repository.c +++ b/src/repository.c @@ -445,7 +445,7 @@ static int load_config( git_config **out, git_repository *repo, const char *global_config_path, - const char *xdr_config_path, + const char *xdg_config_path, const char *system_config_path) { git_buf config_path = GIT_BUF_INIT; @@ -470,8 +470,8 @@ static int load_config( goto on_error; } - if (xdr_config_path != NULL) { - if (git_config_add_file_ondisk(cfg, xdr_config_path, 2) < 0) + if (xdg_config_path != NULL) { + if (git_config_add_file_ondisk(cfg, xdg_config_path, 2) < 0) goto on_error; } @@ -493,23 +493,23 @@ on_error: int git_repository_config__weakptr(git_config **out, git_repository *repo) { if (repo->_config == NULL) { - git_buf global_buf = GIT_BUF_INIT, xdr_buf = GIT_BUF_INIT, system_buf = GIT_BUF_INIT; + git_buf global_buf = GIT_BUF_INIT, xdg_buf = GIT_BUF_INIT, system_buf = GIT_BUF_INIT; int res; const char *global_config_path = NULL; - const char *xdr_config_path = NULL; + const char *xdg_config_path = NULL; const char *system_config_path = NULL; if (git_config_find_global_r(&global_buf) == 0) global_config_path = global_buf.ptr; - if (git_config_find_xdr_r(&xdr_buf) == 0) - xdr_config_path = xdr_buf.ptr; + if (git_config_find_xdg_r(&xdg_buf) == 0) + xdg_config_path = xdg_buf.ptr; if (git_config_find_system_r(&system_buf) == 0) system_config_path = system_buf.ptr; - res = load_config(&repo->_config, repo, global_config_path, xdr_config_path, system_config_path); + res = load_config(&repo->_config, repo, global_config_path, xdg_config_path, system_config_path); git_buf_free(&global_buf); git_buf_free(&system_buf); From 997579bed1806f217c910da05092ffdf9f4523b4 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 2 Oct 2012 17:55:29 +0200 Subject: [PATCH 16/16] Move win32 specific stuff to win32/findfile.c Signed-off-by: Sven Strickroth --- src/fileops.c | 148 +----------------------------------------- src/win32/findfile.c | 149 +++++++++++++++++++++++++++++++++++++++++++ src/win32/findfile.h | 23 +++++++ 3 files changed, 175 insertions(+), 145 deletions(-) create mode 100644 src/win32/findfile.c create mode 100644 src/win32/findfile.h diff --git a/src/fileops.c b/src/fileops.c index d99e117bd..763537a46 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -7,6 +7,9 @@ #include "common.h" #include "fileops.h" #include +#if GIT_WIN32 +#include "win32/findfile.h" +#endif int git_futils_mkpath2file(const char *file_path, const mode_t mode) { @@ -371,151 +374,6 @@ int git_futils_rmdir_r(const char *path, git_directory_removal_type removal_type return error; } -#ifdef GIT_WIN32 -struct win32_path { - wchar_t path[MAX_PATH]; - DWORD len; -}; - -static int win32_expand_path(struct win32_path *s_root, const wchar_t *templ) -{ - s_root->len = ExpandEnvironmentStringsW(templ, s_root->path, MAX_PATH); - return s_root->len ? 0 : -1; -} - -static int win32_find_file(git_buf *path, const struct win32_path *root, const char *filename) -{ - size_t len, alloc_len; - wchar_t *file_utf16 = NULL; - char file_utf8[GIT_PATH_MAX]; - - if (!root || !filename || (len = strlen(filename)) == 0) - return GIT_ENOTFOUND; - - /* allocate space for wchar_t path to file */ - alloc_len = root->len + len + 2; - file_utf16 = git__calloc(alloc_len, sizeof(wchar_t)); - GITERR_CHECK_ALLOC(file_utf16); - - /* append root + '\\' + filename as wchar_t */ - memcpy(file_utf16, root->path, root->len * sizeof(wchar_t)); - - if (*filename == '/' || *filename == '\\') - filename++; - - git__utf8_to_16(file_utf16 + root->len - 1, alloc_len, filename); - - /* check access */ - if (_waccess(file_utf16, F_OK) < 0) { - git__free(file_utf16); - return GIT_ENOTFOUND; - } - - git__utf16_to_8(file_utf8, file_utf16); - git_path_mkposix(file_utf8); - git_buf_sets(path, file_utf8); - - git__free(file_utf16); - return 0; -} -static wchar_t* win32_nextpath(wchar_t *path, wchar_t *buf, size_t buflen) -{ - wchar_t term, *base = path; - - assert(path && buf && buflen); - - term = (*path == L'"') ? *path++ : L';'; - - for (buflen--; *path && *path != term && buflen; buflen--) - *buf++ = *path++; - - *buf = L'\0'; /* reserved a byte via initial subtract */ - - while (*path == term || *path == L';') - path++; - - return (path != base) ? path : NULL; -} - -static int win32_find_system_file_using_path(git_buf *path, const char *filename) -{ - wchar_t * env = NULL; - struct win32_path root; - - env = _wgetenv(L"PATH"); - if (!env) - return -1; - - // search in all paths defined in PATH - while ((env = win32_nextpath(env, root.path, MAX_PATH - 1)) != NULL && *root.path) - { - wchar_t * pfin = root.path + wcslen(root.path) - 1; // last char of the current path entry - - // ensure trailing slash - if (*pfin != L'/' && *pfin != L'\\') - wcscpy(++pfin, L"\\"); // we have enough space left, MAX_PATH - 1 is used in nextpath above - - root.len = (DWORD)wcslen(root.path) + 1; - - if (win32_find_file(path, &root, "git.cmd") == 0 || win32_find_file(path, &root, "git.exe") == 0) { - // we found the cmd or bin directory of a git installaton - if (root.len > 5) { - wcscpy(root.path + wcslen(root.path) - 4, L"etc\\"); - if (win32_find_file(path, &root, filename) == 0) - return 0; - } - } - } - - return GIT_ENOTFOUND; -} - -static int win32_find_system_file_using_registry(git_buf *path, const char *filename) -{ -#ifndef _WIN64 -#define REG_MSYSGIT_INSTALL L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" -#else -#define REG_MSYSGIT_INSTALL L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" -#endif - - struct win32_path root; - - HKEY hKey; - DWORD dwType = REG_SZ; - DWORD dwSize = MAX_PATH; - - root.len = 0; - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, REG_MSYSGIT_INSTALL, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) - { - if (RegQueryValueExW(hKey, L"InstallLocation", NULL, &dwType,(LPBYTE)&root.path, &dwSize) == ERROR_SUCCESS) - { - // InstallLocation points to the root of the msysgit directory - if (dwSize + 4 > MAX_PATH) // 4 = wcslen(L"etc\\") - { - giterr_set(GITERR_OS, "Cannot locate the system's msysgit directory - path too long"); - return -1; - } - wcscat(root.path, L"etc\\"); - root.len = (DWORD)wcslen(root.path) + 1; - } - } - RegCloseKey(hKey); - - if (!root.len) { - giterr_set(GITERR_OS, "Cannot locate the system's msysgit directory"); - return -1; - } - - if (win32_find_file(path, &root, filename) < 0) { - giterr_set(GITERR_OS, "The system file '%s' doesn't exist", filename); - git_buf_clear(path); - return GIT_ENOTFOUND; - } - - return 0; -} -#endif - int git_futils_find_system_file(git_buf *path, const char *filename) { #ifdef GIT_WIN32 diff --git a/src/win32/findfile.c b/src/win32/findfile.c new file mode 100644 index 000000000..de9373cbb --- /dev/null +++ b/src/win32/findfile.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2012 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "utf-conv.h" +#include "path.h" +#include "findfile.h" + +#ifndef _WIN64 +#define REG_MSYSGIT_INSTALL L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" +#else +#define REG_MSYSGIT_INSTALL L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" +#endif + +int win32_expand_path(struct win32_path *s_root, const wchar_t *templ) +{ + s_root->len = ExpandEnvironmentStringsW(templ, s_root->path, MAX_PATH); + return s_root->len ? 0 : -1; +} + +int win32_find_file(git_buf *path, const struct win32_path *root, const char *filename) +{ + size_t len, alloc_len; + wchar_t *file_utf16 = NULL; + char file_utf8[GIT_PATH_MAX]; + + if (!root || !filename || (len = strlen(filename)) == 0) + return GIT_ENOTFOUND; + + /* allocate space for wchar_t path to file */ + alloc_len = root->len + len + 2; + file_utf16 = git__calloc(alloc_len, sizeof(wchar_t)); + GITERR_CHECK_ALLOC(file_utf16); + + /* append root + '\\' + filename as wchar_t */ + memcpy(file_utf16, root->path, root->len * sizeof(wchar_t)); + + if (*filename == '/' || *filename == '\\') + filename++; + + git__utf8_to_16(file_utf16 + root->len - 1, alloc_len, filename); + + /* check access */ + if (_waccess(file_utf16, F_OK) < 0) { + git__free(file_utf16); + return GIT_ENOTFOUND; + } + + git__utf16_to_8(file_utf8, file_utf16); + git_path_mkposix(file_utf8); + git_buf_sets(path, file_utf8); + + git__free(file_utf16); + return 0; +} + +wchar_t* win32_nextpath(wchar_t *path, wchar_t *buf, size_t buflen) +{ + wchar_t term, *base = path; + + assert(path && buf && buflen); + + term = (*path == L'"') ? *path++ : L';'; + + for (buflen--; *path && *path != term && buflen; buflen--) + *buf++ = *path++; + + *buf = L'\0'; /* reserved a byte via initial subtract */ + + while (*path == term || *path == L';') + path++; + + return (path != base) ? path : NULL; +} + +int win32_find_system_file_using_path(git_buf *path, const char *filename) +{ + wchar_t * env = NULL; + struct win32_path root; + + env = _wgetenv(L"PATH"); + if (!env) + return -1; + + // search in all paths defined in PATH + while ((env = win32_nextpath(env, root.path, MAX_PATH - 1)) != NULL && *root.path) + { + wchar_t * pfin = root.path + wcslen(root.path) - 1; // last char of the current path entry + + // ensure trailing slash + if (*pfin != L'/' && *pfin != L'\\') + wcscpy(++pfin, L"\\"); // we have enough space left, MAX_PATH - 1 is used in nextpath above + + root.len = (DWORD)wcslen(root.path) + 1; + + if (win32_find_file(path, &root, "git.cmd") == 0 || win32_find_file(path, &root, "git.exe") == 0) { + // we found the cmd or bin directory of a git installaton + if (root.len > 5) { + wcscpy(root.path + wcslen(root.path) - 4, L"etc\\"); + if (win32_find_file(path, &root, filename) == 0) + return 0; + } + } + } + + return GIT_ENOTFOUND; +} + +int win32_find_system_file_using_registry(git_buf *path, const char *filename) +{ + struct win32_path root; + + HKEY hKey; + DWORD dwType = REG_SZ; + DWORD dwSize = MAX_PATH; + + root.len = 0; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, REG_MSYSGIT_INSTALL, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) + { + if (RegQueryValueExW(hKey, L"InstallLocation", NULL, &dwType,(LPBYTE)&root.path, &dwSize) == ERROR_SUCCESS) + { + // InstallLocation points to the root of the msysgit directory + if (dwSize + 4 > MAX_PATH) // 4 = wcslen(L"etc\\") + { + giterr_set(GITERR_OS, "Cannot locate the system's msysgit directory - path too long"); + return -1; + } + wcscat(root.path, L"etc\\"); + root.len = (DWORD)wcslen(root.path) + 1; + } + } + RegCloseKey(hKey); + + if (!root.len) { + giterr_set(GITERR_OS, "Cannot locate the system's msysgit directory"); + return -1; + } + + if (win32_find_file(path, &root, filename) < 0) { + giterr_set(GITERR_OS, "The system file '%s' doesn't exist", filename); + git_buf_clear(path); + return GIT_ENOTFOUND; + } + + return 0; +} diff --git a/src/win32/findfile.h b/src/win32/findfile.h new file mode 100644 index 000000000..8751b7391 --- /dev/null +++ b/src/win32/findfile.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2012 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_git_findfile_h__ +#define INCLUDE_git_findfile_h__ + +struct win32_path { + wchar_t path[MAX_PATH]; + DWORD len; +}; + +int win32_expand_path(struct win32_path *s_root, const wchar_t *templ); + +int win32_find_file(git_buf *path, const struct win32_path *root, const char *filename); +int win32_find_system_file_using_path(git_buf *path, const char *filename); +int win32_find_system_file_using_registry(git_buf *path, const char *filename); + +#endif +