Disable unsupported commands
[TortoiseGit.git] / src / Utils / DirFileEnum.cpp
blobbd78d28c16e6c9ff96bce05da650e10c487d9a36
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2015-2016 - TortoiseGit
4 // Copyright (C) 2005-2006, 2009-2010 - 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.
19 #include "stdafx.h"
20 #include "DirFileEnum.h"
21 #include "SysInfo.h"
23 CSimpleFileFind::CSimpleFileFind(const CString &sPath, LPCTSTR pPattern) :
24 m_dError(ERROR_SUCCESS),
25 m_bFirst(TRUE),
26 m_sPathPrefix(sPath)
28 // Add a trailing \ to m_sPathPrefix if it is missing.
29 // Do not add one to "C:" since "C:" and "C:\" are different.
30 int len = m_sPathPrefix.GetLength();
31 if (len != 0)
33 TCHAR ch = sPath[len-1];
34 if (ch != '\\' && (ch != ':' || len != 2))
36 m_sPathPrefix += "\\";
39 if ((len >= 248) && (m_sPathPrefix.Left(4).Compare(L"\\\\?\\")))
40 m_hFindFile = ::FindFirstFileEx((LPCTSTR)(L"\\\\?\\" + m_sPathPrefix + pPattern), SysInfo::Instance().IsWin7OrLater() ? FindExInfoBasic : FindExInfoStandard, &m_FindFileData, FindExSearchNameMatch, nullptr, SysInfo::Instance().IsWin7OrLater() ? FIND_FIRST_EX_LARGE_FETCH : 0);
41 else
42 m_hFindFile = ::FindFirstFileEx((LPCTSTR)(m_sPathPrefix + pPattern), SysInfo::Instance().IsWin7OrLater() ? FindExInfoBasic : FindExInfoStandard, &m_FindFileData, FindExSearchNameMatch, nullptr, SysInfo::Instance().IsWin7OrLater() ? FIND_FIRST_EX_LARGE_FETCH : 0);
43 if (m_hFindFile == INVALID_HANDLE_VALUE) {
44 m_dError = ::GetLastError();
48 CSimpleFileFind::~CSimpleFileFind()
50 if (m_hFindFile != INVALID_HANDLE_VALUE) {
51 ::FindClose(m_hFindFile);
55 BOOL CSimpleFileFind::FindNextFile()
57 if (m_dError) {
58 return FALSE;
61 if (m_bFirst) {
62 m_bFirst = FALSE;
63 return TRUE;
66 if (!::FindNextFile(m_hFindFile, &m_FindFileData)) {
67 m_dError = ::GetLastError();
68 return FALSE;
71 return TRUE;
74 BOOL CSimpleFileFind::FindNextFileNoDots()
76 BOOL result;
77 do {
78 result = FindNextFile();
79 } while (result && IsDots());
81 return result;
84 BOOL CSimpleFileFind::FindNextFileNoDirectories()
86 BOOL result;
87 do {
88 result = FindNextFile();
89 } while (result && IsDirectory());
91 return result;
96 * Implementation notes:
98 * This is a depth-first traversal. Directories are visited before
99 * their contents.
101 * We keep a stack of directories. The deepest directory is at the top
102 * of the stack, the originally-requested directory is at the bottom.
103 * If we come across a directory, we first return it to the user, then
104 * recurse into it. The finder at the bottom of the stack always points
105 * to the file or directory last returned to the user (except immediately
106 * after creation, when the finder points to the first valid thing we need
107 * to return, but we haven't actually returned anything yet - hence the
108 * m_bIsNew variable).
110 * Errors reading a directory are assumed to be end-of-directory, and
111 * are otherwise ignored.
113 * The "." and ".." psedo-directories are ignored for obvious reasons.
117 CDirFileEnum::CDirStackEntry::CDirStackEntry(CDirStackEntry * seNext,
118 const CString& sDirName)
119 : CSimpleFileFind(sDirName),
120 m_seNext(seNext)
124 CDirFileEnum::CDirStackEntry::~CDirStackEntry()
128 inline void CDirFileEnum::PopStack()
130 CDirStackEntry * seToDelete = m_seStack;
131 m_seStack = seToDelete->m_seNext;
132 delete seToDelete;
135 inline void CDirFileEnum::PushStack(const CString& sDirName)
137 m_seStack = new CDirStackEntry(m_seStack,sDirName);
140 CDirFileEnum::CDirFileEnum(const CString& sDirName) :
141 m_seStack(nullptr),
142 m_bIsNew(TRUE)
144 PushStack(sDirName);
147 CDirFileEnum::~CDirFileEnum()
149 while (m_seStack)
151 PopStack();
155 BOOL CDirFileEnum::NextFile(CString &sResult, bool* pbIsDirectory, bool bRecurse /* = true */)
157 if (m_bIsNew) {
158 // Special-case first time - haven't found anything yet,
159 // so don't do recurse-into-directory check.
160 m_bIsNew = FALSE;
161 } else if (m_seStack && m_seStack->IsDirectory() && bRecurse) {
162 PushStack(m_seStack->GetFilePath());
165 while (m_seStack && !m_seStack->FindNextFileNoDots()) {
166 // No more files in this directory, try parent.
167 PopStack();
170 if (m_seStack)
172 sResult = m_seStack->GetFilePath();
173 if (pbIsDirectory)
174 *pbIsDirectory = m_seStack->IsDirectory();
175 return TRUE;
176 } else {
177 return FALSE;