Fixed issue #3108: Versioned file in ignored folder causes wrong overlays
[TortoiseGit.git] / src / TortoiseMerge / TempFile.cpp
blob02783f99dd5d23d909eac214557a4114897df6ad
1 // TortoiseGitMerge - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2012 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
20 #include "TempFile.h"
21 #include "PathUtils.h"
22 #include "DirFileEnum.h"
23 #include "SmartHandle.h"
25 CTempFiles::CTempFiles(void)
29 CTempFiles::~CTempFiles(void)
31 m_TempFileList.DeleteAllFiles(false, false);
34 CTempFiles& CTempFiles::Instance()
36 static CTempFiles instance;
37 return instance;
40 CTGitPath CTempFiles::ConstructTempPath(const CTGitPath& path)
42 DWORD len = ::GetTempPath(0, nullptr);
43 auto temppath = std::make_unique<TCHAR[]>(len + 1);
44 auto tempF = std::make_unique<TCHAR[]>(len + 50);
45 ::GetTempPath (len+1, temppath.get());
46 CTGitPath tempfile;
47 CString possibletempfile;
48 if (path.IsEmpty())
50 ::GetTempFileName(temppath.get(), L"tsm", 0, tempF.get());
51 tempfile = CTGitPath (tempF.get());
53 else
55 int i=0;
58 // use the UI path, which does unescaping for urls
59 CString filename = path.GetUIFileOrDirectoryName();
60 // remove illegal chars which could be present in urls
61 filename.Remove('?');
62 filename.Remove('*');
63 filename.Remove('<');
64 filename.Remove('>');
65 filename.Remove('|');
66 filename.Remove('"');
67 // the inner loop assures that the resulting path is < MAX_PATH
68 // if that's not possible without reducing the 'filename' to less than 5 chars, use a path
69 // that's longer than MAX_PATH (in that case, we can't really do much to avoid longer paths)
72 possibletempfile.Format(L"%s%s.tsm%3.3x.tmp%s", temppath.get(), (LPCTSTR)filename, i, (LPCTSTR)path.GetFileExtension());
73 tempfile.SetFromWin(possibletempfile);
74 filename = filename.Left(filename.GetLength()-1);
75 } while ( (filename.GetLength() > 4)
76 && (tempfile.GetWinPathString().GetLength() >= MAX_PATH));
77 i++;
78 } while (PathFileExists(tempfile.GetWinPath()));
81 // caller has to actually grab the file path
83 return tempfile;
86 CTGitPath CTempFiles::CreateTempPath (bool bRemoveAtEnd, const CTGitPath& path, bool directory)
88 bool succeeded = false;
89 for (int retryCount = 0; retryCount < MAX_RETRIES; ++retryCount)
91 CTGitPath tempfile = ConstructTempPath (path);
93 // now create the temp file / directory, so that subsequent calls to GetTempFile() return
94 // different filenames.
95 // Handle races, i.e. name collisions.
97 if (directory)
99 DeleteFile(tempfile.GetWinPath());
100 if (CreateDirectory(tempfile.GetWinPath(), nullptr) == FALSE)
102 if (GetLastError() != ERROR_ALREADY_EXISTS)
103 return CTGitPath();
105 else
106 succeeded = true;
108 else
110 CAutoFile hFile = CreateFile(tempfile.GetWinPath(), GENERIC_READ, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, nullptr);
111 if (!hFile)
113 if (GetLastError() != ERROR_ALREADY_EXISTS)
114 return CTGitPath();
116 else
118 succeeded = true;
122 // done?
124 if (succeeded)
126 if (bRemoveAtEnd)
127 m_TempFileList.AddPath(tempfile);
129 return tempfile;
133 // give up
135 return CTGitPath();
138 CTGitPath CTempFiles::GetTempFilePath(bool bRemoveAtEnd, const CTGitPath& path /* = CTGitPath() */)
140 return CreateTempPath (bRemoveAtEnd, path, false);
143 CString CTempFiles::GetTempFilePathString()
145 return CreateTempPath (true, CTGitPath(), false).GetWinPathString();
148 CTGitPath CTempFiles::GetTempDirPath(bool bRemoveAtEnd, const CTGitPath& path /* = CTGitPath() */)
150 return CreateTempPath (bRemoveAtEnd, path, true);
153 void CTempFiles::DeleteOldTempFiles(LPCTSTR wildCard)
155 DWORD len = ::GetTempPath(0, nullptr);
156 auto path = std::make_unique<TCHAR[]>(len + 100);
157 len = ::GetTempPath (len+100, path.get());
158 if (len == 0)
159 return;
161 CSimpleFileFind finder = CSimpleFileFind(path.get(), wildCard);
162 FILETIME systime_;
163 ::GetSystemTimeAsFileTime(&systime_);
164 __int64 systime = (__int64)systime_.dwLowDateTime | (__int64)systime_.dwHighDateTime << 32LL;
165 while (finder.FindNextFileNoDirectories())
167 CString filepath = finder.GetFilePath();
169 FILETIME createtime_ = finder.GetCreateTime();
170 __int64 createtime = (__int64)createtime_.dwLowDateTime | (__int64)createtime_.dwHighDateTime << 32LL;
171 createtime += 864000000000LL; //only delete files older than a day
172 if (createtime < systime)
174 ::SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL);
175 ::DeleteFile(filepath);