/* * 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; }