5 #include "Common/StringConvert.h"
6 #include "Common/Wildcard.h"
7 #include "Common/MyCom.h"
9 #include "EnumDirItems.h"
11 using namespace NWindows;
12 using namespace NFile;
13 using namespace NName;
16 const UString &prefix, // prefix for logical path
17 const UString &fullPathName, // path on disk: can be relative to some basePrefix
18 const NFind::CFileInfoW &fileInfo,
19 CObjectVector<CDirItem> &dirItems)
22 item.Attributes = fileInfo.Attributes;
23 item.Size = fileInfo.Size;
24 item.CreationTime = fileInfo.CreationTime;
25 item.LastAccessTime = fileInfo.LastAccessTime;
26 item.LastWriteTime = fileInfo.LastWriteTime;
27 item.Name = prefix + fileInfo.Name;
28 item.FullPath = fullPathName;
32 static void EnumerateDirectory(
33 const UString &baseFolderPrefix, // base (disk) prefix for scanning
34 const UString &directory, // additional disk prefix starting from baseFolderPrefix
35 const UString &prefix, // logical prefix
36 CObjectVector<CDirItem> &dirItems,
37 UStringVector &errorPaths,
38 CRecordVector<DWORD> &errorCodes)
40 NFind::CEnumeratorW enumerator(baseFolderPrefix + directory + wchar_t(kAnyStringWildcard));
43 NFind::CFileInfoW fileInfo;
45 if (!enumerator.Next(fileInfo, found))
47 errorCodes.Add(::GetLastError());
48 errorPaths.Add(baseFolderPrefix + directory);
53 AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo, dirItems);
54 if (fileInfo.IsDirectory())
56 EnumerateDirectory(baseFolderPrefix, directory + fileInfo.Name + wchar_t(kDirDelimiter),
57 prefix + fileInfo.Name + wchar_t(kDirDelimiter), dirItems, errorPaths, errorCodes);
62 void EnumerateDirItems(
63 const UString &baseFolderPrefix, // base (disk) prefix for scanning
64 const UStringVector &fileNames, // names relative to baseFolderPrefix
65 const UString &archiveNamePrefix,
66 CObjectVector<CDirItem> &dirItems,
67 UStringVector &errorPaths,
68 CRecordVector<DWORD> &errorCodes)
70 for(int i = 0; i < fileNames.Size(); i++)
72 const UString &fileName = fileNames[i];
73 NFind::CFileInfoW fileInfo;
74 if (!NFind::FindFile(baseFolderPrefix + fileName, fileInfo))
76 errorCodes.Add(::GetLastError());
77 errorPaths.Add(baseFolderPrefix + fileName);
80 AddDirFileInfo(archiveNamePrefix, fileName, fileInfo, dirItems);
81 if (fileInfo.IsDirectory())
83 EnumerateDirectory(baseFolderPrefix, fileName + wchar_t(kDirDelimiter),
84 archiveNamePrefix + fileInfo.Name + wchar_t(kDirDelimiter),
85 dirItems, errorPaths, errorCodes);
90 static HRESULT EnumerateDirItems(
91 const NWildcard::CCensorNode &curNode,
92 const UString &diskPrefix, // full disk path prefix
93 const UString &archivePrefix, // prefix from root
94 const UStringVector &addArchivePrefix, // prefix from curNode
95 CObjectVector<CDirItem> &dirItems,
96 bool enterToSubFolders,
97 IEnumDirItemCallback *callback,
98 UStringVector &errorPaths,
99 CRecordVector<DWORD> &errorCodes)
101 if (!enterToSubFolders)
102 if (curNode.NeedCheckSubDirs())
103 enterToSubFolders = true;
105 RINOK(callback->CheckBreak());
107 // try direct_names case at first
108 if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
110 // check that all names are direct
112 for (i = 0; i < curNode.IncludeItems.Size(); i++)
114 const NWildcard::CItem &item = curNode.IncludeItems[i];
115 if (item.Recursive || item.PathParts.Size() != 1)
117 const UString &name = item.PathParts.Front();
118 if (name.IsEmpty() || DoesNameContainWildCard(name))
121 if (i == curNode.IncludeItems.Size())
123 // all names are direct (no wildcards)
124 // so we don't need file_system's dir enumerator
125 CRecordVector<bool> needEnterVector;
126 for (i = 0; i < curNode.IncludeItems.Size(); i++)
128 const NWildcard::CItem &item = curNode.IncludeItems[i];
129 const UString &name = item.PathParts.Front();
130 const UString fullPath = diskPrefix + name;
131 NFind::CFileInfoW fileInfo;
132 if (!NFind::FindFile(fullPath, fileInfo))
134 errorCodes.Add(::GetLastError());
135 errorPaths.Add(fullPath);
138 bool isDir = fileInfo.IsDirectory();
139 if (isDir && !item.ForDir || !isDir && !item.ForFile)
141 errorCodes.Add((DWORD)E_FAIL);
142 errorPaths.Add(fullPath);
145 const UString realName = fileInfo.Name;
146 const UString realDiskPath = diskPrefix + realName;
148 UStringVector pathParts;
149 pathParts.Add(fileInfo.Name);
150 if (curNode.CheckPathToRoot(false, pathParts, !isDir))
153 AddDirFileInfo(archivePrefix, realDiskPath, fileInfo, dirItems);
157 UStringVector addArchivePrefixNew;
158 const NWildcard::CCensorNode *nextNode = 0;
159 int index = curNode.FindSubNode(name);
162 for (int t = needEnterVector.Size(); t <= index; t++)
163 needEnterVector.Add(true);
164 needEnterVector[index] = false;
165 nextNode = &curNode.SubNodes[index];
170 addArchivePrefixNew.Add(name); // don't change it to realName. It's for shortnames support
172 RINOK(EnumerateDirItems(*nextNode,
173 realDiskPath + wchar_t(kDirDelimiter),
174 archivePrefix + realName + wchar_t(kDirDelimiter),
175 addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes));
177 for (i = 0; i < curNode.SubNodes.Size(); i++)
179 if (i < needEnterVector.Size())
180 if (!needEnterVector[i])
182 const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
183 const UString fullPath = diskPrefix + nextNode.Name;
184 NFind::CFileInfoW fileInfo;
185 if (!NFind::FindFile(fullPath, fileInfo))
187 if (!nextNode.AreThereIncludeItems())
189 errorCodes.Add(::GetLastError());
190 errorPaths.Add(fullPath);
193 if (!fileInfo.IsDirectory())
195 errorCodes.Add((DWORD)E_FAIL);
196 errorPaths.Add(fullPath);
199 RINOK(EnumerateDirItems(nextNode,
200 diskPrefix + fileInfo.Name + wchar_t(kDirDelimiter),
201 archivePrefix + fileInfo.Name + wchar_t(kDirDelimiter),
202 UStringVector(), dirItems, false, callback, errorPaths, errorCodes));
209 NFind::CEnumeratorW enumerator(diskPrefix + wchar_t(kAnyStringWildcard));
212 NFind::CFileInfoW fileInfo;
214 if (!enumerator.Next(fileInfo, found))
216 errorCodes.Add(::GetLastError());
217 errorPaths.Add(diskPrefix);
224 RINOK(callback->CheckBreak());
225 const UString &name = fileInfo.Name;
226 bool enterToSubFolders2 = enterToSubFolders;
227 UStringVector addArchivePrefixNew = addArchivePrefix;
228 addArchivePrefixNew.Add(name);
230 UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
231 if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fileInfo.IsDirectory()))
234 if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fileInfo.IsDirectory()))
236 AddDirFileInfo(archivePrefix, diskPrefix + name, fileInfo, dirItems);
237 if (fileInfo.IsDirectory())
238 enterToSubFolders2 = true;
240 if (!fileInfo.IsDirectory())
243 const NWildcard::CCensorNode *nextNode = 0;
244 if (addArchivePrefix.IsEmpty())
246 int index = curNode.FindSubNode(name);
248 nextNode = &curNode.SubNodes[index];
250 if (!enterToSubFolders2 && nextNode == 0)
253 addArchivePrefixNew = addArchivePrefix;
257 addArchivePrefixNew.Add(name);
259 RINOK(EnumerateDirItems(*nextNode,
260 diskPrefix + name + wchar_t(kDirDelimiter),
261 archivePrefix + name + wchar_t(kDirDelimiter),
262 addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes));
267 HRESULT EnumerateItems(
268 const NWildcard::CCensor &censor,
269 CObjectVector<CDirItem> &dirItems,
270 IEnumDirItemCallback *callback,
271 UStringVector &errorPaths,
272 CRecordVector<DWORD> &errorCodes)
274 for (int i = 0; i < censor.Pairs.Size(); i++)
276 const NWildcard::CPair &pair = censor.Pairs[i];
277 RINOK(EnumerateDirItems(pair.Head, pair.Prefix, L"", UStringVector(), dirItems, false,
278 callback, errorPaths, errorCodes));