Fix typos
[TortoiseGit.git] / src / TortoiseMerge / TempFile.cpp
blob2549e6eba33d430d59ba68b9368a7caf30a1b48f
1 // TortoiseGitMerge - a Windows shell extension for easy version control
3 // Copyright (C) 2019 - TortoiseGit
4 // Copyright (C) 2003-2012, 2020 - 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 "TempFile.h"
22 #include "PathUtils.h"
23 #include "DirFileEnum.h"
24 #include "SmartHandle.h"
26 CTempFiles::CTempFiles()
30 CTempFiles::~CTempFiles()
32 m_TempFileList.DeleteAllFiles(false, false);
35 CTempFiles& CTempFiles::Instance()
37 static CTempFiles instance;
38 return instance;
41 CTGitPath CTempFiles::ConstructTempPath(const CTGitPath& path)
43 DWORD len = ::GetTempPath(0, nullptr);
44 auto temppath = std::make_unique<wchar_t[]>(len + 1);
45 auto tempF = std::make_unique<wchar_t[]>(len + 50);
46 ::GetTempPath (len+1, temppath.get());
47 CTGitPath tempfile;
48 CString possibletempfile;
49 if (path.IsEmpty())
51 ::GetTempFileName(temppath.get(), L"tsm", 0, tempF.get());
52 tempfile = CTGitPath (tempF.get());
54 else
56 int i=0;
59 // use the UI path, which does unescaping for urls
60 CString filename = path.GetUIFileOrDirectoryName();
61 // remove illegal chars which could be present in urls
62 filename.Remove('?');
63 filename.Remove('*');
64 filename.Remove('<');
65 filename.Remove('>');
66 filename.Remove('|');
67 filename.Remove('"');
68 // the inner loop assures that the resulting path is < MAX_PATH
69 // if that's not possible without reducing the 'filename' to less than 5 chars, use a path
70 // that's longer than MAX_PATH (in that case, we can't really do much to avoid longer paths)
73 possibletempfile.Format(L"%s%s.tsm%3.3x.tmp%s", temppath.get(), static_cast<LPCWSTR>(filename), i, static_cast<LPCWSTR>(path.GetFileExtension()));
74 tempfile.SetFromWin(possibletempfile);
75 filename.Truncate(std::max(0, filename.GetLength() - 1));
76 } while ( (filename.GetLength() > 4)
77 && (tempfile.GetWinPathString().GetLength() >= MAX_PATH));
78 i++;
79 // now create the temp file in a thread safe way, so that subsequent calls to GetTempFile() return different filenames.
80 CAutoFile hFile = CreateFile(tempfile.GetWinPath(), GENERIC_READ, FILE_SHARE_READ, nullptr, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, nullptr);
81 auto lastErr = GetLastError();
82 if (hFile || ((lastErr != ERROR_FILE_EXISTS) && (lastErr != ERROR_ACCESS_DENIED)))
83 break;
84 } while (true);
87 // caller has to actually grab the file path
89 return tempfile;
92 CTGitPath CTempFiles::CreateTempPath (bool bRemoveAtEnd, const CTGitPath& path, bool directory)
94 bool succeeded = false;
95 for (int retryCount = 0; retryCount < MAX_RETRIES; ++retryCount)
97 CTGitPath tempfile = ConstructTempPath (path);
99 // now create the temp file / directory, so that subsequent calls to GetTempFile() return
100 // different filenames.
101 // Handle races, i.e. name collisions.
103 if (directory)
105 DeleteFile(tempfile.GetWinPath());
106 if (CreateDirectory(tempfile.GetWinPath(), nullptr) == FALSE)
108 auto lastErr = GetLastError();
109 if ((lastErr != ERROR_ALREADY_EXISTS) && (lastErr != ERROR_ACCESS_DENIED))
110 return CTGitPath();
112 else
113 succeeded = true;
115 else
117 CAutoFile hFile = CreateFile(tempfile.GetWinPath(), GENERIC_READ, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, nullptr);
118 if (!hFile)
120 auto lastErr = GetLastError();
121 if ((lastErr != ERROR_ALREADY_EXISTS) && (lastErr != ERROR_ACCESS_DENIED))
122 return CTGitPath();
124 else
126 succeeded = true;
130 // done?
132 if (succeeded)
134 if (bRemoveAtEnd)
135 m_TempFileList.AddPath(tempfile);
137 return tempfile;
141 // give up
143 return CTGitPath();
146 CTGitPath CTempFiles::GetTempFilePath(bool bRemoveAtEnd, const CTGitPath& path /* = CTGitPath() */)
148 return CreateTempPath (bRemoveAtEnd, path, false);
151 CString CTempFiles::GetTempFilePathString()
153 return CreateTempPath (true, CTGitPath(), false).GetWinPathString();
156 CTGitPath CTempFiles::GetTempDirPath(bool bRemoveAtEnd, const CTGitPath& path /* = CTGitPath() */)
158 return CreateTempPath (bRemoveAtEnd, path, true);
161 void CTempFiles::DeleteOldTempFiles(LPCWSTR wildCard)
163 DWORD len = ::GetTempPath(0, nullptr);
164 auto path = std::make_unique<wchar_t[]>(len + 100);
165 len = ::GetTempPath (len+100, path.get());
166 if (len == 0)
167 return;
169 CSimpleFileFind finder = CSimpleFileFind(path.get(), wildCard);
170 FILETIME systime_;
171 ::GetSystemTimeAsFileTime(&systime_);
172 __int64 systime = static_cast<__int64>(systime_.dwHighDateTime) << 32 | systime_.dwLowDateTime;
173 while (finder.FindNextFileNoDirectories())
175 CString filepath = finder.GetFilePath();
177 FILETIME createtime_ = finder.GetCreateTime();
178 __int64 createtime = static_cast<__int64>(createtime_.dwHighDateTime) << 32 | createtime_.dwLowDateTime;
179 createtime += 864000000000LL; //only delete files older than a day
180 if (createtime < systime)
182 ::SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL);
183 ::DeleteFile(filepath);