Make sure we do not forget to use ReleaseBuffer and make use of CStrBuf
[TortoiseGit.git] / src / Git / GitAdminDir.cpp
blob92bb5ffc4047e5c5748b019b5d13f5edd9962fcc
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2015 - 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"
25 GitAdminDir::GitAdminDir()
29 GitAdminDir::~GitAdminDir()
33 CString GitAdminDir::GetSuperProjectRoot(const CString& path)
35 CString projectroot=path;
39 if (CGit::GitPathFileExists(projectroot + _T("\\.git")))
41 if (CGit::GitPathFileExists(projectroot + _T("\\.gitmodules")))
42 return projectroot;
43 else
44 return _T("");
47 projectroot = projectroot.Left(projectroot.ReverseFind('\\'));
49 // don't check for \\COMPUTERNAME\.git
50 if (projectroot[0] == _T('\\') && projectroot[1] == _T('\\') && projectroot.Find(_T('\\'), 2) < 0)
51 return _T("");
52 }while(projectroot.ReverseFind('\\')>0);
54 return _T("");
58 CString GitAdminDir::GetGitTopDir(const CString& path)
60 CString str;
61 HasAdminDir(path,!!PathIsDirectory(path),&str);
62 return str;
65 bool GitAdminDir::IsWorkingTreeOrBareRepo(const CString& path)
67 return HasAdminDir(path) || IsBareRepo(path);
70 bool GitAdminDir::HasAdminDir(const CString& path)
72 return HasAdminDir(path, !!PathIsDirectory(path));
75 bool GitAdminDir::HasAdminDir(const CString& path,CString* ProjectTopDir)
77 return HasAdminDir(path, !!PathIsDirectory(path),ProjectTopDir);
80 bool GitAdminDir::HasAdminDir(const CString& path, bool bDir, CString* ProjectTopDir)
82 if (path.IsEmpty())
83 return false;
84 CString sDirName = path;
85 if (!bDir)
87 // e.g "C:\"
88 if (path.GetLength() <= 3)
89 return false;
90 sDirName = path.Left(path.ReverseFind(_T('\\')));
93 // a .git dir or anything inside it should be left out, only interested in working copy files -- Myagi
95 int n = 0;
96 for (;;)
98 n = sDirName.Find(_T("\\.git"), n);
99 if (n < 0)
101 break;
104 // check for actual .git dir (and not .gitignore or something else), continue search if false match
105 n += 5;
106 if (sDirName[n] == _T('\\') || sDirName[n] == 0)
108 return false;
113 for (;;)
115 if(CGit::GitPathFileExists(sDirName + _T("\\.git")))
117 if(ProjectTopDir)
119 *ProjectTopDir=sDirName;
120 // Make sure to add the trailing slash to root paths such as 'C:'
121 if (sDirName.GetLength() == 2 && sDirName[1] == _T(':'))
122 (*ProjectTopDir) += _T("\\");
124 return true;
126 else if (IsBareRepo(sDirName))
127 return false;
129 int x = sDirName.ReverseFind(_T('\\'));
130 if (x < 2)
131 break;
133 sDirName = sDirName.Left(x);
134 // don't check for \\COMPUTERNAME\.git
135 if (sDirName[0] == _T('\\') && sDirName[1] == _T('\\') && sDirName.Find(_T('\\'), 2) < 0)
136 break;
139 return false;
143 * Returns the .git-path (if .git is a file, read the repository path and return it)
144 * adminDir always ends with "\"
146 bool GitAdminDir::GetAdminDirPath(const CString &projectTopDir, CString& adminDir)
148 if (IsBareRepo(projectTopDir))
150 adminDir = projectTopDir;
151 adminDir.TrimRight('\\');
152 adminDir.Append(_T("\\"));
153 return true;
156 CString sDotGitPath = projectTopDir + _T("\\") + GetAdminDirName();
157 if (CTGitPath(sDotGitPath).IsDirectory())
159 sDotGitPath.TrimRight('\\');
160 sDotGitPath.Append(_T("\\"));
161 adminDir = sDotGitPath;
162 return true;
164 else
166 CString result = ReadGitLink(projectTopDir, sDotGitPath);
167 if (result.IsEmpty())
168 return false;
169 adminDir = result + _T("\\");
170 return true;
174 CString GitAdminDir::ReadGitLink(const CString& topDir, const CString& dotGitPath)
176 FILE* pFile = _tfsopen(dotGitPath, _T("r"), SH_DENYWR);
178 if (!pFile)
179 return _T("");
181 int size = 65536;
182 std::unique_ptr<char[]> buffer(new char[size]);
183 int length = (int)fread(buffer.get(), sizeof(char), size, pFile);
184 fclose(pFile);
185 CStringA gitPathA(buffer.get(), length);
186 if (length < 8 || gitPathA.Left(8) != "gitdir: ")
187 return _T("");
188 CString gitPath = CUnicodeUtils::GetUnicode(gitPathA);
189 // trim after converting to UTF-16, because CStringA trim does not work when having UTF-8 chars
190 gitPath = gitPath.Trim().Mid(8); // 8 = len("gitdir: ")
191 gitPath.Replace('/', '\\');
192 gitPath.TrimRight('\\');
193 if (!gitPath.IsEmpty() && gitPath[0] == _T('.'))
195 gitPath = topDir + _T("\\") + gitPath;
196 CString adminDir;
197 PathCanonicalize(CStrBuf(adminDir, MAX_PATH), gitPath);
198 return adminDir;
200 return gitPath;
203 bool GitAdminDir::IsAdminDirPath(const CString& path)
205 if (path.IsEmpty())
206 return false;
207 bool bIsAdminDir = false;
208 CString lowerpath = path;
209 lowerpath.MakeLower();
210 int ind1 = 0;
211 while ((ind1 = lowerpath.Find(_T("\\.git"), ind1))>=0)
213 int ind = ind1++;
214 if (ind == (lowerpath.GetLength() - 5))
216 bIsAdminDir = true;
217 break;
219 else if (lowerpath.Find(_T("\\.git\\"), ind)>=0)
221 bIsAdminDir = true;
222 break;
226 return bIsAdminDir;
229 bool GitAdminDir::IsBareRepo(const CString& path)
231 if (path.IsEmpty())
232 return false;
234 if (IsAdminDirPath(path))
235 return false;
237 // don't check for \\COMPUTERNAME\HEAD
238 if (path[0] == _T('\\') && path[1] == _T('\\'))
240 if (path.Find(_T('\\'), 2) < 0)
241 return false;
244 if (!PathFileExists(path + _T("\\HEAD")) || !PathFileExists(path + _T("\\config")))
245 return false;
247 if (!PathFileExists(path + _T("\\objects\\")) || !PathFileExists(path + _T("\\refs\\")))
248 return false;
250 return true;