1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* 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;
}