git.exe of msysgit cmd folder does not work, so try to guess bin folder
[TortoiseGit.git] / src / Git / GitAdminDir.cpp
blob6f27402a8c9bfb050d01d56f1eb6abf7ce4fa97f
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2013 - TortoiseGit
4 // Copyright (C) 2003-2008 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "UnicodeUtils.h"
22 #include "GitAdminDir.h"
23 #include "Git.h"
24 #include <memory>
26 GitAdminDir g_GitAdminDir;
28 GitAdminDir::GitAdminDir()
32 GitAdminDir::~GitAdminDir()
36 CString GitAdminDir::GetSuperProjectRoot(const CString& path)
38 CString projectroot=path;
42 if(CGit::GitPathFileExists(projectroot + _T("\\.gitmodules")))
44 return projectroot;
47 projectroot = projectroot.Left(projectroot.ReverseFind('\\'));
49 }while(projectroot.ReverseFind('\\')>0);
51 return _T("");
55 CString GitAdminDir::GetGitTopDir(const CString& path)
57 CString str;
58 str=_T("");
59 HasAdminDir(path,!!PathIsDirectory(path),&str);
60 return str;
63 bool GitAdminDir::HasAdminDir(const CString& path) const
65 return HasAdminDir(path, !!PathIsDirectory(path));
68 bool GitAdminDir::HasAdminDir(const CString& path,CString *ProjectTopDir) const
70 return HasAdminDir(path, !!PathIsDirectory(path),ProjectTopDir);
73 bool GitAdminDir::HasAdminDir(const CString& path, bool bDir,CString *ProjectTopDir) const
75 if (path.IsEmpty())
76 return false;
77 CString sDirName = path;
78 if (!bDir)
80 sDirName = path.Left(path.ReverseFind(_T('\\')));
83 // a .git dir or anything inside it should be left out, only interested in working copy files -- Myagi
85 int n = 0;
86 for (;;)
88 n = sDirName.Find(_T("\\.git"), n);
89 if (n < 0)
91 break;
94 // check for actual .git dir (and not .gitignore or something else), continue search if false match
95 n += 5;
96 if (sDirName[n] == _T('\\') || sDirName[n] == 0)
98 return false;
103 for (;;)
105 if(CGit::GitPathFileExists(sDirName + _T("\\.git")))
107 if(ProjectTopDir)
109 *ProjectTopDir=sDirName;
110 // Make sure to add the trailing slash to root paths such as 'C:'
111 if (sDirName.GetLength() == 2 && sDirName[1] == _T(':'))
112 (*ProjectTopDir) += _T("\\");
114 return true;
117 int x = sDirName.ReverseFind(_T('\\'));
118 if (x < 2)
119 break;
121 sDirName = sDirName.Left(x);
124 return false;
128 * Returns the .git-path (if .git is a file, read the repository path and return it)
129 * adminDir always ends with "\"
131 bool GitAdminDir::GetAdminDirPath(const CString &projectTopDir, CString &adminDir) const
133 if (IsBareRepo(projectTopDir))
135 adminDir = projectTopDir;
136 adminDir.TrimRight('\\');
137 adminDir.Append(_T("\\"));
138 return true;
141 CString sDotGitPath = projectTopDir + _T("\\") + g_GitAdminDir.GetAdminDirName();
142 if (CTGitPath(sDotGitPath).IsDirectory())
144 sDotGitPath.TrimRight('\\');
145 sDotGitPath.Append(_T("\\"));
146 adminDir = sDotGitPath;
147 return true;
149 else
151 FILE *pFile;
152 _tfopen_s(&pFile, sDotGitPath, _T("r"));
154 if (!pFile)
155 return false;
157 int size = 65536;
158 std::unique_ptr<char[]> buffer(new char[size]);
159 SecureZeroMemory(buffer.get(), size);
160 fread(buffer.get(), sizeof(char), size, pFile);
161 fclose(pFile);
162 CStringA gitPathA(buffer.get());
163 if (gitPathA.Left(8) != "gitdir: ")
164 return false;
165 CString gitPath = CUnicodeUtils::GetUnicode(gitPathA.Trim().Mid(8)); // 8 = len("gitdir: ")
166 gitPath.Replace('/', '\\');
167 gitPath.TrimRight('\\');
168 gitPath.Append(_T("\\"));
169 if (gitPath.GetLength() > 0 && gitPath[0] == _T('.'))
171 gitPath = projectTopDir + _T("\\") + gitPath;
172 PathCanonicalize(adminDir.GetBuffer(MAX_PATH), gitPath.GetBuffer());
173 adminDir.ReleaseBuffer();
174 gitPath.ReleaseBuffer();
175 return true;
177 adminDir = gitPath;
178 return true;
182 bool GitAdminDir::IsAdminDirPath(const CString& path) const
184 if (path.IsEmpty())
185 return false;
186 bool bIsAdminDir = false;
187 CString lowerpath = path;
188 lowerpath.MakeLower();
189 int ind = -1;
190 int ind1 = 0;
191 while ((ind1 = lowerpath.Find(_T("\\.git"), ind1))>=0)
193 ind = ind1++;
194 if (ind == (lowerpath.GetLength() - 5))
196 bIsAdminDir = true;
197 break;
199 else if (lowerpath.Find(_T("\\.git\\"), ind)>=0)
201 bIsAdminDir = true;
202 break;
206 return bIsAdminDir;
209 bool GitAdminDir::IsBareRepo(const CString& path) const
211 if (path.IsEmpty())
212 return false;
214 if (IsAdminDirPath(path))
215 return false;
217 if (!PathFileExists(path + _T("\\HEAD")) || !PathFileExists(path + _T("\\config")))
218 return false;
220 if (!PathFileExists(path + _T("\\objects\\")) || !PathFileExists(path + _T("\\refs\\")))
221 return false;
223 return true;