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.
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
;
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());
48 CString possibletempfile
;
51 ::GetTempFileName(temppath
.get(), L
"tsm", 0, tempF
.get());
52 tempfile
= CTGitPath (tempF
.get());
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
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
));
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
)))
87 // caller has to actually grab the file path
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.
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
))
117 CAutoFile hFile
= CreateFile(tempfile
.GetWinPath(), GENERIC_READ
, FILE_SHARE_READ
, nullptr, CREATE_ALWAYS
, FILE_ATTRIBUTE_TEMPORARY
, nullptr);
120 auto lastErr
= GetLastError();
121 if ((lastErr
!= ERROR_ALREADY_EXISTS
) && (lastErr
!= ERROR_ACCESS_DENIED
))
135 m_TempFileList
.AddPath(tempfile
);
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());
169 CSimpleFileFind finder
= CSimpleFileFind(path
.get(), wildCard
);
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
);